all repos — mgba @ b2d406a411b31acce5bbf0246af32a80c22ca834

mGBA Game Boy Advance Emulator

src/third-party/lzma/Util/Lzma/LzmaUtil.c (view raw)

  1/* LzmaUtil.c -- Test application for LZMA compression
  22018-07-04 : Igor Pavlov : Public domain */
  3
  4#include "../../Precomp.h"
  5
  6#include <stdio.h>
  7#include <stdlib.h>
  8#include <string.h>
  9
 10#include "../../CpuArch.h"
 11
 12#include "../../Alloc.h"
 13#include "../../7zFile.h"
 14#include "../../7zVersion.h"
 15#include "../../LzmaDec.h"
 16#include "../../LzmaEnc.h"
 17
 18static const char * const kCantReadMessage = "Can not read input file";
 19static const char * const kCantWriteMessage = "Can not write output file";
 20static const char * const kCantAllocateMessage = "Can not allocate memory";
 21static const char * const kDataErrorMessage = "Data error";
 22
 23static void PrintHelp(char *buffer)
 24{
 25  strcat(buffer,
 26    "\nLZMA-C " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n"
 27    "Usage:  lzma <e|d> inputFile outputFile\n"
 28    "  e: encode file\n"
 29    "  d: decode file\n");
 30}
 31
 32static int PrintError(char *buffer, const char *message)
 33{
 34  strcat(buffer, "\nError: ");
 35  strcat(buffer, message);
 36  strcat(buffer, "\n");
 37  return 1;
 38}
 39
 40static int PrintErrorNumber(char *buffer, SRes val)
 41{
 42  sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val);
 43  return 1;
 44}
 45
 46static int PrintUserError(char *buffer)
 47{
 48  return PrintError(buffer, "Incorrect command");
 49}
 50
 51
 52#define IN_BUF_SIZE (1 << 16)
 53#define OUT_BUF_SIZE (1 << 16)
 54
 55
 56static SRes Decode2(CLzmaDec *state, ISeqOutStream *outStream, ISeqInStream *inStream,
 57    UInt64 unpackSize)
 58{
 59  int thereIsSize = (unpackSize != (UInt64)(Int64)-1);
 60  Byte inBuf[IN_BUF_SIZE];
 61  Byte outBuf[OUT_BUF_SIZE];
 62  size_t inPos = 0, inSize = 0, outPos = 0;
 63  LzmaDec_Init(state);
 64  for (;;)
 65  {
 66    if (inPos == inSize)
 67    {
 68      inSize = IN_BUF_SIZE;
 69      RINOK(inStream->Read(inStream, inBuf, &inSize));
 70      inPos = 0;
 71    }
 72    {
 73      SRes res;
 74      SizeT inProcessed = inSize - inPos;
 75      SizeT outProcessed = OUT_BUF_SIZE - outPos;
 76      ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
 77      ELzmaStatus status;
 78      if (thereIsSize && outProcessed > unpackSize)
 79      {
 80        outProcessed = (SizeT)unpackSize;
 81        finishMode = LZMA_FINISH_END;
 82      }
 83      
 84      res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed,
 85        inBuf + inPos, &inProcessed, finishMode, &status);
 86      inPos += inProcessed;
 87      outPos += outProcessed;
 88      unpackSize -= outProcessed;
 89      
 90      if (outStream)
 91        if (outStream->Write(outStream, outBuf, outPos) != outPos)
 92          return SZ_ERROR_WRITE;
 93        
 94      outPos = 0;
 95      
 96      if (res != SZ_OK || (thereIsSize && unpackSize == 0))
 97        return res;
 98      
 99      if (inProcessed == 0 && outProcessed == 0)
100      {
101        if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK)
102          return SZ_ERROR_DATA;
103        return res;
104      }
105    }
106  }
107}
108
109
110static SRes Decode(ISeqOutStream *outStream, ISeqInStream *inStream)
111{
112  UInt64 unpackSize;
113  int i;
114  SRes res = 0;
115
116  CLzmaDec state;
117
118  /* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */
119  unsigned char header[LZMA_PROPS_SIZE + 8];
120
121  /* Read and parse header */
122
123  RINOK(SeqInStream_Read(inStream, header, sizeof(header)));
124
125  unpackSize = 0;
126  for (i = 0; i < 8; i++)
127    unpackSize += (UInt64)header[LZMA_PROPS_SIZE + i] << (i * 8);
128
129  LzmaDec_Construct(&state);
130  RINOK(LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc));
131  res = Decode2(&state, outStream, inStream, unpackSize);
132  LzmaDec_Free(&state, &g_Alloc);
133  return res;
134}
135
136static SRes Encode(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 fileSize, char *rs)
137{
138  CLzmaEncHandle enc;
139  SRes res;
140  CLzmaEncProps props;
141
142  UNUSED_VAR(rs);
143
144  enc = LzmaEnc_Create(&g_Alloc);
145  if (enc == 0)
146    return SZ_ERROR_MEM;
147
148  LzmaEncProps_Init(&props);
149  res = LzmaEnc_SetProps(enc, &props);
150
151  if (res == SZ_OK)
152  {
153    Byte header[LZMA_PROPS_SIZE + 8];
154    size_t headerSize = LZMA_PROPS_SIZE;
155    int i;
156
157    res = LzmaEnc_WriteProperties(enc, header, &headerSize);
158    for (i = 0; i < 8; i++)
159      header[headerSize++] = (Byte)(fileSize >> (8 * i));
160    if (outStream->Write(outStream, header, headerSize) != headerSize)
161      res = SZ_ERROR_WRITE;
162    else
163    {
164      if (res == SZ_OK)
165        res = LzmaEnc_Encode(enc, outStream, inStream, NULL, &g_Alloc, &g_Alloc);
166    }
167  }
168  LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
169  return res;
170}
171
172
173static int main2(int numArgs, const char *args[], char *rs)
174{
175  CFileSeqInStream inStream;
176  CFileOutStream outStream;
177  char c;
178  int res;
179  int encodeMode;
180  BoolInt useOutFile = False;
181
182  FileSeqInStream_CreateVTable(&inStream);
183  File_Construct(&inStream.file);
184
185  FileOutStream_CreateVTable(&outStream);
186  File_Construct(&outStream.file);
187
188  if (numArgs == 1)
189  {
190    PrintHelp(rs);
191    return 0;
192  }
193
194  if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1)
195    return PrintUserError(rs);
196
197  c = args[1][0];
198  encodeMode = (c == 'e' || c == 'E');
199  if (!encodeMode && c != 'd' && c != 'D')
200    return PrintUserError(rs);
201
202  {
203    size_t t4 = sizeof(UInt32);
204    size_t t8 = sizeof(UInt64);
205    if (t4 != 4 || t8 != 8)
206      return PrintError(rs, "Incorrect UInt32 or UInt64");
207  }
208
209  if (InFile_Open(&inStream.file, args[2]) != 0)
210    return PrintError(rs, "Can not open input file");
211
212  if (numArgs > 3)
213  {
214    useOutFile = True;
215    if (OutFile_Open(&outStream.file, args[3]) != 0)
216      return PrintError(rs, "Can not open output file");
217  }
218  else if (encodeMode)
219    PrintUserError(rs);
220
221  if (encodeMode)
222  {
223    UInt64 fileSize;
224    File_GetLength(&inStream.file, &fileSize);
225    res = Encode(&outStream.vt, &inStream.vt, fileSize, rs);
226  }
227  else
228  {
229    res = Decode(&outStream.vt, useOutFile ? &inStream.vt : NULL);
230  }
231
232  if (useOutFile)
233    File_Close(&outStream.file);
234  File_Close(&inStream.file);
235
236  if (res != SZ_OK)
237  {
238    if (res == SZ_ERROR_MEM)
239      return PrintError(rs, kCantAllocateMessage);
240    else if (res == SZ_ERROR_DATA)
241      return PrintError(rs, kDataErrorMessage);
242    else if (res == SZ_ERROR_WRITE)
243      return PrintError(rs, kCantWriteMessage);
244    else if (res == SZ_ERROR_READ)
245      return PrintError(rs, kCantReadMessage);
246    return PrintErrorNumber(rs, res);
247  }
248  return 0;
249}
250
251
252int MY_CDECL main(int numArgs, const char *args[])
253{
254  char rs[800] = { 0 };
255  int res = main2(numArgs, args, rs);
256  fputs(rs, stdout);
257  return res;
258}