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