Home | History | Annotate | Download | only in LzmaCompress
      1 /** @file
      2   LZMA Compress/Decompress tool (LzmaCompress)
      3 
      4   Based on LZMA SDK 16.04:
      5     LzmaUtil.c -- Test application for LZMA compression
      6     2016-10-04 : Igor Pavlov : Public domain
      7 
      8   Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
      9   This program and the accompanying materials
     10   are licensed and made available under the terms and conditions of the BSD License
     11   which accompanies this distribution.  The full text of the license may be found at
     12   http://opensource.org/licenses/bsd-license.php
     13 
     14   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     15   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     16 
     17 **/
     18 
     19 #define _CRT_SECURE_NO_WARNINGS
     20 
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 
     25 #include "Sdk/C/Alloc.h"
     26 #include "Sdk/C/7zFile.h"
     27 #include "Sdk/C/7zVersion.h"
     28 #include "Sdk/C/LzmaDec.h"
     29 #include "Sdk/C/LzmaEnc.h"
     30 #include "Sdk/C/Bra.h"
     31 #include "CommonLib.h"
     32 
     33 #define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8)
     34 
     35 typedef enum {
     36   NoConverter,
     37   X86Converter,
     38   MaxConverter
     39 } CONVERTER_TYPE;
     40 
     41 const char *kCantReadMessage = "Can not read input file";
     42 const char *kCantWriteMessage = "Can not write output file";
     43 const char *kCantAllocateMessage = "Can not allocate memory";
     44 const char *kDataErrorMessage = "Data error";
     45 
     46 static Bool mQuietMode = False;
     47 static CONVERTER_TYPE mConType = NoConverter;
     48 
     49 #define UTILITY_NAME "LzmaCompress"
     50 #define UTILITY_MAJOR_VERSION 0
     51 #define UTILITY_MINOR_VERSION 2
     52 #define INTEL_COPYRIGHT \
     53   "Copyright (c) 2009-2016, Intel Corporation. All rights reserved."
     54 void PrintHelp(char *buffer)
     55 {
     56   strcat(buffer,
     57       "\n" UTILITY_NAME " - " INTEL_COPYRIGHT "\n"
     58       "Based on LZMA Utility " MY_VERSION_COPYRIGHT_DATE "\n"
     59       "\nUsage:  LzmaCompress -e|-d [options] <inputFile>\n"
     60              "  -e: encode file\n"
     61              "  -d: decode file\n"
     62              "  -o FileName, --output FileName: specify the output filename\n"
     63              "  --f86: enable converter for x86 code\n"
     64              "  -v, --verbose: increase output messages\n"
     65              "  -q, --quiet: reduce output messages\n"
     66              "  --debug [0-9]: set debug level\n"
     67              "  --version: display the program version and exit\n"
     68              "  -h, --help: display this help text\n"
     69              );
     70 }
     71 
     72 int PrintError(char *buffer, const char *message)
     73 {
     74   strcat(buffer, "\nError: ");
     75   strcat(buffer, message);
     76   strcat(buffer, "\n");
     77   return 1;
     78 }
     79 
     80 int PrintErrorNumber(char *buffer, SRes val)
     81 {
     82   sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val);
     83   return 1;
     84 }
     85 
     86 int PrintUserError(char *buffer)
     87 {
     88   return PrintError(buffer, "Incorrect command");
     89 }
     90 
     91 void PrintVersion(char *buffer)
     92 {
     93   sprintf (buffer, "%s Version %d.%d %s ", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
     94 }
     95 
     96 static SRes Encode(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 fileSize)
     97 {
     98   SRes res;
     99   size_t inSize = (size_t)fileSize;
    100   Byte *inBuffer = 0;
    101   Byte *outBuffer = 0;
    102   Byte *filteredStream = 0;
    103   size_t outSize;
    104   CLzmaEncProps props;
    105 
    106   LzmaEncProps_Init(&props);
    107   LzmaEncProps_Normalize(&props);
    108 
    109   if (inSize != 0) {
    110     inBuffer = (Byte *)MyAlloc(inSize);
    111     if (inBuffer == 0)
    112       return SZ_ERROR_MEM;
    113   } else {
    114     return SZ_ERROR_INPUT_EOF;
    115   }
    116 
    117   if (SeqInStream_Read(inStream, inBuffer, inSize) != SZ_OK) {
    118     res = SZ_ERROR_READ;
    119     goto Done;
    120   }
    121 
    122   // we allocate 105% of original size + 64KB for output buffer
    123   outSize = (size_t)fileSize / 20 * 21 + (1 << 16);
    124   outBuffer = (Byte *)MyAlloc(outSize);
    125   if (outBuffer == 0) {
    126     res = SZ_ERROR_MEM;
    127     goto Done;
    128   }
    129 
    130   {
    131     int i;
    132     for (i = 0; i < 8; i++)
    133       outBuffer[i + LZMA_PROPS_SIZE] = (Byte)(fileSize >> (8 * i));
    134   }
    135 
    136   if (mConType != NoConverter)
    137   {
    138     filteredStream = (Byte *)MyAlloc(inSize);
    139     if (filteredStream == 0) {
    140       res = SZ_ERROR_MEM;
    141       goto Done;
    142     }
    143     memcpy(filteredStream, inBuffer, inSize);
    144 
    145     if (mConType == X86Converter) {
    146       {
    147         UInt32 x86State;
    148         x86_Convert_Init(x86State);
    149         x86_Convert(filteredStream, (SizeT) inSize, 0, &x86State, 1);
    150       }
    151     }
    152   }
    153 
    154   {
    155     size_t outSizeProcessed = outSize - LZMA_HEADER_SIZE;
    156     size_t outPropsSize = LZMA_PROPS_SIZE;
    157 
    158     res = LzmaEncode(outBuffer + LZMA_HEADER_SIZE, &outSizeProcessed,
    159         mConType != NoConverter ? filteredStream : inBuffer, inSize,
    160         &props, outBuffer, &outPropsSize, 0,
    161         NULL, &g_Alloc, &g_Alloc);
    162 
    163     if (res != SZ_OK)
    164       goto Done;
    165 
    166     outSize = LZMA_HEADER_SIZE + outSizeProcessed;
    167   }
    168 
    169   if (outStream->Write(outStream, outBuffer, outSize) != outSize)
    170     res = SZ_ERROR_WRITE;
    171 
    172 Done:
    173   MyFree(outBuffer);
    174   MyFree(inBuffer);
    175   MyFree(filteredStream);
    176 
    177   return res;
    178 }
    179 
    180 static SRes Decode(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 fileSize)
    181 {
    182   SRes res;
    183   size_t inSize = (size_t)fileSize;
    184   Byte *inBuffer = 0;
    185   Byte *outBuffer = 0;
    186   size_t outSize = 0;
    187   size_t inSizePure;
    188   ELzmaStatus status;
    189   UInt64 outSize64 = 0;
    190 
    191   int i;
    192 
    193   if (inSize < LZMA_HEADER_SIZE)
    194     return SZ_ERROR_INPUT_EOF;
    195 
    196   inBuffer = (Byte *)MyAlloc(inSize);
    197   if (inBuffer == 0)
    198     return SZ_ERROR_MEM;
    199 
    200   if (SeqInStream_Read(inStream, inBuffer, inSize) != SZ_OK) {
    201     res = SZ_ERROR_READ;
    202     goto Done;
    203   }
    204 
    205   for (i = 0; i < 8; i++)
    206     outSize64 += ((UInt64)inBuffer[LZMA_PROPS_SIZE + i]) << (i * 8);
    207 
    208   outSize = (size_t)outSize64;
    209   if (outSize != 0) {
    210     outBuffer = (Byte *)MyAlloc(outSize);
    211     if (outBuffer == 0) {
    212       res = SZ_ERROR_MEM;
    213       goto Done;
    214     }
    215   } else {
    216     res = SZ_OK;
    217     goto Done;
    218   }
    219 
    220   inSizePure = inSize - LZMA_HEADER_SIZE;
    221   res = LzmaDecode(outBuffer, &outSize, inBuffer + LZMA_HEADER_SIZE, &inSizePure,
    222       inBuffer, LZMA_PROPS_SIZE, LZMA_FINISH_END, &status, &g_Alloc);
    223 
    224   if (res != SZ_OK)
    225     goto Done;
    226 
    227   if (mConType == X86Converter)
    228   {
    229     UInt32 x86State;
    230     x86_Convert_Init(x86State);
    231     x86_Convert(outBuffer, (SizeT) outSize, 0, &x86State, 0);
    232   }
    233 
    234   if (outStream->Write(outStream, outBuffer, outSize) != outSize)
    235     res = SZ_ERROR_WRITE;
    236 
    237 Done:
    238   MyFree(outBuffer);
    239   MyFree(inBuffer);
    240 
    241   return res;
    242 }
    243 
    244 int main2(int numArgs, const char *args[], char *rs)
    245 {
    246   CFileSeqInStream inStream;
    247   CFileOutStream outStream;
    248   int res;
    249   int encodeMode = 0;
    250   Bool modeWasSet = False;
    251   const char *inputFile = NULL;
    252   const char *outputFile = "file.tmp";
    253   int param;
    254   UInt64 fileSize;
    255 
    256   FileSeqInStream_CreateVTable(&inStream);
    257   File_Construct(&inStream.file);
    258 
    259   FileOutStream_CreateVTable(&outStream);
    260   File_Construct(&outStream.file);
    261 
    262   if (numArgs == 1)
    263   {
    264     PrintHelp(rs);
    265     return 0;
    266   }
    267 
    268   for (param = 1; param < numArgs; param++) {
    269     if (strcmp(args[param], "-e") == 0 || strcmp(args[param], "-d") == 0) {
    270       encodeMode = (args[param][1] == 'e');
    271       modeWasSet = True;
    272     } else if (strcmp(args[param], "--f86") == 0) {
    273       mConType = X86Converter;
    274     } else if (strcmp(args[param], "-o") == 0 ||
    275                strcmp(args[param], "--output") == 0) {
    276       if (numArgs < (param + 2)) {
    277         return PrintUserError(rs);
    278       }
    279       outputFile = args[++param];
    280     } else if (strcmp(args[param], "--debug") == 0) {
    281       if (numArgs < (param + 2)) {
    282         return PrintUserError(rs);
    283       }
    284       //
    285       // For now we silently ignore this parameter to achieve command line
    286       // parameter compatibility with other build tools.
    287       //
    288       param++;
    289     } else if (
    290                 strcmp(args[param], "-h") == 0 ||
    291                 strcmp(args[param], "--help") == 0
    292               ) {
    293       PrintHelp(rs);
    294       return 0;
    295     } else if (
    296                 strcmp(args[param], "-v") == 0 ||
    297                 strcmp(args[param], "--verbose") == 0
    298               ) {
    299       //
    300       // For now we silently ignore this parameter to achieve command line
    301       // parameter compatibility with other build tools.
    302       //
    303     } else if (
    304                 strcmp(args[param], "-q") == 0 ||
    305                 strcmp(args[param], "--quiet") == 0
    306               ) {
    307       mQuietMode = True;
    308     } else if (strcmp(args[param], "--version") == 0) {
    309       PrintVersion(rs);
    310       return 0;
    311     } else if (inputFile == NULL) {
    312       inputFile = args[param];
    313     } else {
    314       return PrintUserError(rs);
    315     }
    316   }
    317 
    318   if ((inputFile == NULL) || !modeWasSet) {
    319     return PrintUserError(rs);
    320   }
    321 
    322   {
    323     size_t t4 = sizeof(UInt32);
    324     size_t t8 = sizeof(UInt64);
    325     if (t4 != 4 || t8 != 8)
    326       return PrintError(rs, "Incorrect UInt32 or UInt64");
    327   }
    328 
    329   if (InFile_Open(&inStream.file, inputFile) != 0)
    330     return PrintError(rs, "Can not open input file");
    331 
    332   if (OutFile_Open(&outStream.file, outputFile) != 0) {
    333     File_Close(&inStream.file);
    334     return PrintError(rs, "Can not open output file");
    335   }
    336 
    337   File_GetLength(&inStream.file, &fileSize);
    338 
    339   if (encodeMode)
    340   {
    341     if (!mQuietMode) {
    342       printf("Encoding\n");
    343     }
    344     res = Encode(&outStream.s, &inStream.s, fileSize);
    345   }
    346   else
    347   {
    348     if (!mQuietMode) {
    349       printf("Decoding\n");
    350     }
    351     res = Decode(&outStream.s, &inStream.s, fileSize);
    352   }
    353 
    354   File_Close(&outStream.file);
    355   File_Close(&inStream.file);
    356 
    357   if (res != SZ_OK)
    358   {
    359     if (res == SZ_ERROR_MEM)
    360       return PrintError(rs, kCantAllocateMessage);
    361     else if (res == SZ_ERROR_DATA)
    362       return PrintError(rs, kDataErrorMessage);
    363     else if (res == SZ_ERROR_WRITE)
    364       return PrintError(rs, kCantWriteMessage);
    365     else if (res == SZ_ERROR_READ)
    366       return PrintError(rs, kCantReadMessage);
    367     return PrintErrorNumber(rs, res);
    368   }
    369   return 0;
    370 }
    371 
    372 int MY_CDECL main(int numArgs, const char *args[])
    373 {
    374   char rs[2000] = { 0 };
    375   int res = main2(numArgs, args, rs);
    376   if (strlen(rs) > 0) {
    377     puts(rs);
    378   }
    379   return res;
    380 }
    381