K2.6 patches and update.
[tomato.git] / release / src / lzma / CPP / 7zip / Compress / LZMA_Alone / LzmaAlone.cpp
blob6d50942bd9e3decec4d33c13db41abf02610ceb7
1 // LzmaAlone.cpp
3 #include "StdAfx.h"
5 #include "../../../Common/MyWindows.h"
6 #include "../../../Common/MyInitGuid.h"
8 #include <stdio.h>
10 #if defined(_WIN32) || defined(OS2) || defined(MSDOS)
11 #include <fcntl.h>
12 #include <io.h>
13 #define MY_SET_BINARY_MODE(file) _setmode(_fileno(file), O_BINARY)
14 #else
15 #define MY_SET_BINARY_MODE(file)
16 #endif
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"
29 #include "LzmaRam.h"
31 #ifdef COMPRESS_MF_MT
32 #include "../../../Windows/System.h"
33 #endif
35 #include "../../MyVersion.h"
37 extern "C"
39 #include "LzmaRamDecode.h"
42 using namespace NCommandLineParser;
44 #ifdef _WIN32
45 bool g_IsNT = false;
46 static inline bool IsItWindowsNT()
48 OSVERSIONINFO versionInfo;
49 versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
50 if (!::GetVersionEx(&versionInfo))
51 return false;
52 return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
54 #endif
56 static const char *kCantAllocate = "Can not allocate memory";
57 static const char *kReadError = "Read error";
58 static const char *kWriteError = "Write error";
60 namespace NKey {
61 enum Enum
63 kHelp1 = 0,
64 kHelp2,
65 kMode,
66 kDictionary,
67 kFastBytes,
68 kMatchFinderCycles,
69 kLitContext,
70 kLitPos,
71 kPosBits,
72 kMatchFinder,
73 kMultiThread,
74 kEOS,
75 kStdIn,
76 kStdOut,
77 kFilter86
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"
105 " e: encode file\n"
106 " d: decode file\n"
107 " b: Benchmark\n"
108 "<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);
127 PrintHelp();
128 throw -1;
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)
145 value = 0;
146 if (MyStringLen(s) == 0)
147 return false;
148 const wchar_t *end;
149 UInt64 res = ConvertStringToUInt64(s, &end);
150 if (*end != L'\0')
151 return false;
152 if (res > 0xFFFFFFFF)
153 return false;
154 value = UInt32(res);
155 return true;
158 int main2(int n, const char *args[])
160 #ifdef _WIN32
161 g_IsNT = IsItWindowsNT();
162 #endif
164 fprintf(stderr, "\nLZMA " MY_VERSION_COPYRIGHT_DATE "\n");
166 if (n == 1)
168 PrintHelp();
169 return 0;
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");
176 return 1;
179 UStringVector commandStrings;
180 WriteArgumentsToStringList(n, args, commandStrings);
181 CParser parser(kNumSwitches);
184 parser.ParseStrings(kSwitchForms, commandStrings);
186 catch(...)
188 IncorrectCommand();
191 if(parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
193 PrintHelp();
194 return 0;
196 const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
198 int paramIndex = 0;
199 if (paramIndex >= nonSwitchStrings.Size())
200 IncorrectCommand();
201 const UString &command = nonSwitchStrings[paramIndex++];
203 bool dictionaryIsDefined = false;
204 UInt32 dictionary = (UInt32)-1;
205 if(parser[NKey::kDictionary].ThereIs)
207 UInt32 dicLog;
208 if (!GetNumber(parser[NKey::kDictionary].PostStrings[0], dicLog))
209 IncorrectCommand();
210 dictionary = 1 << dicLog;
211 dictionaryIsDefined = true;
213 UString mf = L"BT4";
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];
224 if (s.IsEmpty())
225 numThreads = numCPUs;
226 else
227 if (!GetNumber(s, numThreads))
228 IncorrectCommand();
230 #endif
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)
245 numThreads = 1;
247 bool encodeMode = false;
248 if (command.CompareNoCase(L"e") == 0)
249 encodeMode = true;
250 else if (command.CompareNoCase(L"d") == 0)
251 encodeMode = false;
252 else
253 IncorrectCommand();
255 bool stdInMode = parser[NKey::kStdIn].ThereIs;
256 bool stdOutMode = parser[NKey::kStdOut].ThereIs;
258 CMyComPtr<ISequentialInStream> inStream;
259 CInFileStream *inStreamSpec = 0;
260 if (stdInMode)
262 inStream = new CStdInFileStream;
263 MY_SET_BINARY_MODE(stdin);
265 else
267 if (paramIndex >= nonSwitchStrings.Size())
268 IncorrectCommand();
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));
276 return 1;
280 CMyComPtr<ISequentialOutStream> outStream;
281 COutFileStream *outStreamSpec = NULL;
282 if (stdOutMode)
284 outStream = new CStdOutFileStream;
285 MY_SET_BINARY_MODE(stdout);
287 else
289 if (paramIndex >= nonSwitchStrings.Size())
290 IncorrectCommand();
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));
298 return 1;
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";
307 UInt64 fileSize;
308 inStreamSpec->File.GetLength(fileSize);
309 if (fileSize > 0xF0000000)
310 throw "File is too big";
311 UInt32 inSize = (UInt32)fileSize;
312 Byte *inBuffer = 0;
313 if (inSize != 0)
315 inBuffer = (Byte *)MyAlloc((size_t)inSize);
316 if (inBuffer == 0)
317 throw kCantAllocate;
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";
326 Byte *outBuffer = 0;
327 size_t outSizeProcessed;
328 if (encodeMode)
330 // we allocate 105% of original size for output buffer
331 size_t outSize = (size_t)fileSize / 20 * 21 + (1 << 16);
332 if (outSize != 0)
334 outBuffer = (Byte *)MyAlloc((size_t)outSize);
335 if (outBuffer == 0)
336 throw kCantAllocate;
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);
342 if (res != 0)
344 fprintf(stderr, "\nEncoder error = %d\n", (int)res);
345 return 1;
348 else
350 size_t outSize;
351 if (LzmaRamGetUncompressedSize(inBuffer, inSize, &outSize) != 0)
352 throw "data error";
353 if (outSize != 0)
355 outBuffer = (Byte *)MyAlloc(outSize);
356 if (outBuffer == 0)
357 throw kCantAllocate;
359 int res = LzmaRamDecompress(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, malloc, free);
360 if (res != 0)
361 throw "LzmaDecoder error";
363 if (WriteStream(outStream, outBuffer, (UInt32)outSizeProcessed, &processedSize) != S_OK)
364 throw kWriteError;
365 MyFree(outBuffer);
366 MyFree(inBuffer);
367 return 0;
371 UInt64 fileSize;
372 if (encodeMode)
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))
394 IncorrectCommand();
396 if(parser[NKey::kFastBytes].ThereIs)
397 if (!GetNumber(parser[NKey::kFastBytes].PostStrings[0], numFastBytes))
398 IncorrectCommand();
399 matchFinderCyclesDefined = parser[NKey::kMatchFinderCycles].ThereIs;
400 if (matchFinderCyclesDefined)
401 if (!GetNumber(parser[NKey::kMatchFinderCycles].PostStrings[0], matchFinderCycles))
402 IncorrectCommand();
403 if(parser[NKey::kLitContext].ThereIs)
404 if (!GetNumber(parser[NKey::kLitContext].PostStrings[0], litContextBits))
405 IncorrectCommand();
406 if(parser[NKey::kLitPos].ThereIs)
407 if (!GetNumber(parser[NKey::kLitPos].PostStrings[0], litPosBits))
408 IncorrectCommand();
409 if(parser[NKey::kPosBits].ThereIs)
410 if (!GetNumber(parser[NKey::kPosBits].PostStrings[0], posStateBits))
411 IncorrectCommand();
413 PROPID propIDs[] =
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)
454 numProps--;
456 if (encoderSpec->SetCoderProperties(propIDs, properties, numProps) != S_OK)
457 IncorrectCommand();
458 encoderSpec->WriteCoderProperties(outStream);
460 if (eos || stdInMode)
461 fileSize = (UInt64)(Int64)-1;
462 else
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);
471 return 1;
474 HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
475 if (result == E_OUTOFMEMORY)
477 fprintf(stderr, "\nError: Can not allocate memory\n");
478 return 1;
480 else if (result != S_OK)
482 fprintf(stderr, "\nEncoder error = %X\n", (unsigned int)result);
483 return 1;
486 else
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);
496 return 1;
498 if (processedSize != kPropertiesSize)
500 fprintf(stderr, kReadError);
501 return 1;
503 if (decoderSpec->SetDecoderProperties2(properties, kPropertiesSize) != S_OK)
505 fprintf(stderr, "SetDecoderProperties error");
506 return 1;
508 fileSize = 0;
509 for (int i = 0; i < 8; i++)
511 Byte b;
512 if (inStream->Read(&b, 1, &processedSize) != S_OK)
514 fprintf(stderr, kReadError);
515 return 1;
517 if (processedSize != 1)
519 fprintf(stderr, kReadError);
520 return 1;
522 fileSize |= ((UInt64)b) << (8 * i);
524 if (decoder->Code(inStream, outStream, 0, &fileSize, 0) != S_OK)
526 fprintf(stderr, "Decoder error");
527 return 1;
530 if (outStreamSpec != NULL)
532 if (outStreamSpec->Close() != S_OK)
534 fprintf(stderr, "File closing error");
535 return 1;
538 return 0;
541 int main(int n, const char *args[])
543 try { return main2(n, args); }
544 catch(const char *s)
546 fprintf(stderr, "\nError: %s\n", s);
547 return 1;
549 catch(...)
551 fprintf(stderr, "\nError\n");
552 return 1;