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