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