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 
Convert_UString_to_AString(const UString & s,AString & temp)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 
PrintErr(const char * s)139 static void PrintErr(const char *s)
140 {
141   fputs(s, stderr);
142 }
143 
PrintErr_LF(const char * s)144 static void PrintErr_LF(const char *s)
145 {
146   PrintErr(s);
147   fputc('\n', stderr);
148 }
149 
150 
PrintError(const char * s)151 static void PrintError(const char *s)
152 {
153   PrintErr("\nERROR: ");
154   PrintErr_LF(s);
155 }
156 
PrintError2(const char * s1,const UString & s2)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 
PrintError_int(const char * s,int code)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 
Print(const char * s)176 static void Print(const char *s)
177 {
178   fputs(s, stdout);
179 }
180 
Print_UInt64(UInt64 v)181 static void Print_UInt64(UInt64 v)
182 {
183   char temp[32];
184   ConvertUInt64ToString(v, temp);
185   Print(temp);
186 }
187 
Print_MB(UInt64 v)188 static void Print_MB(UInt64 v)
189 {
190   Print_UInt64(v);
191   Print(" MiB");
192 }
193 
Print_Size(const char * s,UInt64 v)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 
PrintTitle()203 static void PrintTitle()
204 {
205   Print(kCopyrightString);
206 }
207 
PrintHelp()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:
CProgressPrint()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 
ClosePrint()238 void CProgressPrint::ClosePrint()
239 {
240   Print(kBackSpaces);
241 }
242 
SetRatioInfo(const UInt64 * inSize,const UInt64 * outSize)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 
IncorrectCommand()267 static void IncorrectCommand()
268 {
269   throw "Incorrect command";
270 }
271 
GetNumber(const wchar_t * s)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 
ParseUInt32(const CParser & parser,unsigned index,UInt32 & res)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 
Error_HRESULT(const char * s,HRESULT res)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 
AddProp(CObjectVector<CProperty> & props2,const char * name,const wchar_t * val)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 
main2(int numArgs,const char * args[])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 
main(int numArgs,const char * args[])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