Upload 2.0.2
[physicsfs] / lzma / CPP / 7zip / Archive / Common / HandlerOut.cpp
1 // HandlerOutCommon.cpp
2
3 #include "StdAfx.h"
4
5 #include "HandlerOut.h"
6 #include "../../../Windows/PropVariant.h"
7 #include "../../../Common/StringToInt.h"
8 #include "../../ICoder.h"
9 #include "../Common/ParseProperties.h"
10
11 #ifdef COMPRESS_MT
12 #include "../../../Windows/System.h"
13 #endif
14
15 using namespace NWindows;
16
17 namespace NArchive {
18
19 static const wchar_t *kCopyMethod = L"Copy";
20 static const wchar_t *kLZMAMethodName = L"LZMA";
21 static const wchar_t *kLZMA2MethodName = L"LZMA2";
22 static const wchar_t *kBZip2MethodName = L"BZip2";
23 static const wchar_t *kPpmdMethodName = L"PPMd";
24 static const wchar_t *kDeflateMethodName = L"Deflate";
25 static const wchar_t *kDeflate64MethodName = L"Deflate64";
26
27 static const wchar_t *kLzmaMatchFinderX1 = L"HC4";
28 static const wchar_t *kLzmaMatchFinderX5 = L"BT4";
29
30 static const UInt32 kLzmaAlgoX1 = 0;
31 static const UInt32 kLzmaAlgoX5 = 1;
32
33 static const UInt32 kLzmaDicSizeX1 = 1 << 16;
34 static const UInt32 kLzmaDicSizeX3 = 1 << 20;
35 static const UInt32 kLzmaDicSizeX5 = 1 << 24;
36 static const UInt32 kLzmaDicSizeX7 = 1 << 25;
37 static const UInt32 kLzmaDicSizeX9 = 1 << 26;
38
39 static const UInt32 kLzmaFastBytesX1 = 32;
40 static const UInt32 kLzmaFastBytesX7 = 64;
41
42 static const UInt32 kPpmdMemSizeX1 = (1 << 22);
43 static const UInt32 kPpmdMemSizeX5 = (1 << 24);
44 static const UInt32 kPpmdMemSizeX7 = (1 << 26);
45 static const UInt32 kPpmdMemSizeX9 = (192 << 20);
46
47 static const UInt32 kPpmdOrderX1 = 4;
48 static const UInt32 kPpmdOrderX5 = 6;
49 static const UInt32 kPpmdOrderX7 = 16;
50 static const UInt32 kPpmdOrderX9 = 32;
51
52 static const UInt32 kDeflateAlgoX1 = 0;
53 static const UInt32 kDeflateAlgoX5 = 1;
54
55 static const UInt32 kDeflateFastBytesX1 = 32;
56 static const UInt32 kDeflateFastBytesX7 = 64;
57 static const UInt32 kDeflateFastBytesX9 = 128;
58
59 static const UInt32 kDeflatePassesX1 = 1;
60 static const UInt32 kDeflatePassesX7 = 3;
61 static const UInt32 kDeflatePassesX9 = 10;
62
63 static const UInt32 kBZip2NumPassesX1 = 1;
64 static const UInt32 kBZip2NumPassesX7 = 2;
65 static const UInt32 kBZip2NumPassesX9 = 7;
66
67 static const UInt32 kBZip2DicSizeX1 = 100000;
68 static const UInt32 kBZip2DicSizeX3 = 500000;
69 static const UInt32 kBZip2DicSizeX5 = 900000;
70
71 static const wchar_t *kDefaultMethodName = kLZMAMethodName;
72
73 static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2";
74 static const UInt32 kDictionaryForHeaders = 1 << 20;
75 static const UInt32 kNumFastBytesForHeaders = 273;
76 static const UInt32 kAlgorithmForHeaders = kLzmaAlgoX5;
77
78 static bool AreEqual(const UString &methodName, const wchar_t *s)
79   { return (methodName.CompareNoCase(s) == 0); }
80
81 static inline bool IsLZMAMethod(const UString &methodName)
82
83   return 
84     AreEqual(methodName, kLZMAMethodName) || 
85     AreEqual(methodName, kLZMA2MethodName); 
86 }
87
88 static inline bool IsBZip2Method(const UString &methodName)
89   { return AreEqual(methodName, kBZip2MethodName); }
90
91 static inline bool IsPpmdMethod(const UString &methodName)
92   { return AreEqual(methodName, kPpmdMethodName); }
93
94 static inline bool IsDeflateMethod(const UString &methodName)
95
96   return 
97     AreEqual(methodName, kDeflateMethodName) || 
98     AreEqual(methodName, kDeflate64MethodName); 
99 }
100
101 struct CNameToPropID
102 {
103   PROPID PropID;
104   VARTYPE VarType;
105   const wchar_t *Name;
106 };
107
108 CNameToPropID g_NameToPropID[] = 
109 {
110   { NCoderPropID::kOrder, VT_UI4, L"O" },
111   { NCoderPropID::kPosStateBits, VT_UI4, L"PB" },
112   { NCoderPropID::kLitContextBits, VT_UI4, L"LC" },
113   { NCoderPropID::kLitPosBits, VT_UI4, L"LP" },
114   { NCoderPropID::kEndMarker, VT_BOOL, L"eos" },
115
116   { NCoderPropID::kNumPasses, VT_UI4, L"Pass" },
117   { NCoderPropID::kNumFastBytes, VT_UI4, L"fb" },
118   { NCoderPropID::kMatchFinderCycles, VT_UI4, L"mc" },
119   { NCoderPropID::kAlgorithm, VT_UI4, L"a" },
120   { NCoderPropID::kMatchFinder, VT_BSTR, L"mf" },
121   { NCoderPropID::kNumThreads, VT_UI4, L"mt" }
122 };
123
124 static bool ConvertProperty(PROPVARIANT srcProp, VARTYPE varType, NCOM::CPropVariant &destProp)
125 {
126   if (varType == srcProp.vt)
127   {
128     destProp = srcProp;
129     return true;
130   }
131   if (varType == VT_UI1)
132   {
133     if (srcProp.vt == VT_UI4)
134     {
135       UInt32 value = srcProp.ulVal;
136       if (value > 0xFF)
137         return false;
138       destProp = (Byte)value;
139       return true;
140     }
141   }
142   else if (varType == VT_BOOL)
143   {
144     bool res;
145     if (SetBoolProperty(res, srcProp) != S_OK)
146       return false;
147     destProp = res;
148     return true;
149   }
150   return false;
151 }
152     
153 static int FindPropIdFromStringName(const UString &name)
154 {
155   for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++)
156     if (name.CompareNoCase(g_NameToPropID[i].Name) == 0)
157       return i;
158   return -1;
159 }
160
161 static void SetOneMethodProp(COneMethodInfo &oneMethodInfo, PROPID propID, 
162     const NWindows::NCOM::CPropVariant &value)
163 {
164   for (int j = 0; j < oneMethodInfo.Properties.Size(); j++)
165     if (oneMethodInfo.Properties[j].Id == propID)
166       return;
167   CProp property;
168   property.Id = propID;
169   property.Value = value;
170   oneMethodInfo.Properties.Add(property);
171 }
172
173 void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo
174     #ifdef COMPRESS_MT
175     , UInt32 numThreads
176     #endif
177     )
178 {
179   UInt32 level = _level;
180   if (oneMethodInfo.MethodName.IsEmpty())
181     oneMethodInfo.MethodName = kDefaultMethodName;
182   
183   if (IsLZMAMethod(oneMethodInfo.MethodName))
184   {
185     UInt32 dicSize = 
186       (level >= 9 ? kLzmaDicSizeX9 : 
187       (level >= 7 ? kLzmaDicSizeX7 : 
188       (level >= 5 ? kLzmaDicSizeX5 : 
189       (level >= 3 ? kLzmaDicSizeX3 : 
190                     kLzmaDicSizeX1)))); 
191     
192     UInt32 algo = 
193       (level >= 5 ? kLzmaAlgoX5 : 
194                     kLzmaAlgoX1); 
195     
196     UInt32 fastBytes = 
197       (level >= 7 ? kLzmaFastBytesX7 : 
198                     kLzmaFastBytesX1); 
199     
200     const wchar_t *matchFinder = 
201       (level >= 5 ? kLzmaMatchFinderX5 : 
202                     kLzmaMatchFinderX1); 
203     
204     SetOneMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
205     SetOneMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
206     SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
207     SetOneMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder);
208     #ifdef COMPRESS_MT
209     SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
210     #endif
211   }
212   else if (IsDeflateMethod(oneMethodInfo.MethodName))
213   {
214     UInt32 fastBytes = 
215       (level >= 9 ? kDeflateFastBytesX9 : 
216       (level >= 7 ? kDeflateFastBytesX7 : 
217                     kDeflateFastBytesX1));
218     
219     UInt32 numPasses = 
220       (level >= 9 ? kDeflatePassesX9 :  
221       (level >= 7 ? kDeflatePassesX7 : 
222                     kDeflatePassesX1));
223     
224     UInt32 algo = 
225       (level >= 5 ? kDeflateAlgoX5 : 
226                     kDeflateAlgoX1); 
227     
228     SetOneMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
229     SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
230     SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
231   }
232   else if (IsBZip2Method(oneMethodInfo.MethodName))
233   {
234     UInt32 numPasses = 
235       (level >= 9 ? kBZip2NumPassesX9 : 
236       (level >= 7 ? kBZip2NumPassesX7 :  
237                     kBZip2NumPassesX1));
238     
239     UInt32 dicSize = 
240       (level >= 5 ? kBZip2DicSizeX5 : 
241       (level >= 3 ? kBZip2DicSizeX3 : 
242                     kBZip2DicSizeX1));
243     
244     SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
245     SetOneMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
246     #ifdef COMPRESS_MT
247     SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
248     #endif
249   }
250   else if (IsPpmdMethod(oneMethodInfo.MethodName))
251   {
252     UInt32 useMemSize = 
253       (level >= 9 ? kPpmdMemSizeX9 : 
254       (level >= 7 ? kPpmdMemSizeX7 : 
255       (level >= 5 ? kPpmdMemSizeX5 : 
256                     kPpmdMemSizeX1)));
257     
258     UInt32 order = 
259       (level >= 9 ? kPpmdOrderX9 : 
260       (level >= 7 ? kPpmdOrderX7 : 
261       (level >= 5 ? kPpmdOrderX5 : 
262                     kPpmdOrderX1)));
263     
264     SetOneMethodProp(oneMethodInfo, NCoderPropID::kUsedMemorySize, useMemSize);
265     SetOneMethodProp(oneMethodInfo, NCoderPropID::kOrder, order);
266   }
267 }
268
269 static void SplitParams(const UString &srcString, UStringVector &subStrings)
270 {
271   subStrings.Clear();
272   UString name;
273   int len = srcString.Length();
274   if (len == 0)
275     return;
276   for (int i = 0; i < len; i++)
277   {
278     wchar_t c = srcString[i];
279     if (c == L':')
280     {
281       subStrings.Add(name);
282       name.Empty();
283     }
284     else
285       name += c;
286   }
287   subStrings.Add(name);
288 }
289
290 static void SplitParam(const UString &param, UString &name, UString &value)
291 {
292   int eqPos = param.Find(L'=');
293   if (eqPos >= 0)
294   {
295     name = param.Left(eqPos);
296     value = param.Mid(eqPos + 1);
297     return;
298   }
299   for(int i = 0; i < param.Length(); i++)
300   {
301     wchar_t c = param[i];
302     if (c >= L'0' && c <= L'9')
303     {
304       name = param.Left(i);
305       value = param.Mid(i);
306       return;
307     }
308   }
309   name = param;
310 }
311
312 HRESULT COutHandler::SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value)
313 {
314   CProp property;
315   if (
316     name.CompareNoCase(L"D") == 0 || 
317     name.CompareNoCase(L"MEM") == 0)
318   {
319     UInt32 dicSize;
320     RINOK(ParsePropDictionaryValue(value, dicSize));
321     if (name.CompareNoCase(L"D") == 0)
322       property.Id = NCoderPropID::kDictionarySize;
323     else
324       property.Id = NCoderPropID::kUsedMemorySize;
325     property.Value = dicSize;
326     oneMethodInfo.Properties.Add(property);
327   }
328   else
329   {
330     int index = FindPropIdFromStringName(name);
331     if (index < 0)
332       return E_INVALIDARG;
333     
334     const CNameToPropID &nameToPropID = g_NameToPropID[index];
335     property.Id = nameToPropID.PropID;
336     
337     NCOM::CPropVariant propValue;
338     
339     if (nameToPropID.VarType == VT_BSTR)
340       propValue = value;
341     else if (nameToPropID.VarType == VT_BOOL)
342     {
343       bool res;
344       if (!StringToBool(value, res))
345         return E_INVALIDARG;
346       propValue = res;
347     }
348     else
349     {
350       UInt32 number;
351       if (ParseStringToUInt32(value, number) == value.Length())
352         propValue = number;
353       else
354         propValue = value;
355     }
356     
357     if (!ConvertProperty(propValue, nameToPropID.VarType, property.Value))
358       return E_INVALIDARG;
359     
360     oneMethodInfo.Properties.Add(property);
361   }
362   return S_OK;
363 }
364
365 HRESULT COutHandler::SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString)
366 {
367   UStringVector params;
368   SplitParams(srcString, params);
369   if (params.Size() > 0)
370     oneMethodInfo.MethodName = params[0];
371   for (int i = 1; i < params.Size(); i++)
372   {
373     const UString &param = params[i];
374     UString name, value;
375     SplitParam(param, name, value);
376     RINOK(SetParam(oneMethodInfo, name, value));
377   }
378   return S_OK;
379 }
380
381 HRESULT COutHandler::SetSolidSettings(const UString &s)
382 {
383   bool res;
384   if (StringToBool(s, res))
385   {
386     if (res)
387       InitSolid();
388     else
389       _numSolidFiles = 1;
390     return S_OK;
391   }
392   UString s2 = s;
393   s2.MakeUpper();
394   for (int i = 0; i < s2.Length();)
395   {
396     const wchar_t *start = ((const wchar_t *)s2) + i;
397     const wchar_t *end;
398     UInt64 v = ConvertStringToUInt64(start, &end);
399     if (start == end)
400     {
401       if (s2[i++] != 'E')
402         return E_INVALIDARG;
403       _solidExtension = true;
404       continue;
405     }
406     i += (int)(end - start);
407     if (i == s2.Length())
408       return E_INVALIDARG;
409     wchar_t c = s2[i++];
410     switch(c)
411     {
412       case 'F':
413         if (v < 1)
414           v = 1;
415         _numSolidFiles = v;
416         break;
417       case 'B':
418         _numSolidBytes = v;
419         _numSolidBytesDefined = true;
420         break;
421       case 'K':
422         _numSolidBytes = (v << 10);
423         _numSolidBytesDefined = true;
424         break;
425       case 'M':
426         _numSolidBytes = (v << 20);
427         _numSolidBytesDefined = true;
428         break;
429       case 'G':
430         _numSolidBytes = (v << 30);
431         _numSolidBytesDefined = true;
432         break;
433       default:
434         return E_INVALIDARG;
435     }
436   }
437   return S_OK;
438 }
439
440 HRESULT COutHandler::SetSolidSettings(const PROPVARIANT &value)
441 {
442   switch(value.vt)
443   {
444     case VT_EMPTY:
445       InitSolid();
446       return S_OK;
447     case VT_BSTR:
448       return SetSolidSettings(value.bstrVal);
449     default:
450       return E_INVALIDARG;
451   }
452 }
453
454 void COutHandler::Init()
455 {
456   _removeSfxBlock = false;
457   _compressHeaders = true;
458   _encryptHeaders = false;
459   
460   WriteModified = true;
461   WriteCreated = false;
462   WriteAccessed = false;
463   
464   #ifdef COMPRESS_MT
465   _numThreads = NWindows::NSystem::GetNumberOfProcessors();
466   #endif
467   
468   _level = 5;
469   _autoFilter = true;
470   _volumeMode = false;
471   _crcSize = 4;
472   InitSolid();
473 }
474
475 void COutHandler::BeforeSetProperty()
476 {
477   Init();
478   #ifdef COMPRESS_MT
479   numProcessors = NSystem::GetNumberOfProcessors();
480   #endif
481
482   mainDicSize = 0xFFFFFFFF;
483   mainDicMethodIndex = 0xFFFFFFFF;
484   minNumber = 0;
485   _crcSize = 4;
486 }
487
488 HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
489 {
490   UString name = nameSpec;
491   name.MakeUpper();
492   if (name.IsEmpty())
493     return E_INVALIDARG;
494   
495   if (name[0] == 'X')
496   {
497     name.Delete(0);
498     _level = 9;
499     return ParsePropValue(name, value, _level);
500   }
501   
502   if (name[0] == L'S')
503   {
504     name.Delete(0);
505     if (name.IsEmpty())
506       return SetSolidSettings(value);
507     if (value.vt != VT_EMPTY)
508       return E_INVALIDARG;
509     return SetSolidSettings(name);
510   }
511   
512   if (name == L"CRC")
513   {
514     _crcSize = 4;
515     name.Delete(0, 3);
516     return ParsePropValue(name, value, _crcSize);
517   }
518   
519   UInt32 number;
520   int index = ParseStringToUInt32(name, number);
521   UString realName = name.Mid(index);
522   if (index == 0)
523   {
524     if(name.Left(2).CompareNoCase(L"MT") == 0)
525     {
526       #ifdef COMPRESS_MT
527       RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
528       #endif
529       return S_OK;
530     }
531     if (name.CompareNoCase(L"RSFX") == 0)
532       return SetBoolProperty(_removeSfxBlock, value);
533     if (name.CompareNoCase(L"F") == 0)
534       return SetBoolProperty(_autoFilter, value);
535     if (name.CompareNoCase(L"HC") == 0)
536       return SetBoolProperty(_compressHeaders, value);
537     if (name.CompareNoCase(L"HCF") == 0)
538     {
539       bool compressHeadersFull = true;
540       RINOK(SetBoolProperty(compressHeadersFull, value));
541       if (!compressHeadersFull)
542         return E_INVALIDARG;
543       return S_OK;
544     }
545     if (name.CompareNoCase(L"HE") == 0)
546       return SetBoolProperty(_encryptHeaders, value);
547     if (name.CompareNoCase(L"TM") == 0)
548       return SetBoolProperty(WriteModified, value);
549     if (name.CompareNoCase(L"TC") == 0)
550       return SetBoolProperty(WriteCreated, value);
551     if (name.CompareNoCase(L"TA") == 0)
552       return SetBoolProperty(WriteAccessed, value);
553     if (name.CompareNoCase(L"V") == 0)
554       return SetBoolProperty(_volumeMode, value);
555     number = 0;
556   }
557   if (number > 10000)
558     return E_FAIL;
559   if (number < minNumber)
560     return E_INVALIDARG;
561   number -= minNumber;
562   for(int j = _methods.Size(); j <= (int)number; j++)
563   {
564     COneMethodInfo oneMethodInfo;
565     _methods.Add(oneMethodInfo);
566   }
567   
568   COneMethodInfo &oneMethodInfo = _methods[number];
569   
570   if (realName.Length() == 0)
571   {
572     if (value.vt != VT_BSTR)
573       return E_INVALIDARG;
574     
575     RINOK(SetParams(oneMethodInfo, value.bstrVal));
576   }
577   else
578   {
579     CProp property;
580     if (realName.Left(1).CompareNoCase(L"D") == 0)
581     {
582       UInt32 dicSize;
583       RINOK(ParsePropDictionaryValue(realName.Mid(1), value, dicSize));
584       property.Id = NCoderPropID::kDictionarySize;
585       property.Value = dicSize;
586       oneMethodInfo.Properties.Add(property);
587       if (number <= mainDicMethodIndex)
588         mainDicSize = dicSize;
589     }
590     else if (realName.Left(3).CompareNoCase(L"MEM") == 0)
591     {
592       UInt32 dicSize;
593       RINOK(ParsePropDictionaryValue(realName.Mid(3), value, dicSize));
594       property.Id = NCoderPropID::kUsedMemorySize;
595       property.Value = dicSize;
596       oneMethodInfo.Properties.Add(property);
597       if (number <= mainDicMethodIndex)
598         mainDicSize = dicSize;
599     }
600     else
601     {
602       int index = FindPropIdFromStringName(realName);
603       if (index < 0)
604         return E_INVALIDARG;
605       
606       const CNameToPropID &nameToPropID = g_NameToPropID[index];
607       property.Id = nameToPropID.PropID;
608       
609       if (!ConvertProperty(value, nameToPropID.VarType, property.Value))
610         return E_INVALIDARG;
611       
612       oneMethodInfo.Properties.Add(property);
613     }
614   }
615   return S_OK;
616 }  
617
618 }