Home | History | Annotate | Download | only in LzmaCon
      1 // LzmaAlone.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include <stdio.h>
      6 
      7 #include "../../../../C/CpuArch.h"
      8 
      9 #if (defined(_WIN32) || defined(OS2) || defined(MSDOS)) && !defined(UNDER_CE)
     10 #include <fcntl.h>
     11 #include <io.h>
     12 #define MY_SET_BINARY_MODE(file) _setmode(_fileno(file), O_BINARY)
     13 #else
     14 #define MY_SET_BINARY_MODE(file)
     15 #endif
     16 
     17 #include "../../../Common/MyWindows.h"
     18 #include "../../../Common/MyInitGuid.h"
     19 
     20 #include "../../../../C/7zVersion.h"
     21 #include "../../../../C/Alloc.h"
     22 #include "../../../../C/Lzma86.h"
     23 
     24 #include "../../../Windows/NtCheck.h"
     25 
     26 #ifndef _7ZIP_ST
     27 #include "../../../Windows/System.h"
     28 #endif
     29 
     30 #include "../../../Common/IntToString.h"
     31 #include "../../../Common/CommandLineParser.h"
     32 #include "../../../Common/StringConvert.h"
     33 #include "../../../Common/StringToInt.h"
     34 
     35 #include "../../Common/FileStreams.h"
     36 #include "../../Common/StreamUtils.h"
     37 
     38 #include "../../Compress/LzmaDecoder.h"
     39 #include "../../Compress/LzmaEncoder.h"
     40 
     41 #include "../../UI/Console/BenchCon.h"
     42 #include "../../UI/Console/ConsoleClose.h"
     43 
     44 bool g_LargePagesMode = false;
     45 
     46 using namespace NCommandLineParser;
     47 
     48 static const unsigned kDictSizeLog = 24;
     49 
     50 #define kCopyrightString "\nLZMA " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n"
     51 
     52 static const char * const kHelpString =
     53     "Usage:  lzma <command> [inputFile] [outputFile] [<switches>...]\n"
     54     "\n"
     55     "<command>\n"
     56     "  e : Encode file\n"
     57     "  d : Decode file\n"
     58     "  b : Benchmark\n"
     59     "<switches>\n"
     60     "  -a{N}  : set compression mode : [0, 1] : default = 1 (max)\n"
     61     "  -d{N}  : set dictionary size : [12, 30] : default = 24 (16 MiB)\n"
     62     "  -fb{N} : set number of fast bytes : [5, 273] : default = 128\n"
     63     "  -mc{N} : set number of cycles for match finder\n"
     64     "  -lc{N} : set number of literal context bits : [0, 8] : default = 3\n"
     65     "  -lp{N} : set number of literal pos bits : [0, 4] : default = 0\n"
     66     "  -pb{N} : set number of pos bits : [0, 4] : default = 2\n"
     67     "  -mf{M} : set match finder: [hc4, bt2, bt3, bt4] : default = bt4\n"
     68     "  -mt{N} : set number of CPU threads\n"
     69     "  -eos   : write end of stream marker\n"
     70     "  -si    : read data from stdin\n"
     71     "  -so    : write data to stdout\n";
     72 
     73 
     74 static const char * const kCantAllocate = "Can not allocate memory";
     75 static const char * const kReadError = "Read error";
     76 static const char * const kWriteError = "Write error";
     77 
     78 
     79 namespace NKey {
     80 enum Enum
     81 {
     82   kHelp1 = 0,
     83   kHelp2,
     84   kMethod,
     85   kLevel,
     86   kAlgo,
     87   kDict,
     88   kFb,
     89   kMc,
     90   kLc,
     91   kLp,
     92   kPb,
     93   kMatchFinder,
     94   kMultiThread,
     95   kEOS,
     96   kStdIn,
     97   kStdOut,
     98   kFilter86
     99 };
    100 }
    101 
    102 static const CSwitchForm kSwitchForms[] =
    103 {
    104   { "?",  NSwitchType::kSimple, false },
    105   { "H",  NSwitchType::kSimple, false },
    106   { "MM", NSwitchType::kString, false, 1 },
    107   { "X", NSwitchType::kString, false, 1 },
    108   { "A", NSwitchType::kString, false, 1 },
    109   { "D", NSwitchType::kString, false, 1 },
    110   { "FB", NSwitchType::kString, false, 1 },
    111   { "MC", NSwitchType::kString, false, 1 },
    112   { "LC", NSwitchType::kString, false, 1 },
    113   { "LP", NSwitchType::kString, false, 1 },
    114   { "PB", NSwitchType::kString, false, 1 },
    115   { "MF", NSwitchType::kString, false, 1 },
    116   { "MT", NSwitchType::kString, false, 0 },
    117   { "EOS", NSwitchType::kSimple, false },
    118   { "SI",  NSwitchType::kSimple, false },
    119   { "SO",  NSwitchType::kSimple, false },
    120   { "F86",  NSwitchType::kChar, false, 0, "+" }
    121 };
    122 
    123 
    124 static void Convert_UString_to_AString(const UString &s, AString &temp)
    125 {
    126   int codePage = CP_OEMCP;
    127   /*
    128   int g_CodePage = -1;
    129   int codePage = g_CodePage;
    130   if (codePage == -1)
    131     codePage = CP_OEMCP;
    132   if (codePage == CP_UTF8)
    133     ConvertUnicodeToUTF8(s, temp);
    134   else
    135   */
    136     UnicodeStringToMultiByte2(temp, s, (UINT)codePage);
    137 }
    138 
    139 static void PrintErr(const char *s)
    140 {
    141   fputs(s, stderr);
    142 }
    143 
    144 static void PrintErr_LF(const char *s)
    145 {
    146   PrintErr(s);
    147   fputc('\n', stderr);
    148 }
    149 
    150 
    151 static void PrintError(const char *s)
    152 {
    153   PrintErr("\nERROR: ");
    154   PrintErr_LF(s);
    155 }
    156 
    157 static void PrintError2(const char *s1, const UString &s2)
    158 {
    159   PrintError(s1);
    160   AString a;
    161   Convert_UString_to_AString(s2, a);
    162   PrintErr_LF(a);
    163 }
    164 
    165 static void PrintError_int(const char *s, int code)
    166 {
    167   PrintError(s);
    168   char temp[32];
    169   ConvertInt64ToString(code, temp);
    170   PrintErr("Error code = ");
    171   PrintErr_LF(temp);
    172 }
    173 
    174 
    175 
    176 static void Print(const char *s)
    177 {
    178   fputs(s, stdout);
    179 }
    180 
    181 static void Print_UInt64(UInt64 v)
    182 {
    183   char temp[32];
    184   ConvertUInt64ToString(v, temp);
    185   Print(temp);
    186 }
    187 
    188 static void Print_MB(UInt64 v)
    189 {
    190   Print_UInt64(v);
    191   Print(" MiB");
    192 }
    193 
    194 static void Print_Size(const char *s, UInt64 v)
    195 {
    196   Print(s);
    197   Print_UInt64(v);
    198   Print(" (");
    199   Print_MB(v >> 20);
    200   Print(")\n");
    201 }
    202 
    203 static void PrintTitle()
    204 {
    205   Print(kCopyrightString);
    206 }
    207 
    208 static void PrintHelp()
    209 {
    210   PrintTitle();
    211   Print(kHelpString);
    212 }
    213 
    214 class CProgressPrint:
    215   public ICompressProgressInfo,
    216   public CMyUnknownImp
    217 {
    218   UInt64 _size1;
    219   UInt64 _size2;
    220 public:
    221   CProgressPrint(): _size1(0), _size2(0) {}
    222 
    223   void ClosePrint();
    224 
    225   MY_UNKNOWN_IMP1(ICompressProgressInfo)
    226 
    227   STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
    228 };
    229 
    230 #define BACK_STR \
    231 "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
    232 static const char * const kBackSpaces =
    233 BACK_STR
    234 "                                                                "
    235 BACK_STR;
    236 
    237 
    238 void CProgressPrint::ClosePrint()
    239 {
    240   Print(kBackSpaces);
    241 }
    242 
    243 STDMETHODIMP CProgressPrint::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
    244 {
    245   if (NConsoleClose::TestBreakSignal())
    246     return E_ABORT;
    247   if (inSize)
    248   {
    249     UInt64 v1 = *inSize >> 20;
    250     UInt64 v2 = _size2;
    251     if (outSize)
    252       v2 = *outSize >> 20;
    253     if (v1 != _size1 || v2 != _size2)
    254     {
    255       _size1 = v1;
    256       _size2 = v2;
    257       ClosePrint();
    258       Print_MB(_size1);
    259       Print(" -> ");
    260       Print_MB(_size2);
    261     }
    262   }
    263   return S_OK;
    264 }
    265 
    266 
    267 static void IncorrectCommand()
    268 {
    269   throw "Incorrect command";
    270 }
    271 
    272 static UInt32 GetNumber(const wchar_t *s)
    273 {
    274   const wchar_t *end;
    275   UInt32 v = ConvertStringToUInt32(s, &end);
    276   if (*end != 0)
    277     IncorrectCommand();
    278   return v;
    279 }
    280 
    281 static void ParseUInt32(const CParser &parser, unsigned index, UInt32 &res)
    282 {
    283   if (parser[index].ThereIs)
    284     res = GetNumber(parser[index].PostStrings[0]);
    285 }
    286 
    287 
    288 static int Error_HRESULT(const char *s, HRESULT res)
    289 {
    290   if (res == E_ABORT)
    291   {
    292     Print("\n\nBreak signaled\n");
    293     return 255;
    294   }
    295 
    296   PrintError(s);
    297 
    298   if (res == E_OUTOFMEMORY)
    299   {
    300     PrintErr_LF(kCantAllocate);
    301     return 8;
    302   }
    303   if (res == E_INVALIDARG)
    304   {
    305     PrintErr_LF("Ununsupported parameter");
    306   }
    307   else
    308   {
    309     char temp[32];
    310     ConvertUInt32ToHex(res, temp);
    311     PrintErr("Error code = 0x");
    312     PrintErr_LF(temp);
    313   }
    314   return 1;
    315 }
    316 
    317 #define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1;
    318 
    319 static void AddProp(CObjectVector<CProperty> &props2, const char *name, const wchar_t *val)
    320 {
    321   CProperty &prop = props2.AddNew();
    322   prop.Name = name;
    323   prop.Value = val;
    324 }
    325 
    326 static int main2(int numArgs, const char *args[])
    327 {
    328   NT_CHECK
    329 
    330   if (numArgs == 1)
    331   {
    332     PrintHelp();
    333     return 0;
    334   }
    335 
    336   /*
    337   bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 8);
    338   if (unsupportedTypes)
    339     throw "Unsupported base types. Edit Common/Types.h and recompile";
    340   */
    341 
    342   UStringVector commandStrings;
    343   for (int i = 1; i < numArgs; i++)
    344     commandStrings.Add(MultiByteToUnicodeString(args[i]));
    345 
    346   CParser parser;
    347   try
    348   {
    349     if (!parser.ParseStrings(kSwitchForms, ARRAY_SIZE(kSwitchForms), commandStrings))
    350     {
    351       PrintError2(parser.ErrorMessage, parser.ErrorLine);
    352       return 1;
    353     }
    354   }
    355   catch(...)
    356   {
    357     IncorrectCommand();
    358   }
    359 
    360   if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
    361   {
    362     PrintHelp();
    363     return 0;
    364   }
    365 
    366   bool stdInMode = parser[NKey::kStdIn].ThereIs;
    367   bool stdOutMode = parser[NKey::kStdOut].ThereIs;
    368 
    369   if (!stdOutMode)
    370     PrintTitle();
    371 
    372   const UStringVector &params = parser.NonSwitchStrings;
    373 
    374   unsigned paramIndex = 0;
    375   if (paramIndex >= params.Size())
    376     IncorrectCommand();
    377   const UString &command = params[paramIndex++];
    378 
    379   CObjectVector<CProperty> props2;
    380   bool dictDefined = false;
    381   UInt32 dict = (UInt32)(Int32)-1;
    382 
    383   if (parser[NKey::kDict].ThereIs)
    384   {
    385     UInt32 dictLog;
    386     const UString &s = parser[NKey::kDict].PostStrings[0];
    387     dictLog = GetNumber(s);
    388     dict = 1 << dictLog;
    389     dictDefined = true;
    390     AddProp(props2, "d", s);
    391   }
    392 
    393   if (parser[NKey::kLevel].ThereIs)
    394   {
    395     const UString &s = parser[NKey::kLevel].PostStrings[0];
    396     /* UInt32 level = */ GetNumber(s);
    397     AddProp(props2, "x", s);
    398   }
    399 
    400   UString mf ("BT4");
    401   if (parser[NKey::kMatchFinder].ThereIs)
    402     mf = parser[NKey::kMatchFinder].PostStrings[0];
    403 
    404   UInt32 numThreads = (UInt32)(Int32)-1;
    405 
    406   #ifndef _7ZIP_ST
    407 
    408   if (parser[NKey::kMultiThread].ThereIs)
    409   {
    410     const UString &s = parser[NKey::kMultiThread].PostStrings[0];
    411     if (s.IsEmpty())
    412       numThreads = NWindows::NSystem::GetNumberOfProcessors();
    413     else
    414       numThreads = GetNumber(s);
    415     AddProp(props2, "mt", s);
    416   }
    417 
    418   #endif
    419 
    420 
    421   if (parser[NKey::kMethod].ThereIs)
    422   {
    423     const UString &s = parser[NKey::kMethod].PostStrings[0];
    424     if (s.IsEmpty() || s[0] != '=')
    425       IncorrectCommand();
    426     AddProp(props2, "m", s.Ptr(1));
    427   }
    428 
    429   if (StringsAreEqualNoCase_Ascii(command, "b"))
    430   {
    431     UInt32 numIterations = 1;
    432     if (paramIndex < params.Size())
    433       numIterations = GetNumber(params[paramIndex++]);
    434     if (params.Size() != paramIndex)
    435       IncorrectCommand();
    436 
    437     HRESULT res = BenchCon(props2, numIterations, stdout);
    438 
    439     if (res == S_OK)
    440       return 0;
    441     return Error_HRESULT("Benchmark error", res);
    442   }
    443 
    444   {
    445     UInt32 needParams = 3;
    446     if (stdInMode) needParams--;
    447     if (stdOutMode) needParams--;
    448     if (needParams != params.Size())
    449       IncorrectCommand();
    450   }
    451 
    452   if (numThreads == (UInt32)(Int32)-1)
    453     numThreads = 1;
    454 
    455   bool encodeMode = false;
    456 
    457   if (StringsAreEqualNoCase_Ascii(command, "e"))
    458     encodeMode = true;
    459   else if (!StringsAreEqualNoCase_Ascii(command, "d"))
    460     IncorrectCommand();
    461 
    462   CMyComPtr<ISequentialInStream> inStream;
    463   CInFileStream *inStreamSpec = NULL;
    464 
    465   if (stdInMode)
    466   {
    467     inStream = new CStdInFileStream;
    468     MY_SET_BINARY_MODE(stdin);
    469   }
    470   else
    471   {
    472     const UString &inputName = params[paramIndex++];
    473     inStreamSpec = new CInFileStream;
    474     inStream = inStreamSpec;
    475     if (!inStreamSpec->Open(us2fs(inputName)))
    476     {
    477       PrintError2("can not open input file", inputName);
    478       return 1;
    479     }
    480   }
    481 
    482   CMyComPtr<ISequentialOutStream> outStream;
    483   COutFileStream *outStreamSpec = NULL;
    484 
    485   if (stdOutMode)
    486   {
    487     outStream = new CStdOutFileStream;
    488     MY_SET_BINARY_MODE(stdout);
    489   }
    490   else
    491   {
    492     const UString &outputName = params[paramIndex++];
    493     outStreamSpec = new COutFileStream;
    494     outStream = outStreamSpec;
    495     if (!outStreamSpec->Create(us2fs(outputName), true))
    496     {
    497       PrintError2("can not open output file", outputName);
    498       return 1;
    499     }
    500   }
    501 
    502   bool fileSizeDefined = false;
    503   UInt64 fileSize = 0;
    504 
    505   if (inStreamSpec)
    506   {
    507     if (!inStreamSpec->File.GetLength(fileSize))
    508       throw "Can not get file length";
    509     fileSizeDefined = true;
    510     if (!stdOutMode)
    511       Print_Size("Input size:  ", fileSize);
    512   }
    513 
    514   if (encodeMode && !dictDefined)
    515   {
    516     dict = 1 << kDictSizeLog;
    517     if (fileSizeDefined)
    518     {
    519       unsigned i;
    520       for (i = 16; i < kDictSizeLog; i++)
    521         if ((UInt32)((UInt32)1 << i) >= fileSize)
    522           break;
    523       dict = (UInt32)1 << i;
    524     }
    525   }
    526 
    527   if (parser[NKey::kFilter86].ThereIs)
    528   {
    529     /* -f86 switch is for x86 filtered mode: BCJ + LZMA.
    530        It uses modified header format.
    531        It's not recommended to use -f86 mode now.
    532        You can use xz format instead, if you want to use filters */
    533 
    534     if (parser[NKey::kEOS].ThereIs || stdInMode)
    535       throw "Can not use stdin in this mode";
    536 
    537     size_t inSize = (size_t)fileSize;
    538 
    539     if (inSize != fileSize)
    540       throw "File is too big";
    541 
    542     Byte *inBuffer = NULL;
    543 
    544     if (inSize != 0)
    545     {
    546       inBuffer = (Byte *)MyAlloc((size_t)inSize);
    547       if (!inBuffer)
    548         throw kCantAllocate;
    549     }
    550 
    551     if (ReadStream_FAIL(inStream, inBuffer, inSize) != S_OK)
    552       throw "Can not read";
    553 
    554     Byte *outBuffer = NULL;
    555     size_t outSize;
    556 
    557     if (encodeMode)
    558     {
    559       // we allocate 105% of original size for output buffer
    560       UInt64 outSize64 = fileSize / 20 * 21 + (1 << 16);
    561 
    562       outSize = (size_t)outSize64;
    563 
    564       if (outSize != outSize64)
    565         throw "File is too big";
    566 
    567       if (outSize != 0)
    568       {
    569         outBuffer = (Byte *)MyAlloc((size_t)outSize);
    570         if (!outBuffer)
    571           throw kCantAllocate;
    572       }
    573 
    574       int res = Lzma86_Encode(outBuffer, &outSize, inBuffer, inSize,
    575           5, dict, parser[NKey::kFilter86].PostCharIndex == 0 ? SZ_FILTER_YES : SZ_FILTER_AUTO);
    576 
    577       if (res != 0)
    578       {
    579         PrintError_int("Encode error", (int)res);
    580         return 1;
    581       }
    582     }
    583     else
    584     {
    585       UInt64 outSize64;
    586 
    587       if (Lzma86_GetUnpackSize(inBuffer, inSize, &outSize64) != 0)
    588         throw "data error";
    589 
    590       outSize = (size_t)outSize64;
    591       if (outSize != outSize64)
    592         throw "Unpack size is too big";
    593       if (outSize != 0)
    594       {
    595         outBuffer = (Byte *)MyAlloc(outSize);
    596         if (!outBuffer)
    597           throw kCantAllocate;
    598       }
    599 
    600       int res = Lzma86_Decode(outBuffer, &outSize, inBuffer, &inSize);
    601 
    602       if (inSize != (size_t)fileSize)
    603         throw "incorrect processed size";
    604       if (res != 0)
    605       {
    606         PrintError_int("Decode error", (int)res);
    607         return 1;
    608       }
    609     }
    610 
    611     if (WriteStream(outStream, outBuffer, outSize) != S_OK)
    612       throw kWriteError;
    613 
    614     MyFree(outBuffer);
    615     MyFree(inBuffer);
    616   }
    617   else
    618   {
    619 
    620   CProgressPrint *progressSpec = NULL;
    621   CMyComPtr<ICompressProgressInfo> progress;
    622 
    623   if (!stdOutMode)
    624   {
    625     progressSpec = new CProgressPrint;
    626     progress = progressSpec;
    627   }
    628 
    629   if (encodeMode)
    630   {
    631     NCompress::NLzma::CEncoder *encoderSpec = new NCompress::NLzma::CEncoder;
    632     CMyComPtr<ICompressCoder> encoder = encoderSpec;
    633 
    634     UInt32 pb = 2;
    635     UInt32 lc = 3; // = 0; for 32-bit data
    636     UInt32 lp = 0; // = 2; for 32-bit data
    637     UInt32 algo = 1;
    638     UInt32 fb = 128;
    639     UInt32 mc = 16 + fb / 2;
    640     bool mcDefined = false;
    641 
    642     bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
    643 
    644     ParseUInt32(parser, NKey::kAlgo, algo);
    645     ParseUInt32(parser, NKey::kFb, fb);
    646     ParseUInt32(parser, NKey::kLc, lc);
    647     ParseUInt32(parser, NKey::kLp, lp);
    648     ParseUInt32(parser, NKey::kPb, pb);
    649 
    650     mcDefined = parser[NKey::kMc].ThereIs;
    651     if (mcDefined)
    652       mc = GetNumber(parser[NKey::kMc].PostStrings[0]);
    653 
    654     const PROPID propIDs[] =
    655     {
    656       NCoderPropID::kDictionarySize,
    657       NCoderPropID::kPosStateBits,
    658       NCoderPropID::kLitContextBits,
    659       NCoderPropID::kLitPosBits,
    660       NCoderPropID::kAlgorithm,
    661       NCoderPropID::kNumFastBytes,
    662       NCoderPropID::kMatchFinder,
    663       NCoderPropID::kEndMarker,
    664       NCoderPropID::kNumThreads,
    665       NCoderPropID::kMatchFinderCycles,
    666     };
    667 
    668     const unsigned kNumPropsMax = ARRAY_SIZE(propIDs);
    669 
    670     PROPVARIANT props[kNumPropsMax];
    671     for (int p = 0; p < 6; p++)
    672       props[p].vt = VT_UI4;
    673 
    674     props[0].ulVal = (UInt32)dict;
    675     props[1].ulVal = (UInt32)pb;
    676     props[2].ulVal = (UInt32)lc;
    677     props[3].ulVal = (UInt32)lp;
    678     props[4].ulVal = (UInt32)algo;
    679     props[5].ulVal = (UInt32)fb;
    680 
    681     props[6].vt = VT_BSTR;
    682     props[6].bstrVal = const_cast<BSTR>((const wchar_t *)mf);
    683 
    684     props[7].vt = VT_BOOL;
    685     props[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;
    686 
    687     props[8].vt = VT_UI4;
    688     props[8].ulVal = (UInt32)numThreads;
    689 
    690     // it must be last in property list
    691     props[9].vt = VT_UI4;
    692     props[9].ulVal = (UInt32)mc;
    693 
    694     unsigned numProps = kNumPropsMax;
    695     if (!mcDefined)
    696       numProps--;
    697 
    698     HRESULT res = encoderSpec->SetCoderProperties(propIDs, props, numProps);
    699     if (res != S_OK)
    700       return Error_HRESULT("incorrect encoder properties", res);
    701 
    702     if (encoderSpec->WriteCoderProperties(outStream) != S_OK)
    703       throw kWriteError;
    704 
    705     bool fileSizeWasUsed = true;
    706     if (eos || stdInMode)
    707     {
    708       fileSize = (UInt64)(Int64)-1;
    709       fileSizeWasUsed = false;
    710     }
    711 
    712     {
    713       Byte temp[8];
    714       for (int i = 0; i < 8; i++)
    715         temp[i]= (Byte)(fileSize >> (8 * i));
    716       if (WriteStream(outStream, temp, 8) != S_OK)
    717         throw kWriteError;
    718     }
    719 
    720     res = encoder->Code(inStream, outStream, NULL, NULL, progress);
    721     if (progressSpec)
    722       progressSpec->ClosePrint();
    723 
    724     if (res != S_OK)
    725       return Error_HRESULT("Encoding error", res);
    726 
    727     UInt64 processedSize = encoderSpec->GetInputProcessedSize();
    728 
    729     if (fileSizeWasUsed && processedSize != fileSize)
    730       throw "Incorrect size of processed data";
    731   }
    732   else
    733   {
    734     NCompress::NLzma::CDecoder *decoderSpec = new NCompress::NLzma::CDecoder;
    735     CMyComPtr<ICompressCoder> decoder = decoderSpec;
    736 
    737     decoderSpec->FinishStream = true;
    738 
    739     const unsigned kPropertiesSize = 5;
    740     Byte header[kPropertiesSize + 8];
    741 
    742     if (ReadStream_FALSE(inStream, header, kPropertiesSize + 8) != S_OK)
    743       throw kReadError;
    744 
    745     if (decoderSpec->SetDecoderProperties2(header, kPropertiesSize) != S_OK)
    746       throw "SetDecoderProperties error";
    747 
    748     UInt64 unpackSize = 0;
    749     for (int i = 0; i < 8; i++)
    750       unpackSize |= ((UInt64)header[kPropertiesSize + i]) << (8 * i);
    751 
    752     bool unpackSizeDefined = (unpackSize != (UInt64)(Int64)-1);
    753 
    754     HRESULT res = decoder->Code(inStream, outStream, NULL, unpackSizeDefined ? &unpackSize : NULL, progress);
    755     if (progressSpec)
    756       progressSpec->ClosePrint();
    757 
    758     if (res != S_OK)
    759     {
    760       if (res == S_FALSE)
    761       {
    762         PrintError("Decoding error");
    763         return 1;
    764       }
    765       return Error_HRESULT("Decoding error", res);
    766     }
    767 
    768     if (unpackSizeDefined && unpackSize != decoderSpec->GetOutputProcessedSize())
    769       throw "incorrect uncompressed size in header";
    770   }
    771   }
    772 
    773   if (outStreamSpec)
    774   {
    775     if (!stdOutMode)
    776       Print_Size("Output size: ", outStreamSpec->ProcessedSize);
    777     if (outStreamSpec->Close() != S_OK)
    778       throw "File closing error";
    779   }
    780 
    781   return 0;
    782 }
    783 
    784 int MY_CDECL main(int numArgs, const char *args[])
    785 {
    786   NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter;
    787 
    788   try { return main2(numArgs, args); }
    789   catch (const char *s)
    790   {
    791     PrintError(s);
    792     return 1;
    793   }
    794   catch(...)
    795   {
    796     PrintError("Unknown Error");
    797     return 1;
    798   }
    799 }
    800