misc/libphysfs/lzma/CPP/7zip/Compress/LZMA_Alone/LzmaAlone.cpp
changeset 13881 99b265e0d1d0
parent 13880 5f819b90d479
child 13882 b172a5d40eee
equal deleted inserted replaced
13880:5f819b90d479 13881:99b265e0d1d0
     1 // LzmaAlone.cpp
       
     2 
       
     3 #include "StdAfx.h"
       
     4 
       
     5 #include "../../../Common/MyWindows.h"
       
     6 #include "../../../Common/MyInitGuid.h"
       
     7 
       
     8 #include <stdio.h>
       
     9 
       
    10 #if defined(_WIN32) || defined(OS2) || defined(MSDOS)
       
    11 #include <fcntl.h>
       
    12 #include <io.h>
       
    13 #define MY_SET_BINARY_MODE(file) _setmode(_fileno(file), O_BINARY)
       
    14 #else
       
    15 #define MY_SET_BINARY_MODE(file)
       
    16 #endif
       
    17 
       
    18 #include "../../../Common/CommandLineParser.h"
       
    19 #include "../../../Common/StringConvert.h"
       
    20 #include "../../../Common/StringToInt.h"
       
    21 
       
    22 #include "../../Common/FileStreams.h"
       
    23 #include "../../Common/StreamUtils.h"
       
    24 
       
    25 #include "../LZMA/LZMADecoder.h"
       
    26 #include "../LZMA/LZMAEncoder.h"
       
    27 
       
    28 #include "LzmaBenchCon.h"
       
    29 #include "LzmaRam.h"
       
    30 
       
    31 #ifdef COMPRESS_MF_MT
       
    32 #include "../../../Windows/System.h"
       
    33 #endif
       
    34 
       
    35 #include "../../MyVersion.h"
       
    36 
       
    37 extern "C"
       
    38 {
       
    39 #include "LzmaRamDecode.h"
       
    40 }
       
    41 
       
    42 using namespace NCommandLineParser;
       
    43 
       
    44 #ifdef _WIN32
       
    45 bool g_IsNT = false;
       
    46 static inline bool IsItWindowsNT()
       
    47 {
       
    48   OSVERSIONINFO versionInfo;
       
    49   versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
       
    50   if (!::GetVersionEx(&versionInfo)) 
       
    51     return false;
       
    52   return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
       
    53 }
       
    54 #endif
       
    55 
       
    56 static const char *kCantAllocate = "Can not allocate memory";
       
    57 static const char *kReadError = "Read error";
       
    58 static const char *kWriteError = "Write error";
       
    59 
       
    60 namespace NKey {
       
    61 enum Enum
       
    62 {
       
    63   kHelp1 = 0,
       
    64   kHelp2,
       
    65   kMode,
       
    66   kDictionary,
       
    67   kFastBytes,
       
    68   kMatchFinderCycles,
       
    69   kLitContext,
       
    70   kLitPos,
       
    71   kPosBits,
       
    72   kMatchFinder,
       
    73   kMultiThread,
       
    74   kEOS,
       
    75   kStdIn,
       
    76   kStdOut,
       
    77   kFilter86
       
    78 };
       
    79 }
       
    80 
       
    81 static const CSwitchForm kSwitchForms[] = 
       
    82 {
       
    83   { L"?",  NSwitchType::kSimple, false },
       
    84   { L"H",  NSwitchType::kSimple, false },
       
    85   { L"A", NSwitchType::kUnLimitedPostString, false, 1 },
       
    86   { L"D", NSwitchType::kUnLimitedPostString, false, 1 },
       
    87   { L"FB", NSwitchType::kUnLimitedPostString, false, 1 },
       
    88   { L"MC", NSwitchType::kUnLimitedPostString, false, 1 },
       
    89   { L"LC", NSwitchType::kUnLimitedPostString, false, 1 },
       
    90   { L"LP", NSwitchType::kUnLimitedPostString, false, 1 },
       
    91   { L"PB", NSwitchType::kUnLimitedPostString, false, 1 },
       
    92   { L"MF", NSwitchType::kUnLimitedPostString, false, 1 },
       
    93   { L"MT", NSwitchType::kUnLimitedPostString, false, 0 },
       
    94   { L"EOS", NSwitchType::kSimple, false },
       
    95   { L"SI",  NSwitchType::kSimple, false },
       
    96   { L"SO",  NSwitchType::kSimple, false },
       
    97   { L"F86",  NSwitchType::kPostChar, false, 0, 0, L"+" }
       
    98 };
       
    99 
       
   100 static const int kNumSwitches = sizeof(kSwitchForms) / sizeof(kSwitchForms[0]);
       
   101 
       
   102 static void PrintHelp()
       
   103 {
       
   104   fprintf(stderr, "\nUsage:  LZMA <e|d> inputFile outputFile [<switches>...]\n"
       
   105              "  e: encode file\n"
       
   106              "  d: decode file\n"
       
   107              "  b: Benchmark\n"
       
   108     "<Switches>\n"
       
   109     "  -a{N}:  set compression mode - [0, 1], default: 1 (max)\n"
       
   110     "  -d{N}:  set dictionary - [0,30], default: 23 (8MB)\n"
       
   111     "  -fb{N}: set number of fast bytes - [5, 273], default: 128\n"
       
   112     "  -mc{N}: set number of cycles for match finder\n"
       
   113     "  -lc{N}: set number of literal context bits - [0, 8], default: 3\n"
       
   114     "  -lp{N}: set number of literal pos bits - [0, 4], default: 0\n"
       
   115     "  -pb{N}: set number of pos bits - [0, 4], default: 2\n"
       
   116     "  -mf{MF_ID}: set Match Finder: [bt2, bt3, bt4, hc4], default: bt4\n"
       
   117     "  -mt{N}: set number of CPU threads\n"
       
   118     "  -eos:   write End Of Stream marker\n"
       
   119     "  -si:    read data from stdin\n"
       
   120     "  -so:    write data to stdout\n"
       
   121     );
       
   122 }
       
   123 
       
   124 static void PrintHelpAndExit(const char *s)
       
   125 {
       
   126   fprintf(stderr, "\nError: %s\n\n", s);
       
   127   PrintHelp();
       
   128   throw -1;
       
   129 }
       
   130 
       
   131 static void IncorrectCommand()
       
   132 {
       
   133   PrintHelpAndExit("Incorrect command");
       
   134 }
       
   135 
       
   136 static void WriteArgumentsToStringList(int numArguments, const char *arguments[], 
       
   137     UStringVector &strings)
       
   138 {
       
   139   for(int i = 1; i < numArguments; i++)
       
   140     strings.Add(MultiByteToUnicodeString(arguments[i]));
       
   141 }
       
   142 
       
   143 static bool GetNumber(const wchar_t *s, UInt32 &value)
       
   144 {
       
   145   value = 0;
       
   146   if (MyStringLen(s) == 0)
       
   147     return false;
       
   148   const wchar_t *end;
       
   149   UInt64 res = ConvertStringToUInt64(s, &end);
       
   150   if (*end != L'\0')
       
   151     return false;
       
   152   if (res > 0xFFFFFFFF)
       
   153     return false;
       
   154   value = UInt32(res);
       
   155   return true;
       
   156 }
       
   157 
       
   158 int main2(int n, const char *args[])
       
   159 {
       
   160   #ifdef _WIN32
       
   161   g_IsNT = IsItWindowsNT();
       
   162   #endif
       
   163 
       
   164   fprintf(stderr, "\nLZMA " MY_VERSION_COPYRIGHT_DATE "\n");
       
   165 
       
   166   if (n == 1)
       
   167   {
       
   168     PrintHelp();
       
   169     return 0;
       
   170   }
       
   171 
       
   172   bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4);
       
   173   if (unsupportedTypes)
       
   174   {
       
   175     fprintf(stderr, "Unsupported base types. Edit Common/Types.h and recompile");
       
   176     return 1;
       
   177   }   
       
   178 
       
   179   UStringVector commandStrings;
       
   180   WriteArgumentsToStringList(n, args, commandStrings);
       
   181   CParser parser(kNumSwitches);
       
   182   try
       
   183   {
       
   184     parser.ParseStrings(kSwitchForms, commandStrings);
       
   185   }
       
   186   catch(...) 
       
   187   {
       
   188     IncorrectCommand();
       
   189   }
       
   190 
       
   191   if(parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
       
   192   {
       
   193     PrintHelp();
       
   194     return 0;
       
   195   }
       
   196   const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
       
   197 
       
   198   int paramIndex = 0;
       
   199   if (paramIndex >= nonSwitchStrings.Size())
       
   200     IncorrectCommand();
       
   201   const UString &command = nonSwitchStrings[paramIndex++]; 
       
   202 
       
   203   bool dictionaryIsDefined = false;
       
   204   UInt32 dictionary = (UInt32)-1;
       
   205   if(parser[NKey::kDictionary].ThereIs)
       
   206   {
       
   207     UInt32 dicLog;
       
   208     if (!GetNumber(parser[NKey::kDictionary].PostStrings[0], dicLog))
       
   209       IncorrectCommand();
       
   210     dictionary = 1 << dicLog;
       
   211     dictionaryIsDefined = true;
       
   212   }
       
   213   UString mf = L"BT4";
       
   214   if (parser[NKey::kMatchFinder].ThereIs)
       
   215     mf = parser[NKey::kMatchFinder].PostStrings[0];
       
   216 
       
   217   UInt32 numThreads = (UInt32)-1;
       
   218 
       
   219   #ifdef COMPRESS_MF_MT
       
   220   if (parser[NKey::kMultiThread].ThereIs)
       
   221   {
       
   222     UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
       
   223     const UString &s = parser[NKey::kMultiThread].PostStrings[0];
       
   224     if (s.IsEmpty())
       
   225       numThreads = numCPUs;
       
   226     else
       
   227       if (!GetNumber(s, numThreads))
       
   228         IncorrectCommand();
       
   229   }
       
   230   #endif
       
   231 
       
   232   if (command.CompareNoCase(L"b") == 0)
       
   233   {
       
   234     const UInt32 kNumDefaultItereations = 1;
       
   235     UInt32 numIterations = kNumDefaultItereations;
       
   236     {
       
   237       if (paramIndex < nonSwitchStrings.Size())
       
   238         if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations))
       
   239           numIterations = kNumDefaultItereations;
       
   240     }
       
   241     return LzmaBenchCon(stderr, numIterations, numThreads, dictionary);
       
   242   }
       
   243 
       
   244   if (numThreads == (UInt32)-1)
       
   245     numThreads = 1;
       
   246 
       
   247   bool encodeMode = false;
       
   248   if (command.CompareNoCase(L"e") == 0)
       
   249     encodeMode = true;
       
   250   else if (command.CompareNoCase(L"d") == 0)
       
   251     encodeMode = false;
       
   252   else
       
   253     IncorrectCommand();
       
   254 
       
   255   bool stdInMode = parser[NKey::kStdIn].ThereIs;
       
   256   bool stdOutMode = parser[NKey::kStdOut].ThereIs;
       
   257 
       
   258   CMyComPtr<ISequentialInStream> inStream;
       
   259   CInFileStream *inStreamSpec = 0;
       
   260   if (stdInMode)
       
   261   {
       
   262     inStream = new CStdInFileStream;
       
   263     MY_SET_BINARY_MODE(stdin);
       
   264   }
       
   265   else
       
   266   {
       
   267     if (paramIndex >= nonSwitchStrings.Size())
       
   268       IncorrectCommand();
       
   269     const UString &inputName = nonSwitchStrings[paramIndex++]; 
       
   270     inStreamSpec = new CInFileStream;
       
   271     inStream = inStreamSpec;
       
   272     if (!inStreamSpec->Open(GetSystemString(inputName)))
       
   273     {
       
   274       fprintf(stderr, "\nError: can not open input file %s\n", 
       
   275           (const char *)GetOemString(inputName));
       
   276       return 1;
       
   277     }
       
   278   }
       
   279 
       
   280   CMyComPtr<ISequentialOutStream> outStream;
       
   281   COutFileStream *outStreamSpec = NULL;
       
   282   if (stdOutMode)
       
   283   {
       
   284     outStream = new CStdOutFileStream;
       
   285     MY_SET_BINARY_MODE(stdout);
       
   286   }
       
   287   else
       
   288   {
       
   289     if (paramIndex >= nonSwitchStrings.Size())
       
   290       IncorrectCommand();
       
   291     const UString &outputName = nonSwitchStrings[paramIndex++]; 
       
   292     outStreamSpec = new COutFileStream;
       
   293     outStream = outStreamSpec;
       
   294     if (!outStreamSpec->Create(GetSystemString(outputName), true))
       
   295     {
       
   296       fprintf(stderr, "\nError: can not open output file %s\n", 
       
   297         (const char *)GetOemString(outputName));
       
   298       return 1;
       
   299     }
       
   300   }
       
   301 
       
   302   if (parser[NKey::kFilter86].ThereIs)
       
   303   {
       
   304     // -f86 switch is for x86 filtered mode: BCJ + LZMA.
       
   305     if (parser[NKey::kEOS].ThereIs || stdInMode)
       
   306       throw "Can not use stdin in this mode";
       
   307     UInt64 fileSize;
       
   308     inStreamSpec->File.GetLength(fileSize);
       
   309     if (fileSize > 0xF0000000)
       
   310       throw "File is too big";
       
   311     UInt32 inSize = (UInt32)fileSize;
       
   312     Byte *inBuffer = 0;
       
   313     if (inSize != 0)
       
   314     {
       
   315       inBuffer = (Byte *)MyAlloc((size_t)inSize); 
       
   316       if (inBuffer == 0)
       
   317         throw kCantAllocate;
       
   318     }
       
   319     
       
   320     UInt32 processedSize;
       
   321     if (ReadStream(inStream, inBuffer, (UInt32)inSize, &processedSize) != S_OK)
       
   322       throw "Can not read";
       
   323     if ((UInt32)inSize != processedSize)
       
   324       throw "Read size error";
       
   325 
       
   326     Byte *outBuffer = 0;
       
   327     size_t outSizeProcessed;
       
   328     if (encodeMode)
       
   329     {
       
   330       // we allocate 105% of original size for output buffer
       
   331       size_t outSize = (size_t)fileSize / 20 * 21 + (1 << 16);
       
   332       if (outSize != 0)
       
   333       {
       
   334         outBuffer = (Byte *)MyAlloc((size_t)outSize); 
       
   335         if (outBuffer == 0)
       
   336           throw kCantAllocate;
       
   337       }
       
   338       if (!dictionaryIsDefined)
       
   339         dictionary = 1 << 23;
       
   340       int res = LzmaRamEncode(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, 
       
   341           dictionary, parser[NKey::kFilter86].PostCharIndex == 0 ? SZ_FILTER_YES : SZ_FILTER_AUTO);
       
   342       if (res != 0)
       
   343       {
       
   344         fprintf(stderr, "\nEncoder error = %d\n", (int)res);
       
   345         return 1;
       
   346       }
       
   347     }
       
   348     else
       
   349     {
       
   350       size_t outSize;
       
   351       if (LzmaRamGetUncompressedSize(inBuffer, inSize, &outSize) != 0)
       
   352         throw "data error";
       
   353       if (outSize != 0)
       
   354       {
       
   355         outBuffer = (Byte *)MyAlloc(outSize); 
       
   356         if (outBuffer == 0)
       
   357           throw kCantAllocate;
       
   358       }
       
   359       int res = LzmaRamDecompress(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, malloc, free);
       
   360       if (res != 0)
       
   361         throw "LzmaDecoder error";
       
   362     }
       
   363     if (WriteStream(outStream, outBuffer, (UInt32)outSizeProcessed, &processedSize) != S_OK)
       
   364       throw kWriteError;
       
   365     MyFree(outBuffer);
       
   366     MyFree(inBuffer);
       
   367     return 0;
       
   368   }
       
   369 
       
   370 
       
   371   UInt64 fileSize;
       
   372   if (encodeMode)
       
   373   {
       
   374     NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder;
       
   375     CMyComPtr<ICompressCoder> encoder = encoderSpec;
       
   376 
       
   377     if (!dictionaryIsDefined)
       
   378       dictionary = 1 << 23;
       
   379 
       
   380     UInt32 posStateBits = 2;
       
   381     UInt32 litContextBits = 3; // for normal files
       
   382     // UInt32 litContextBits = 0; // for 32-bit data
       
   383     UInt32 litPosBits = 0;
       
   384     // UInt32 litPosBits = 2; // for 32-bit data
       
   385     UInt32 algorithm = 1;
       
   386     UInt32 numFastBytes = 128;
       
   387     UInt32 matchFinderCycles = 16 + numFastBytes / 2;
       
   388     bool matchFinderCyclesDefined = false;
       
   389 
       
   390     bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
       
   391  
       
   392     if(parser[NKey::kMode].ThereIs)
       
   393       if (!GetNumber(parser[NKey::kMode].PostStrings[0], algorithm))
       
   394         IncorrectCommand();
       
   395 
       
   396     if(parser[NKey::kFastBytes].ThereIs)
       
   397       if (!GetNumber(parser[NKey::kFastBytes].PostStrings[0], numFastBytes))
       
   398         IncorrectCommand();
       
   399     matchFinderCyclesDefined = parser[NKey::kMatchFinderCycles].ThereIs;
       
   400     if (matchFinderCyclesDefined)
       
   401       if (!GetNumber(parser[NKey::kMatchFinderCycles].PostStrings[0], matchFinderCycles))
       
   402         IncorrectCommand();
       
   403     if(parser[NKey::kLitContext].ThereIs)
       
   404       if (!GetNumber(parser[NKey::kLitContext].PostStrings[0], litContextBits))
       
   405         IncorrectCommand();
       
   406     if(parser[NKey::kLitPos].ThereIs)
       
   407       if (!GetNumber(parser[NKey::kLitPos].PostStrings[0], litPosBits))
       
   408         IncorrectCommand();
       
   409     if(parser[NKey::kPosBits].ThereIs)
       
   410       if (!GetNumber(parser[NKey::kPosBits].PostStrings[0], posStateBits))
       
   411         IncorrectCommand();
       
   412 
       
   413     PROPID propIDs[] = 
       
   414     {
       
   415       NCoderPropID::kDictionarySize,
       
   416       NCoderPropID::kPosStateBits,
       
   417       NCoderPropID::kLitContextBits,
       
   418       NCoderPropID::kLitPosBits,
       
   419       NCoderPropID::kAlgorithm,
       
   420       NCoderPropID::kNumFastBytes,
       
   421       NCoderPropID::kMatchFinder,
       
   422       NCoderPropID::kEndMarker,
       
   423       NCoderPropID::kNumThreads,
       
   424       NCoderPropID::kMatchFinderCycles,
       
   425     };
       
   426     const int kNumPropsMax = sizeof(propIDs) / sizeof(propIDs[0]);
       
   427 
       
   428     PROPVARIANT properties[kNumPropsMax];
       
   429     for (int p = 0; p < 6; p++)
       
   430       properties[p].vt = VT_UI4;
       
   431 
       
   432     properties[0].ulVal = (UInt32)dictionary;
       
   433     properties[1].ulVal = (UInt32)posStateBits;
       
   434     properties[2].ulVal = (UInt32)litContextBits;
       
   435     properties[3].ulVal = (UInt32)litPosBits;
       
   436     properties[4].ulVal = (UInt32)algorithm;
       
   437     properties[5].ulVal = (UInt32)numFastBytes;
       
   438 
       
   439     properties[6].vt = VT_BSTR;
       
   440     properties[6].bstrVal = (BSTR)(const wchar_t *)mf;
       
   441 
       
   442     properties[7].vt = VT_BOOL;
       
   443     properties[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;
       
   444 
       
   445     properties[8].vt = VT_UI4;
       
   446     properties[8].ulVal = (UInt32)numThreads;
       
   447 
       
   448     // it must be last in property list
       
   449     properties[9].vt = VT_UI4;
       
   450     properties[9].ulVal = (UInt32)matchFinderCycles;
       
   451 
       
   452     int numProps = kNumPropsMax;
       
   453     if (!matchFinderCyclesDefined)
       
   454       numProps--;
       
   455 
       
   456     if (encoderSpec->SetCoderProperties(propIDs, properties, numProps) != S_OK)
       
   457       IncorrectCommand();
       
   458     encoderSpec->WriteCoderProperties(outStream);
       
   459 
       
   460     if (eos || stdInMode)
       
   461       fileSize = (UInt64)(Int64)-1;
       
   462     else
       
   463       inStreamSpec->File.GetLength(fileSize);
       
   464 
       
   465     for (int i = 0; i < 8; i++)
       
   466     {
       
   467       Byte b = Byte(fileSize >> (8 * i));
       
   468       if (outStream->Write(&b, 1, 0) != S_OK)
       
   469       {
       
   470         fprintf(stderr, kWriteError);
       
   471         return 1;
       
   472       }
       
   473     }
       
   474     HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
       
   475     if (result == E_OUTOFMEMORY)
       
   476     {
       
   477       fprintf(stderr, "\nError: Can not allocate memory\n");
       
   478       return 1;
       
   479     }   
       
   480     else if (result != S_OK)
       
   481     {
       
   482       fprintf(stderr, "\nEncoder error = %X\n", (unsigned int)result);
       
   483       return 1;
       
   484     }   
       
   485   }
       
   486   else
       
   487   {
       
   488     NCompress::NLZMA::CDecoder *decoderSpec = new NCompress::NLZMA::CDecoder;
       
   489     CMyComPtr<ICompressCoder> decoder = decoderSpec;
       
   490     const UInt32 kPropertiesSize = 5;
       
   491     Byte properties[kPropertiesSize];
       
   492     UInt32 processedSize;
       
   493     if (ReadStream(inStream, properties, kPropertiesSize, &processedSize) != S_OK)
       
   494     {
       
   495       fprintf(stderr, kReadError);
       
   496       return 1;
       
   497     }
       
   498     if (processedSize != kPropertiesSize)
       
   499     {
       
   500       fprintf(stderr, kReadError);
       
   501       return 1;
       
   502     }
       
   503     if (decoderSpec->SetDecoderProperties2(properties, kPropertiesSize) != S_OK)
       
   504     {
       
   505       fprintf(stderr, "SetDecoderProperties error");
       
   506       return 1;
       
   507     }
       
   508     fileSize = 0;
       
   509     for (int i = 0; i < 8; i++)
       
   510     {
       
   511       Byte b;
       
   512       if (inStream->Read(&b, 1, &processedSize) != S_OK)
       
   513       {
       
   514         fprintf(stderr, kReadError);
       
   515         return 1;
       
   516       }
       
   517       if (processedSize != 1)
       
   518       {
       
   519         fprintf(stderr, kReadError);
       
   520         return 1;
       
   521       }
       
   522       fileSize |= ((UInt64)b) << (8 * i);
       
   523     }
       
   524     if (decoder->Code(inStream, outStream, 0, &fileSize, 0) != S_OK)
       
   525     {
       
   526       fprintf(stderr, "Decoder error");
       
   527       return 1;
       
   528     }   
       
   529   }
       
   530   if (outStreamSpec != NULL)
       
   531   {
       
   532     if (outStreamSpec->Close() != S_OK)
       
   533     {
       
   534       fprintf(stderr, "File closing error");
       
   535       return 1;
       
   536     }
       
   537   }
       
   538   return 0;
       
   539 }
       
   540 
       
   541 int main(int n, const char *args[])
       
   542 {
       
   543   try { return main2(n, args); }
       
   544   catch(const char *s) 
       
   545   { 
       
   546     fprintf(stderr, "\nError: %s\n", s);
       
   547     return 1; 
       
   548   }
       
   549   catch(...) 
       
   550   { 
       
   551     fprintf(stderr, "\nError\n");
       
   552     return 1; 
       
   553   }
       
   554 }