5 #include "../../../Common/MyWindows.h"
6 #include "../../../Common/MyInitGuid.h"
10 #if defined(_WIN32) || defined(OS2) || defined(MSDOS)
13 #define MY_SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
15 #define MY_SET_BINARY_MODE(file)
18 #include "../../../Common/CommandLineParser.h"
19 #include "../../../Common/StringConvert.h"
20 #include "../../../Common/StringToInt.h"
22 #include "../../Common/FileStreams.h"
23 #include "../../Common/StreamUtils.h"
25 #include "../LZMA/LZMADecoder.h"
26 #include "../LZMA/LZMAEncoder.h"
28 #include "LzmaBench.h"
33 #include "LzmaRamDecode.h"
36 using namespace NCommandLineParser
;
40 static inline bool IsItWindowsNT()
42 OSVERSIONINFO versionInfo
;
43 versionInfo
.dwOSVersionInfoSize
= sizeof(versionInfo
);
44 if (!::GetVersionEx(&versionInfo
))
46 return (versionInfo
.dwPlatformId
== VER_PLATFORM_WIN32_NT
);
50 static const char *kCantAllocate
= "Can not allocate memory";
51 static const char *kReadError
= "Read error";
52 static const char *kWriteError
= "Write error";
73 static const CSwitchForm kSwitchForms
[] =
75 { L
"?", NSwitchType::kSimple
, false },
76 { L
"H", NSwitchType::kSimple
, false },
77 { L
"A", NSwitchType::kUnLimitedPostString
, false, 1 },
78 { L
"D", NSwitchType::kUnLimitedPostString
, false, 1 },
79 { L
"FB", NSwitchType::kUnLimitedPostString
, false, 1 },
80 { L
"LC", NSwitchType::kUnLimitedPostString
, false, 1 },
81 { L
"LP", NSwitchType::kUnLimitedPostString
, false, 1 },
82 { L
"PB", NSwitchType::kUnLimitedPostString
, false, 1 },
83 { L
"MF", NSwitchType::kUnLimitedPostString
, false, 1 },
84 { L
"EOS", NSwitchType::kSimple
, false },
85 { L
"SI", NSwitchType::kSimple
, false },
86 { L
"SO", NSwitchType::kSimple
, false },
87 { L
"F86", NSwitchType::kSimple
, false }
90 static const int kNumSwitches
= sizeof(kSwitchForms
) / sizeof(kSwitchForms
[0]);
92 static void PrintHelp()
94 fprintf(stderr
, "\nUsage: LZMA <e|d> inputFile outputFile [<switches>...]\n"
99 " -a{N}: set compression mode - [0, 2], default: 2 (max)\n"
100 " -d{N}: set dictionary - [0,28], default: 23 (8MB)\n"
101 " -fb{N}: set number of fast bytes - [5, 273], default: 128\n"
102 " -lc{N}: set number of literal context bits - [0, 8], default: 3\n"
103 " -lp{N}: set number of literal pos bits - [0, 4], default: 0\n"
104 " -pb{N}: set number of pos bits - [0, 4], default: 2\n"
105 " -mf{MF_ID}: set Match Finder: [bt2, bt3, bt4, bt4b, pat2r, pat2,\n"
106 " pat2h, pat3h, pat4h, hc3, hc4], default: bt4\n"
107 " -eos: write End Of Stream marker\n"
108 " -si: read data from stdin\n"
109 " -so: write data to stdout\n"
113 static void PrintHelpAndExit(const char *s
)
115 fprintf(stderr
, "\nError: %s\n\n", s
);
120 static void IncorrectCommand()
122 PrintHelpAndExit("Incorrect command");
125 static void WriteArgumentsToStringList(int numArguments
, const char *arguments
[],
126 UStringVector
&strings
)
128 for(int i
= 1; i
< numArguments
; i
++)
129 strings
.Add(MultiByteToUnicodeString(arguments
[i
]));
132 static bool GetNumber(const wchar_t *s
, UInt32
&value
)
135 if (MyStringLen(s
) == 0)
138 UInt64 res
= ConvertStringToUInt64(s
, &end
);
141 if (res
> 0xFFFFFFFF)
147 int main2(int n
, const char *args
[])
150 g_IsNT
= IsItWindowsNT();
153 fprintf(stderr
, "\nLZMA 4.32 Copyright (c) 1999-2005 Igor Pavlov 2005-12-09\n");
161 if (sizeof(Byte
) != 1 || sizeof(UInt32
) < 4 || sizeof(UInt64
) < 4)
163 fprintf(stderr
, "Unsupported base types. Edit Common/Types.h and recompile");
167 UStringVector commandStrings
;
168 WriteArgumentsToStringList(n
, args
, commandStrings
);
169 CParser
parser(kNumSwitches
);
172 parser
.ParseStrings(kSwitchForms
, commandStrings
);
179 if(parser
[NKey::kHelp1
].ThereIs
|| parser
[NKey::kHelp2
].ThereIs
)
184 const UStringVector
&nonSwitchStrings
= parser
.NonSwitchStrings
;
187 if (paramIndex
>= nonSwitchStrings
.Size())
189 const UString
&command
= nonSwitchStrings
[paramIndex
++];
191 bool dictionaryIsDefined
= false;
192 UInt32 dictionary
= 1 << 21;
193 if(parser
[NKey::kDictionary
].ThereIs
)
196 if (!GetNumber(parser
[NKey::kDictionary
].PostStrings
[0], dicLog
))
198 dictionary
= 1 << dicLog
;
199 dictionaryIsDefined
= true;
202 if (parser
[NKey::kMatchFinder
].ThereIs
)
203 mf
= parser
[NKey::kMatchFinder
].PostStrings
[0];
205 if (command
.CompareNoCase(L
"b") == 0)
207 const UInt32 kNumDefaultItereations
= 10;
208 UInt32 numIterations
= kNumDefaultItereations
;
210 if (paramIndex
< nonSwitchStrings
.Size())
211 if (!GetNumber(nonSwitchStrings
[paramIndex
++], numIterations
))
212 numIterations
= kNumDefaultItereations
;
214 return LzmaBenchmark(stderr
, numIterations
, dictionary
,
215 mf
.CompareNoCase(L
"BT4") == 0);
218 bool encodeMode
= false;
219 if (command
.CompareNoCase(L
"e") == 0)
221 else if (command
.CompareNoCase(L
"d") == 0)
226 bool stdInMode
= parser
[NKey::kStdIn
].ThereIs
;
227 bool stdOutMode
= parser
[NKey::kStdOut
].ThereIs
;
229 CMyComPtr
<ISequentialInStream
> inStream
;
230 CInFileStream
*inStreamSpec
= 0;
233 inStream
= new CStdInFileStream
;
234 MY_SET_BINARY_MODE(stdin
);
238 if (paramIndex
>= nonSwitchStrings
.Size())
240 const UString
&inputName
= nonSwitchStrings
[paramIndex
++];
241 inStreamSpec
= new CInFileStream
;
242 inStream
= inStreamSpec
;
243 if (!inStreamSpec
->Open(GetSystemString(inputName
)))
245 fprintf(stderr
, "\nError: can not open input file %s\n",
246 (const char *)GetOemString(inputName
));
251 CMyComPtr
<ISequentialOutStream
> outStream
;
254 outStream
= new CStdOutFileStream
;
255 MY_SET_BINARY_MODE(stdout
);
259 if (paramIndex
>= nonSwitchStrings
.Size())
261 const UString
&outputName
= nonSwitchStrings
[paramIndex
++];
262 COutFileStream
*outStreamSpec
= new COutFileStream
;
263 outStream
= outStreamSpec
;
264 if (!outStreamSpec
->Create(GetSystemString(outputName
), true))
266 fprintf(stderr
, "\nError: can not open output file %s\n",
267 (const char *)GetOemString(outputName
));
272 if (parser
[NKey::kFilter86
].ThereIs
)
274 // -f86 switch is for x86 filtered mode: BCJ + LZMA.
275 if (parser
[NKey::kEOS
].ThereIs
|| stdInMode
)
276 throw "Can not use stdin in this mode";
278 inStreamSpec
->File
.GetLength(fileSize
);
279 if (fileSize
> 0xF0000000)
280 throw "File is too big";
281 UInt32 inSize
= (UInt32
)fileSize
;
285 inBuffer
= (Byte
*)MyAlloc((size_t)inSize
);
290 UInt32 processedSize
;
291 if (ReadStream(inStream
, inBuffer
, (UInt32
)inSize
, &processedSize
) != S_OK
)
292 throw "Can not read";
293 if ((UInt32
)inSize
!= processedSize
)
294 throw "Read size error";
297 size_t outSizeProcessed
;
300 // we allocate 105% of original size for output buffer
301 size_t outSize
= (size_t)fileSize
/ 20 * 21 + (1 << 16);
304 outBuffer
= (Byte
*)MyAlloc((size_t)outSize
);
308 if (!dictionaryIsDefined
)
309 dictionary
= 1 << 23;
310 int res
= LzmaRamEncode(inBuffer
, inSize
, outBuffer
, outSize
, &outSizeProcessed
,
311 dictionary
, SZ_FILTER_AUTO
);
314 fprintf(stderr
, "\nEncoder error = %d\n", (int)res
);
321 if (LzmaRamGetUncompressedSize(inBuffer
, inSize
, &outSize
) != 0)
325 outBuffer
= (Byte
*)MyAlloc(outSize
);
329 int res
= LzmaRamDecompress(inBuffer
, inSize
, outBuffer
, outSize
, &outSizeProcessed
, malloc
, free
);
331 throw "LzmaDecoder error";
333 if (WriteStream(outStream
, outBuffer
, (UInt32
)outSizeProcessed
, &processedSize
) != S_OK
)
344 NCompress::NLZMA::CEncoder
*encoderSpec
=
345 new NCompress::NLZMA::CEncoder
;
346 CMyComPtr
<ICompressCoder
> encoder
= encoderSpec
;
348 if (!dictionaryIsDefined
)
349 dictionary
= 1 << 23;
351 UInt32 posStateBits
= 2;
352 UInt32 litContextBits
= 3; // for normal files
353 // UInt32 litContextBits = 0; // for 32-bit data
354 UInt32 litPosBits
= 0;
355 // UInt32 litPosBits = 2; // for 32-bit data
356 UInt32 algorithm
= 2;
357 UInt32 numFastBytes
= 128;
359 bool eos
= parser
[NKey::kEOS
].ThereIs
|| stdInMode
;
361 if(parser
[NKey::kMode
].ThereIs
)
362 if (!GetNumber(parser
[NKey::kMode
].PostStrings
[0], algorithm
))
365 if(parser
[NKey::kFastBytes
].ThereIs
)
366 if (!GetNumber(parser
[NKey::kFastBytes
].PostStrings
[0], numFastBytes
))
368 if(parser
[NKey::kLitContext
].ThereIs
)
369 if (!GetNumber(parser
[NKey::kLitContext
].PostStrings
[0], litContextBits
))
371 if(parser
[NKey::kLitPos
].ThereIs
)
372 if (!GetNumber(parser
[NKey::kLitPos
].PostStrings
[0], litPosBits
))
374 if(parser
[NKey::kPosBits
].ThereIs
)
375 if (!GetNumber(parser
[NKey::kPosBits
].PostStrings
[0], posStateBits
))
380 NCoderPropID::kDictionarySize
,
381 NCoderPropID::kPosStateBits
,
382 NCoderPropID::kLitContextBits
,
383 NCoderPropID::kLitPosBits
,
384 NCoderPropID::kAlgorithm
,
385 NCoderPropID::kNumFastBytes
,
386 NCoderPropID::kMatchFinder
,
387 NCoderPropID::kEndMarker
389 const int kNumProps
= sizeof(propIDs
) / sizeof(propIDs
[0]);
391 NWindows::NCOM::CPropVariant properties[kNumProps];
392 properties[0] = UInt32(dictionary);
393 properties[1] = UInt32(posStateBits);
394 properties[2] = UInt32(litContextBits);
396 properties[3] = UInt32(litPosBits);
397 properties[4] = UInt32(algorithm);
398 properties[5] = UInt32(numFastBytes);
402 PROPVARIANT properties
[kNumProps
];
403 for (int p
= 0; p
< 6; p
++)
404 properties
[p
].vt
= VT_UI4
;
405 properties
[0].ulVal
= UInt32(dictionary
);
406 properties
[1].ulVal
= UInt32(posStateBits
);
407 properties
[2].ulVal
= UInt32(litContextBits
);
408 properties
[3].ulVal
= UInt32(litPosBits
);
409 properties
[4].ulVal
= UInt32(algorithm
);
410 properties
[5].ulVal
= UInt32(numFastBytes
);
412 properties
[6].vt
= VT_BSTR
;
413 properties
[6].bstrVal
= (BSTR
)(const wchar_t *)mf
;
415 properties
[7].vt
= VT_BOOL
;
416 properties
[7].boolVal
= eos
? VARIANT_TRUE
: VARIANT_FALSE
;
418 if (encoderSpec
->SetCoderProperties(propIDs
, properties
, kNumProps
) != S_OK
)
420 encoderSpec
->WriteCoderProperties(outStream
);
422 if (eos
|| stdInMode
)
423 fileSize
= (UInt64
)(Int64
)-1;
425 inStreamSpec
->File
.GetLength(fileSize
);
427 for (int i
= 0; i
< 8; i
++)
429 Byte b
= Byte(fileSize
>> (8 * i
));
430 if (outStream
->Write(&b
, 1, 0) != S_OK
)
432 fprintf(stderr
, kWriteError
);
436 HRESULT result
= encoder
->Code(inStream
, outStream
, 0, 0, 0);
437 if (result
== E_OUTOFMEMORY
)
439 fprintf(stderr
, "\nError: Can not allocate memory\n");
442 else if (result
!= S_OK
)
444 fprintf(stderr
, "\nEncoder error = %X\n", (unsigned int)result
);
450 NCompress::NLZMA::CDecoder
*decoderSpec
=
451 new NCompress::NLZMA::CDecoder
;
452 CMyComPtr
<ICompressCoder
> decoder
= decoderSpec
;
453 const UInt32 kPropertiesSize
= 5;
454 Byte properties
[kPropertiesSize
];
455 UInt32 processedSize
;
456 if (ReadStream(inStream
, properties
, kPropertiesSize
, &processedSize
) != S_OK
)
458 fprintf(stderr
, kReadError
);
461 if (processedSize
!= kPropertiesSize
)
463 fprintf(stderr
, kReadError
);
466 if (decoderSpec
->SetDecoderProperties2(properties
, kPropertiesSize
) != S_OK
)
468 fprintf(stderr
, "SetDecoderProperties error");
472 for (int i
= 0; i
< 8; i
++)
475 if (inStream
->Read(&b
, 1, &processedSize
) != S_OK
)
477 fprintf(stderr
, kReadError
);
480 if (processedSize
!= 1)
482 fprintf(stderr
, kReadError
);
485 fileSize
|= ((UInt64
)b
) << (8 * i
);
487 if (decoder
->Code(inStream
, outStream
, 0, &fileSize
, 0) != S_OK
)
489 fprintf(stderr
, "Decoder error");
496 int main(int n
, const char *args
[])
498 try { return main2(n
, args
); }
501 fprintf(stderr
, "\nError: %s\n", s
);
506 fprintf(stderr
, "\nError\n");