all repos — mgba @ dab12cf5c674542cae0db7708c333035255fbc65

mGBA Game Boy Advance Emulator

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

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