• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/lzma/CPP/7zip/Compress/LZMA_Alone/
1// LzmaAlone.cpp
2
3#include "StdAfx.h"
4
5#include "../../../Common/MyWindows.h"
6#include "../../../Common/MyInitGuid.h"
7
8#include <stdio.h>
9
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
17
18#include "../../../Common/CommandLineParser.h"
19#include "../../../Common/StringConvert.h"
20#include "../../../Common/StringToInt.h"
21
22#include "../../Common/FileStreams.h"
23#include "../../Common/StreamUtils.h"
24
25#include "../LZMA/LZMADecoder.h"
26#include "../LZMA/LZMAEncoder.h"
27
28#include "LzmaBenchCon.h"
29#include "LzmaRam.h"
30
31#ifdef COMPRESS_MF_MT
32#include "../../../Windows/System.h"
33#endif
34
35#include "../../MyVersion.h"
36
37extern "C"
38{
39#include "LzmaRamDecode.h"
40}
41
42using namespace NCommandLineParser;
43
44#ifdef _WIN32
45bool g_IsNT = false;
46static inline bool IsItWindowsNT()
47{
48  OSVERSIONINFO versionInfo;
49  versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
50  if (!::GetVersionEx(&versionInfo))
51    return false;
52  return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
53}
54#endif
55
56static const char *kCantAllocate = "Can not allocate memory";
57static const char *kReadError = "Read error";
58static const char *kWriteError = "Write error";
59
60namespace NKey {
61enum Enum
62{
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
78};
79}
80
81static const CSwitchForm kSwitchForms[] =
82{
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"+" }
98};
99
100static const int kNumSwitches = sizeof(kSwitchForms) / sizeof(kSwitchForms[0]);
101
102static void PrintHelp()
103{
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"
121    );
122}
123
124static void PrintHelpAndExit(const char *s)
125{
126  fprintf(stderr, "\nError: %s\n\n", s);
127  PrintHelp();
128  throw -1;
129}
130
131static void IncorrectCommand()
132{
133  PrintHelpAndExit("Incorrect command");
134}
135
136static void WriteArgumentsToStringList(int numArguments, const char *arguments[],
137    UStringVector &strings)
138{
139  for(int i = 1; i < numArguments; i++)
140    strings.Add(MultiByteToUnicodeString(arguments[i]));
141}
142
143static bool GetNumber(const wchar_t *s, UInt32 &value)
144{
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;
156}
157
158int main2(int n, const char *args[])
159{
160  #ifdef _WIN32
161  g_IsNT = IsItWindowsNT();
162  #endif
163
164  fprintf(stderr, "\nLZMA " MY_VERSION_COPYRIGHT_DATE "\n");
165
166  if (n == 1)
167  {
168    PrintHelp();
169    return 0;
170  }
171
172  bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4);
173  if (unsupportedTypes)
174  {
175    fprintf(stderr, "Unsupported base types. Edit Common/Types.h and recompile");
176    return 1;
177  }
178
179  UStringVector commandStrings;
180  WriteArgumentsToStringList(n, args, commandStrings);
181  CParser parser(kNumSwitches);
182  try
183  {
184    parser.ParseStrings(kSwitchForms, commandStrings);
185  }
186  catch(...)
187  {
188    IncorrectCommand();
189  }
190
191  if(parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
192  {
193    PrintHelp();
194    return 0;
195  }
196  const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
197
198  int paramIndex = 0;
199  if (paramIndex >= nonSwitchStrings.Size())
200    IncorrectCommand();
201  const UString &command = nonSwitchStrings[paramIndex++];
202
203  bool dictionaryIsDefined = false;
204  UInt32 dictionary = (UInt32)-1;
205  if(parser[NKey::kDictionary].ThereIs)
206  {
207    UInt32 dicLog;
208    if (!GetNumber(parser[NKey::kDictionary].PostStrings[0], dicLog))
209      IncorrectCommand();
210    dictionary = 1 << dicLog;
211    dictionaryIsDefined = true;
212  }
213  UString mf = L"BT4";
214  if (parser[NKey::kMatchFinder].ThereIs)
215    mf = parser[NKey::kMatchFinder].PostStrings[0];
216
217  UInt32 numThreads = (UInt32)-1;
218
219  #ifdef COMPRESS_MF_MT
220  if (parser[NKey::kMultiThread].ThereIs)
221  {
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();
229  }
230  #endif
231
232  if (command.CompareNoCase(L"b") == 0)
233  {
234    const UInt32 kNumDefaultItereations = 1;
235    UInt32 numIterations = kNumDefaultItereations;
236    {
237      if (paramIndex < nonSwitchStrings.Size())
238        if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations))
239          numIterations = kNumDefaultItereations;
240    }
241    return LzmaBenchCon(stderr, numIterations, numThreads, dictionary);
242  }
243
244  if (numThreads == (UInt32)-1)
245    numThreads = 1;
246
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();
254
255  bool stdInMode = parser[NKey::kStdIn].ThereIs;
256  bool stdOutMode = parser[NKey::kStdOut].ThereIs;
257
258  CMyComPtr<ISequentialInStream> inStream;
259  CInFileStream *inStreamSpec = 0;
260  if (stdInMode)
261  {
262    inStream = new CStdInFileStream;
263    MY_SET_BINARY_MODE(stdin);
264  }
265  else
266  {
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)))
273    {
274      fprintf(stderr, "\nError: can not open input file %s\n",
275          (const char *)GetOemString(inputName));
276      return 1;
277    }
278  }
279
280  CMyComPtr<ISequentialOutStream> outStream;
281  COutFileStream *outStreamSpec = NULL;
282  if (stdOutMode)
283  {
284    outStream = new CStdOutFileStream;
285    MY_SET_BINARY_MODE(stdout);
286  }
287  else
288  {
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))
295    {
296      fprintf(stderr, "\nError: can not open output file %s\n",
297        (const char *)GetOemString(outputName));
298      return 1;
299    }
300  }
301
302  if (parser[NKey::kFilter86].ThereIs)
303  {
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)
314    {
315      inBuffer = (Byte *)MyAlloc((size_t)inSize);
316      if (inBuffer == 0)
317        throw kCantAllocate;
318    }
319
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";
325
326    Byte *outBuffer = 0;
327    size_t outSizeProcessed;
328    if (encodeMode)
329    {
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)
333      {
334        outBuffer = (Byte *)MyAlloc((size_t)outSize);
335        if (outBuffer == 0)
336          throw kCantAllocate;
337      }
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)
343      {
344        fprintf(stderr, "\nEncoder error = %d\n", (int)res);
345        return 1;
346      }
347    }
348    else
349    {
350      size_t outSize;
351      if (LzmaRamGetUncompressedSize(inBuffer, inSize, &outSize) != 0)
352        throw "data error";
353      if (outSize != 0)
354      {
355        outBuffer = (Byte *)MyAlloc(outSize);
356        if (outBuffer == 0)
357          throw kCantAllocate;
358      }
359      int res = LzmaRamDecompress(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, malloc, free);
360      if (res != 0)
361        throw "LzmaDecoder error";
362    }
363    if (WriteStream(outStream, outBuffer, (UInt32)outSizeProcessed, &processedSize) != S_OK)
364      throw kWriteError;
365    MyFree(outBuffer);
366    MyFree(inBuffer);
367    return 0;
368  }
369
370
371  UInt64 fileSize;
372  if (encodeMode)
373  {
374    NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder;
375    CMyComPtr<ICompressCoder> encoder = encoderSpec;
376
377    if (!dictionaryIsDefined)
378      dictionary = 1 << 23;
379
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;
389
390    bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
391
392    if(parser[NKey::kMode].ThereIs)
393      if (!GetNumber(parser[NKey::kMode].PostStrings[0], algorithm))
394        IncorrectCommand();
395
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();
412
413    PROPID propIDs[] =
414    {
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,
425    };
426    const int kNumPropsMax = sizeof(propIDs) / sizeof(propIDs[0]);
427
428    PROPVARIANT properties[kNumPropsMax];
429    for (int p = 0; p < 6; p++)
430      properties[p].vt = VT_UI4;
431
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;
438
439    properties[6].vt = VT_BSTR;
440    properties[6].bstrVal = (BSTR)(const wchar_t *)mf;
441
442    properties[7].vt = VT_BOOL;
443    properties[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;
444
445    properties[8].vt = VT_UI4;
446    properties[8].ulVal = (UInt32)numThreads;
447
448    // it must be last in property list
449    properties[9].vt = VT_UI4;
450    properties[9].ulVal = (UInt32)matchFinderCycles;
451
452    int numProps = kNumPropsMax;
453    if (!matchFinderCyclesDefined)
454      numProps--;
455
456    if (encoderSpec->SetCoderProperties(propIDs, properties, numProps) != S_OK)
457      IncorrectCommand();
458    encoderSpec->WriteCoderProperties(outStream);
459
460    if (eos || stdInMode)
461      fileSize = (UInt64)(Int64)-1;
462    else
463      inStreamSpec->File.GetLength(fileSize);
464
465    for (int i = 0; i < 8; i++)
466    {
467      Byte b = Byte(fileSize >> (8 * i));
468      if (outStream->Write(&b, 1, 0) != S_OK)
469      {
470        fprintf(stderr, kWriteError);
471        return 1;
472      }
473    }
474    HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
475    if (result == E_OUTOFMEMORY)
476    {
477      fprintf(stderr, "\nError: Can not allocate memory\n");
478      return 1;
479    }
480    else if (result != S_OK)
481    {
482      fprintf(stderr, "\nEncoder error = %X\n", (unsigned int)result);
483      return 1;
484    }
485  }
486  else
487  {
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)
494    {
495      fprintf(stderr, kReadError);
496      return 1;
497    }
498    if (processedSize != kPropertiesSize)
499    {
500      fprintf(stderr, kReadError);
501      return 1;
502    }
503    if (decoderSpec->SetDecoderProperties2(properties, kPropertiesSize) != S_OK)
504    {
505      fprintf(stderr, "SetDecoderProperties error");
506      return 1;
507    }
508    fileSize = 0;
509    for (int i = 0; i < 8; i++)
510    {
511      Byte b;
512      if (inStream->Read(&b, 1, &processedSize) != S_OK)
513      {
514        fprintf(stderr, kReadError);
515        return 1;
516      }
517      if (processedSize != 1)
518      {
519        fprintf(stderr, kReadError);
520        return 1;
521      }
522      fileSize |= ((UInt64)b) << (8 * i);
523    }
524    if (decoder->Code(inStream, outStream, 0, &fileSize, 0) != S_OK)
525    {
526      fprintf(stderr, "Decoder error");
527      return 1;
528    }
529  }
530  if (outStreamSpec != NULL)
531  {
532    if (outStreamSpec->Close() != S_OK)
533    {
534      fprintf(stderr, "File closing error");
535      return 1;
536    }
537  }
538  return 0;
539}
540
541int main(int n, const char *args[])
542{
543  try { return main2(n, args); }
544  catch(const char *s)
545  {
546    fprintf(stderr, "\nError: %s\n", s);
547    return 1;
548  }
549  catch(...)
550  {
551    fprintf(stderr, "\nError\n");
552    return 1;
553  }
554}
555