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