tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

LzmaAlone.cpp (19352B)


      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 }