Home | History | Annotate | Download | only in Lzma
      1 /* LzmaUtil.c -- Test application for LZMA compression
      2 2018-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 
     18 static const char * const kCantReadMessage = "Can not read input file";
     19 static const char * const kCantWriteMessage = "Can not write output file";
     20 static const char * const kCantAllocateMessage = "Can not allocate memory";
     21 static const char * const kDataErrorMessage = "Data error";
     22 
     23 static 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 
     32 static 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 
     40 static int PrintErrorNumber(char *buffer, SRes val)
     41 {
     42   sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val);
     43   return 1;
     44 }
     45 
     46 static 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 
     56 static 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 
    110 static 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 
    136 static 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 
    173 static 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 
    252 int 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 }
    259