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 ¶ms = 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