Home | History | Annotate | Download | only in Lzma
      1 /* LzmaUtil.c -- Test application for LZMA compression
      2 2015-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 
     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 void 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 
     29 int PrintError(char *buffer, const char *message)
     30 {
     31   strcat(buffer, "\nError: ");
     32   strcat(buffer, message);
     33   strcat(buffer, "\n");
     34   return 1;
     35 }
     36 
     37 int PrintErrorNumber(char *buffer, SRes val)
     38 {
     39   sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val);
     40   return 1;
     41 }
     42 
     43 int 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 
     51 static 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 
    104 static 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 
    130 static 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 
    166 int 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 
    244 int 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 }
    251