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 "LzmaBenchCon.h"
32 #include "../../../Windows/System.h"
35 #include "../../MyVersion.h"
39 #include "LzmaRamDecode.h"
42 using namespace NCommandLineParser
;
46 static inline bool IsItWindowsNT()
48 OSVERSIONINFO versionInfo
;
49 versionInfo
.dwOSVersionInfoSize
= sizeof(versionInfo
);
50 if (!::GetVersionEx(&versionInfo
))
52 return (versionInfo
.dwPlatformId
== VER_PLATFORM_WIN32_NT
);
56 static const char *kCantAllocate
= "Can not allocate memory";
57 static const char *kReadError
= "Read error";
58 static const char *kWriteError
= "Write error";
81 static const CSwitchForm kSwitchForms
[] =
83 { L
"?", NSwitchType::kSimple
, false },
84 { L
"H", NSwitchType::kSimple
, false },
85 { L
"A", NSwitchType::kUnLimitedPostString
, false, 1 },
86 { L
"D", NSwitchType::kUnLimitedPostString
, false, 1 },
87 { L
"FB", NSwitchType::kUnLimitedPostString
, false, 1 },
88 { L
"MC", NSwitchType::kUnLimitedPostString
, false, 1 },
89 { L
"LC", NSwitchType::kUnLimitedPostString
, false, 1 },
90 { L
"LP", NSwitchType::kUnLimitedPostString
, false, 1 },
91 { L
"PB", NSwitchType::kUnLimitedPostString
, false, 1 },
92 { L
"MF", NSwitchType::kUnLimitedPostString
, false, 1 },
93 { L
"MT", NSwitchType::kUnLimitedPostString
, false, 0 },
94 { L
"EOS", NSwitchType::kSimple
, false },
95 { L
"SI", NSwitchType::kSimple
, false },
96 { L
"SO", NSwitchType::kSimple
, false },
97 { L
"F86", NSwitchType::kPostChar
, false, 0, 0, L
"+" }
100 static const int kNumSwitches
= sizeof(kSwitchForms
) / sizeof(kSwitchForms
[0]);
102 static void PrintHelp()
104 fprintf(stderr
, "\nUsage: LZMA <e|d> inputFile outputFile [<switches>...]\n"
109 " -a{N}: set compression mode - [0, 1], default: 1 (max)\n"
110 " -d{N}: set dictionary - [0,30], default: 23 (8MB)\n"
111 " -fb{N}: set number of fast bytes - [5, 273], default: 128\n"
112 " -mc{N}: set number of cycles for match finder\n"
113 " -lc{N}: set number of literal context bits - [0, 8], default: 3\n"
114 " -lp{N}: set number of literal pos bits - [0, 4], default: 0\n"
115 " -pb{N}: set number of pos bits - [0, 4], default: 2\n"
116 " -mf{MF_ID}: set Match Finder: [bt2, bt3, bt4, hc4], default: bt4\n"
117 " -mt{N}: set number of CPU threads\n"
118 " -eos: write End Of Stream marker\n"
119 " -si: read data from stdin\n"
120 " -so: write data to stdout\n"
124 static void PrintHelpAndExit(const char *s
)
126 fprintf(stderr
, "\nError: %s\n\n", s
);
131 static void IncorrectCommand()
133 PrintHelpAndExit("Incorrect command");
136 static void WriteArgumentsToStringList(int numArguments
, const char *arguments
[],
137 UStringVector
&strings
)
139 for(int i
= 1; i
< numArguments
; i
++)
140 strings
.Add(MultiByteToUnicodeString(arguments
[i
]));
143 static bool GetNumber(const wchar_t *s
, UInt32
&value
)
146 if (MyStringLen(s
) == 0)
149 UInt64 res
= ConvertStringToUInt64(s
, &end
);
152 if (res
> 0xFFFFFFFF)
158 int main2(int n
, const char *args
[])
161 g_IsNT
= IsItWindowsNT();
164 fprintf(stderr
, "\nLZMA " MY_VERSION_COPYRIGHT_DATE
"\n");
172 bool unsupportedTypes
= (sizeof(Byte
) != 1 || sizeof(UInt32
) < 4 || sizeof(UInt64
) < 4);
173 if (unsupportedTypes
)
175 fprintf(stderr
, "Unsupported base types. Edit Common/Types.h and recompile");
179 UStringVector commandStrings
;
180 WriteArgumentsToStringList(n
, args
, commandStrings
);
181 CParser
parser(kNumSwitches
);
184 parser
.ParseStrings(kSwitchForms
, commandStrings
);
191 if(parser
[NKey::kHelp1
].ThereIs
|| parser
[NKey::kHelp2
].ThereIs
)
196 const UStringVector
&nonSwitchStrings
= parser
.NonSwitchStrings
;
199 if (paramIndex
>= nonSwitchStrings
.Size())
201 const UString
&command
= nonSwitchStrings
[paramIndex
++];
203 bool dictionaryIsDefined
= false;
204 UInt32 dictionary
= (UInt32
)-1;
205 if(parser
[NKey::kDictionary
].ThereIs
)
208 if (!GetNumber(parser
[NKey::kDictionary
].PostStrings
[0], dicLog
))
210 dictionary
= 1 << dicLog
;
211 dictionaryIsDefined
= true;
214 if (parser
[NKey::kMatchFinder
].ThereIs
)
215 mf
= parser
[NKey::kMatchFinder
].PostStrings
[0];
217 UInt32 numThreads
= (UInt32
)-1;
219 #ifdef COMPRESS_MF_MT
220 if (parser
[NKey::kMultiThread
].ThereIs
)
222 UInt32 numCPUs
= NWindows::NSystem::GetNumberOfProcessors();
223 const UString
&s
= parser
[NKey::kMultiThread
].PostStrings
[0];
225 numThreads
= numCPUs
;
227 if (!GetNumber(s
, numThreads
))
232 if (command
.CompareNoCase(L
"b") == 0)
234 const UInt32 kNumDefaultItereations
= 1;
235 UInt32 numIterations
= kNumDefaultItereations
;
237 if (paramIndex
< nonSwitchStrings
.Size())
238 if (!GetNumber(nonSwitchStrings
[paramIndex
++], numIterations
))
239 numIterations
= kNumDefaultItereations
;
241 return LzmaBenchCon(stderr
, numIterations
, numThreads
, dictionary
);
244 if (numThreads
== (UInt32
)-1)
247 bool encodeMode
= false;
248 if (command
.CompareNoCase(L
"e") == 0)
250 else if (command
.CompareNoCase(L
"d") == 0)
255 bool stdInMode
= parser
[NKey::kStdIn
].ThereIs
;
256 bool stdOutMode
= parser
[NKey::kStdOut
].ThereIs
;
258 CMyComPtr
<ISequentialInStream
> inStream
;
259 CInFileStream
*inStreamSpec
= 0;
262 inStream
= new CStdInFileStream
;
263 MY_SET_BINARY_MODE(stdin
);
267 if (paramIndex
>= nonSwitchStrings
.Size())
269 const UString
&inputName
= nonSwitchStrings
[paramIndex
++];
270 inStreamSpec
= new CInFileStream
;
271 inStream
= inStreamSpec
;
272 if (!inStreamSpec
->Open(GetSystemString(inputName
)))
274 fprintf(stderr
, "\nError: can not open input file %s\n",
275 (const char *)GetOemString(inputName
));
280 CMyComPtr
<ISequentialOutStream
> outStream
;
281 COutFileStream
*outStreamSpec
= NULL
;
284 outStream
= new CStdOutFileStream
;
285 MY_SET_BINARY_MODE(stdout
);
289 if (paramIndex
>= nonSwitchStrings
.Size())
291 const UString
&outputName
= nonSwitchStrings
[paramIndex
++];
292 outStreamSpec
= new COutFileStream
;
293 outStream
= outStreamSpec
;
294 if (!outStreamSpec
->Create(GetSystemString(outputName
), true))
296 fprintf(stderr
, "\nError: can not open output file %s\n",
297 (const char *)GetOemString(outputName
));
302 if (parser
[NKey::kFilter86
].ThereIs
)
304 // -f86 switch is for x86 filtered mode: BCJ + LZMA.
305 if (parser
[NKey::kEOS
].ThereIs
|| stdInMode
)
306 throw "Can not use stdin in this mode";
308 inStreamSpec
->File
.GetLength(fileSize
);
309 if (fileSize
> 0xF0000000)
310 throw "File is too big";
311 UInt32 inSize
= (UInt32
)fileSize
;
315 inBuffer
= (Byte
*)MyAlloc((size_t)inSize
);
320 UInt32 processedSize
;
321 if (ReadStream(inStream
, inBuffer
, (UInt32
)inSize
, &processedSize
) != S_OK
)
322 throw "Can not read";
323 if ((UInt32
)inSize
!= processedSize
)
324 throw "Read size error";
327 size_t outSizeProcessed
;
330 // we allocate 105% of original size for output buffer
331 size_t outSize
= (size_t)fileSize
/ 20 * 21 + (1 << 16);
334 outBuffer
= (Byte
*)MyAlloc((size_t)outSize
);
338 if (!dictionaryIsDefined
)
339 dictionary
= 1 << 23;
340 int res
= LzmaRamEncode(inBuffer
, inSize
, outBuffer
, outSize
, &outSizeProcessed
,
341 dictionary
, parser
[NKey::kFilter86
].PostCharIndex
== 0 ? SZ_FILTER_YES
: SZ_FILTER_AUTO
);
344 fprintf(stderr
, "\nEncoder error = %d\n", (int)res
);
351 if (LzmaRamGetUncompressedSize(inBuffer
, inSize
, &outSize
) != 0)
355 outBuffer
= (Byte
*)MyAlloc(outSize
);
359 int res
= LzmaRamDecompress(inBuffer
, inSize
, outBuffer
, outSize
, &outSizeProcessed
, malloc
, free
);
361 throw "LzmaDecoder error";
363 if (WriteStream(outStream
, outBuffer
, (UInt32
)outSizeProcessed
, &processedSize
) != S_OK
)
374 NCompress::NLZMA::CEncoder
*encoderSpec
= new NCompress::NLZMA::CEncoder
;
375 CMyComPtr
<ICompressCoder
> encoder
= encoderSpec
;
377 if (!dictionaryIsDefined
)
378 dictionary
= 1 << 23;
380 UInt32 posStateBits
= 2;
381 UInt32 litContextBits
= 3; // for normal files
382 // UInt32 litContextBits = 0; // for 32-bit data
383 UInt32 litPosBits
= 0;
384 // UInt32 litPosBits = 2; // for 32-bit data
385 UInt32 algorithm
= 1;
386 UInt32 numFastBytes
= 128;
387 UInt32 matchFinderCycles
= 16 + numFastBytes
/ 2;
388 bool matchFinderCyclesDefined
= false;
390 bool eos
= parser
[NKey::kEOS
].ThereIs
|| stdInMode
;
392 if(parser
[NKey::kMode
].ThereIs
)
393 if (!GetNumber(parser
[NKey::kMode
].PostStrings
[0], algorithm
))
396 if(parser
[NKey::kFastBytes
].ThereIs
)
397 if (!GetNumber(parser
[NKey::kFastBytes
].PostStrings
[0], numFastBytes
))
399 matchFinderCyclesDefined
= parser
[NKey::kMatchFinderCycles
].ThereIs
;
400 if (matchFinderCyclesDefined
)
401 if (!GetNumber(parser
[NKey::kMatchFinderCycles
].PostStrings
[0], matchFinderCycles
))
403 if(parser
[NKey::kLitContext
].ThereIs
)
404 if (!GetNumber(parser
[NKey::kLitContext
].PostStrings
[0], litContextBits
))
406 if(parser
[NKey::kLitPos
].ThereIs
)
407 if (!GetNumber(parser
[NKey::kLitPos
].PostStrings
[0], litPosBits
))
409 if(parser
[NKey::kPosBits
].ThereIs
)
410 if (!GetNumber(parser
[NKey::kPosBits
].PostStrings
[0], posStateBits
))
415 NCoderPropID::kDictionarySize
,
416 NCoderPropID::kPosStateBits
,
417 NCoderPropID::kLitContextBits
,
418 NCoderPropID::kLitPosBits
,
419 NCoderPropID::kAlgorithm
,
420 NCoderPropID::kNumFastBytes
,
421 NCoderPropID::kMatchFinder
,
422 NCoderPropID::kEndMarker
,
423 NCoderPropID::kNumThreads
,
424 NCoderPropID::kMatchFinderCycles
,
426 const int kNumPropsMax
= sizeof(propIDs
) / sizeof(propIDs
[0]);
428 PROPVARIANT properties
[kNumPropsMax
];
429 for (int p
= 0; p
< 6; p
++)
430 properties
[p
].vt
= VT_UI4
;
432 properties
[0].ulVal
= (UInt32
)dictionary
;
433 properties
[1].ulVal
= (UInt32
)posStateBits
;
434 properties
[2].ulVal
= (UInt32
)litContextBits
;
435 properties
[3].ulVal
= (UInt32
)litPosBits
;
436 properties
[4].ulVal
= (UInt32
)algorithm
;
437 properties
[5].ulVal
= (UInt32
)numFastBytes
;
439 properties
[6].vt
= VT_BSTR
;
440 properties
[6].bstrVal
= (BSTR
)(const wchar_t *)mf
;
442 properties
[7].vt
= VT_BOOL
;
443 properties
[7].boolVal
= eos
? VARIANT_TRUE
: VARIANT_FALSE
;
445 properties
[8].vt
= VT_UI4
;
446 properties
[8].ulVal
= (UInt32
)numThreads
;
448 // it must be last in property list
449 properties
[9].vt
= VT_UI4
;
450 properties
[9].ulVal
= (UInt32
)matchFinderCycles
;
452 int numProps
= kNumPropsMax
;
453 if (!matchFinderCyclesDefined
)
456 if (encoderSpec
->SetCoderProperties(propIDs
, properties
, numProps
) != S_OK
)
458 encoderSpec
->WriteCoderProperties(outStream
);
460 if (eos
|| stdInMode
)
461 fileSize
= (UInt64
)(Int64
)-1;
463 inStreamSpec
->File
.GetLength(fileSize
);
465 for (int i
= 0; i
< 8; i
++)
467 Byte b
= Byte(fileSize
>> (8 * i
));
468 if (outStream
->Write(&b
, 1, 0) != S_OK
)
470 fprintf(stderr
, kWriteError
);
474 HRESULT result
= encoder
->Code(inStream
, outStream
, 0, 0, 0);
475 if (result
== E_OUTOFMEMORY
)
477 fprintf(stderr
, "\nError: Can not allocate memory\n");
480 else if (result
!= S_OK
)
482 fprintf(stderr
, "\nEncoder error = %X\n", (unsigned int)result
);
488 NCompress::NLZMA::CDecoder
*decoderSpec
= new NCompress::NLZMA::CDecoder
;
489 CMyComPtr
<ICompressCoder
> decoder
= decoderSpec
;
490 const UInt32 kPropertiesSize
= 5;
491 Byte properties
[kPropertiesSize
];
492 UInt32 processedSize
;
493 if (ReadStream(inStream
, properties
, kPropertiesSize
, &processedSize
) != S_OK
)
495 fprintf(stderr
, kReadError
);
498 if (processedSize
!= kPropertiesSize
)
500 fprintf(stderr
, kReadError
);
503 if (decoderSpec
->SetDecoderProperties2(properties
, kPropertiesSize
) != S_OK
)
505 fprintf(stderr
, "SetDecoderProperties error");
509 for (int i
= 0; i
< 8; i
++)
512 if (inStream
->Read(&b
, 1, &processedSize
) != S_OK
)
514 fprintf(stderr
, kReadError
);
517 if (processedSize
!= 1)
519 fprintf(stderr
, kReadError
);
522 fileSize
|= ((UInt64
)b
) << (8 * i
);
524 if (decoder
->Code(inStream
, outStream
, 0, &fileSize
, 0) != S_OK
)
526 fprintf(stderr
, "Decoder error");
530 if (outStreamSpec
!= NULL
)
532 if (outStreamSpec
->Close() != S_OK
)
534 fprintf(stderr
, "File closing error");
541 int main(int n
, const char *args
[])
543 try { return main2(n
, args
); }
546 fprintf(stderr
, "\nError: %s\n", s
);
551 fprintf(stderr
, "\nError\n");