5 #include "../../../Common/StringToInt.h"
\r
7 #include "../../../Windows/PropVariant.h"
\r
10 #include "../../../Windows/System.h"
\r
13 #include "../../ICoder.h"
\r
15 #include "../Common/ParseProperties.h"
\r
17 #include "HandlerOut.h"
\r
19 using namespace NWindows;
\r
21 namespace NArchive {
\r
23 static const wchar_t *kCopyMethod = L"Copy";
\r
24 static const wchar_t *kLZMAMethodName = L"LZMA";
\r
25 static const wchar_t *kLZMA2MethodName = L"LZMA2";
\r
26 static const wchar_t *kBZip2MethodName = L"BZip2";
\r
27 static const wchar_t *kPpmdMethodName = L"PPMd";
\r
28 static const wchar_t *kDeflateMethodName = L"Deflate";
\r
29 static const wchar_t *kDeflate64MethodName = L"Deflate64";
\r
31 static const wchar_t *kLzmaMatchFinderX1 = L"HC4";
\r
32 static const wchar_t *kLzmaMatchFinderX5 = L"BT4";
\r
34 static const UInt32 kLzmaAlgoX1 = 0;
\r
35 static const UInt32 kLzmaAlgoX5 = 1;
\r
37 static const UInt32 kLzmaDicSizeX1 = 1 << 16;
\r
38 static const UInt32 kLzmaDicSizeX3 = 1 << 20;
\r
39 static const UInt32 kLzmaDicSizeX5 = 1 << 24;
\r
40 static const UInt32 kLzmaDicSizeX7 = 1 << 25;
\r
41 static const UInt32 kLzmaDicSizeX9 = 1 << 26;
\r
43 static const UInt32 kLzmaFastBytesX1 = 32;
\r
44 static const UInt32 kLzmaFastBytesX7 = 64;
\r
46 static const UInt32 kPpmdMemSizeX1 = (1 << 22);
\r
47 static const UInt32 kPpmdMemSizeX5 = (1 << 24);
\r
48 static const UInt32 kPpmdMemSizeX7 = (1 << 26);
\r
49 static const UInt32 kPpmdMemSizeX9 = (192 << 20);
\r
51 static const UInt32 kPpmdOrderX1 = 4;
\r
52 static const UInt32 kPpmdOrderX5 = 6;
\r
53 static const UInt32 kPpmdOrderX7 = 16;
\r
54 static const UInt32 kPpmdOrderX9 = 32;
\r
56 static const UInt32 kDeflateAlgoX1 = 0;
\r
57 static const UInt32 kDeflateAlgoX5 = 1;
\r
59 static const UInt32 kDeflateFastBytesX1 = 32;
\r
60 static const UInt32 kDeflateFastBytesX7 = 64;
\r
61 static const UInt32 kDeflateFastBytesX9 = 128;
\r
63 static const UInt32 kDeflatePassesX1 = 1;
\r
64 static const UInt32 kDeflatePassesX7 = 3;
\r
65 static const UInt32 kDeflatePassesX9 = 10;
\r
67 static const UInt32 kBZip2NumPassesX1 = 1;
\r
68 static const UInt32 kBZip2NumPassesX7 = 2;
\r
69 static const UInt32 kBZip2NumPassesX9 = 7;
\r
71 static const UInt32 kBZip2DicSizeX1 = 100000;
\r
72 static const UInt32 kBZip2DicSizeX3 = 500000;
\r
73 static const UInt32 kBZip2DicSizeX5 = 900000;
\r
75 static const wchar_t *kDefaultMethodName = kLZMAMethodName;
\r
77 static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2";
\r
78 static const UInt32 kDictionaryForHeaders = 1 << 20;
\r
79 static const UInt32 kNumFastBytesForHeaders = 273;
\r
80 static const UInt32 kAlgorithmForHeaders = kLzmaAlgoX5;
\r
82 static bool AreEqual(const UString &methodName, const wchar_t *s)
\r
83 { return (methodName.CompareNoCase(s) == 0); }
\r
85 bool COneMethodInfo::IsLzma() const
\r
88 AreEqual(MethodName, kLZMAMethodName) ||
\r
89 AreEqual(MethodName, kLZMA2MethodName);
\r
92 static inline bool IsBZip2Method(const UString &methodName)
\r
93 { return AreEqual(methodName, kBZip2MethodName); }
\r
95 static inline bool IsPpmdMethod(const UString &methodName)
\r
96 { return AreEqual(methodName, kPpmdMethodName); }
\r
98 static inline bool IsDeflateMethod(const UString &methodName)
\r
101 AreEqual(methodName, kDeflateMethodName) ||
\r
102 AreEqual(methodName, kDeflate64MethodName);
\r
105 struct CNameToPropID
\r
109 const wchar_t *Name;
\r
112 static CNameToPropID g_NameToPropID[] =
\r
114 { NCoderPropID::kBlockSize, VT_UI4, L"C" },
\r
115 { NCoderPropID::kDictionarySize, VT_UI4, L"D" },
\r
116 { NCoderPropID::kUsedMemorySize, VT_UI4, L"MEM" },
\r
118 { NCoderPropID::kOrder, VT_UI4, L"O" },
\r
119 { NCoderPropID::kPosStateBits, VT_UI4, L"PB" },
\r
120 { NCoderPropID::kLitContextBits, VT_UI4, L"LC" },
\r
121 { NCoderPropID::kLitPosBits, VT_UI4, L"LP" },
\r
122 { NCoderPropID::kEndMarker, VT_BOOL, L"eos" },
\r
124 { NCoderPropID::kNumPasses, VT_UI4, L"Pass" },
\r
125 { NCoderPropID::kNumFastBytes, VT_UI4, L"fb" },
\r
126 { NCoderPropID::kMatchFinderCycles, VT_UI4, L"mc" },
\r
127 { NCoderPropID::kAlgorithm, VT_UI4, L"a" },
\r
128 { NCoderPropID::kMatchFinder, VT_BSTR, L"mf" },
\r
129 { NCoderPropID::kNumThreads, VT_UI4, L"mt" },
\r
130 { NCoderPropID::kDefaultProp, VT_UI4, L"" }
\r
133 static bool ConvertProperty(PROPVARIANT srcProp, VARTYPE varType, NCOM::CPropVariant &destProp)
\r
135 if (varType == srcProp.vt)
\r
137 destProp = srcProp;
\r
140 if (varType == VT_UI1)
\r
142 if (srcProp.vt == VT_UI4)
\r
144 UInt32 value = srcProp.ulVal;
\r
147 destProp = (Byte)value;
\r
151 else if (varType == VT_BOOL)
\r
154 if (SetBoolProperty(res, srcProp) != S_OK)
\r
162 static int FindPropIdExact(const UString &name)
\r
164 for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++)
\r
165 if (name.CompareNoCase(g_NameToPropID[i].Name) == 0)
\r
170 static int FindPropIdStart(const UString &name)
\r
172 for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++)
\r
174 UString t = g_NameToPropID[i].Name;
\r
175 if (t.CompareNoCase(name.Left(t.Length())) == 0)
\r
181 static void SetMethodProp(COneMethodInfo &m, PROPID propID, const NCOM::CPropVariant &value)
\r
183 for (int j = 0; j < m.Props.Size(); j++)
\r
184 if (m.Props[j].Id == propID)
\r
188 prop.Value = value;
\r
192 void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo
\r
194 , UInt32 numThreads
\r
198 UInt32 level = _level;
\r
199 if (oneMethodInfo.MethodName.IsEmpty())
\r
200 oneMethodInfo.MethodName = kDefaultMethodName;
\r
202 if (oneMethodInfo.IsLzma())
\r
205 (level >= 9 ? kLzmaDicSizeX9 :
\r
206 (level >= 7 ? kLzmaDicSizeX7 :
\r
207 (level >= 5 ? kLzmaDicSizeX5 :
\r
208 (level >= 3 ? kLzmaDicSizeX3 :
\r
209 kLzmaDicSizeX1))));
\r
212 (level >= 5 ? kLzmaAlgoX5 :
\r
216 (level >= 7 ? kLzmaFastBytesX7 :
\r
219 const wchar_t *matchFinder =
\r
220 (level >= 5 ? kLzmaMatchFinderX5 :
\r
221 kLzmaMatchFinderX1);
\r
223 SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
\r
224 SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
\r
225 SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
\r
226 SetMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder);
\r
228 SetMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
\r
231 else if (IsDeflateMethod(oneMethodInfo.MethodName))
\r
234 (level >= 9 ? kDeflateFastBytesX9 :
\r
235 (level >= 7 ? kDeflateFastBytesX7 :
\r
236 kDeflateFastBytesX1));
\r
239 (level >= 9 ? kDeflatePassesX9 :
\r
240 (level >= 7 ? kDeflatePassesX7 :
\r
241 kDeflatePassesX1));
\r
244 (level >= 5 ? kDeflateAlgoX5 :
\r
247 SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
\r
248 SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
\r
249 SetMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
\r
251 else if (IsBZip2Method(oneMethodInfo.MethodName))
\r
254 (level >= 9 ? kBZip2NumPassesX9 :
\r
255 (level >= 7 ? kBZip2NumPassesX7 :
\r
256 kBZip2NumPassesX1));
\r
259 (level >= 5 ? kBZip2DicSizeX5 :
\r
260 (level >= 3 ? kBZip2DicSizeX3 :
\r
263 SetMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
\r
264 SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
\r
266 SetMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
\r
269 else if (IsPpmdMethod(oneMethodInfo.MethodName))
\r
271 UInt32 useMemSize =
\r
272 (level >= 9 ? kPpmdMemSizeX9 :
\r
273 (level >= 7 ? kPpmdMemSizeX7 :
\r
274 (level >= 5 ? kPpmdMemSizeX5 :
\r
278 (level >= 9 ? kPpmdOrderX9 :
\r
279 (level >= 7 ? kPpmdOrderX7 :
\r
280 (level >= 5 ? kPpmdOrderX5 :
\r
283 SetMethodProp(oneMethodInfo, NCoderPropID::kUsedMemorySize, useMemSize);
\r
284 SetMethodProp(oneMethodInfo, NCoderPropID::kOrder, order);
\r
288 static void SplitParams(const UString &srcString, UStringVector &subStrings)
\r
290 subStrings.Clear();
\r
292 int len = srcString.Length();
\r
295 for (int i = 0; i < len; i++)
\r
297 wchar_t c = srcString[i];
\r
300 subStrings.Add(name);
\r
306 subStrings.Add(name);
\r
309 static void SplitParam(const UString ¶m, UString &name, UString &value)
\r
311 int eqPos = param.Find(L'=');
\r
314 name = param.Left(eqPos);
\r
315 value = param.Mid(eqPos + 1);
\r
318 for(int i = 0; i < param.Length(); i++)
\r
320 wchar_t c = param[i];
\r
321 if (c >= L'0' && c <= L'9')
\r
323 name = param.Left(i);
\r
324 value = param.Mid(i);
\r
331 HRESULT COutHandler::SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value)
\r
334 int index = FindPropIdExact(name);
\r
336 return E_INVALIDARG;
\r
337 const CNameToPropID &nameToPropID = g_NameToPropID[index];
\r
338 prop.Id = nameToPropID.PropID;
\r
340 if (prop.Id == NCoderPropID::kBlockSize ||
\r
341 prop.Id == NCoderPropID::kDictionarySize ||
\r
342 prop.Id == NCoderPropID::kUsedMemorySize)
\r
345 RINOK(ParsePropDictionaryValue(value, dicSize));
\r
346 prop.Value = dicSize;
\r
350 NCOM::CPropVariant propValue;
\r
352 if (nameToPropID.VarType == VT_BSTR)
\r
354 else if (nameToPropID.VarType == VT_BOOL)
\r
357 if (!StringToBool(value, res))
\r
358 return E_INVALIDARG;
\r
364 if (ParseStringToUInt32(value, number) == value.Length())
\r
365 propValue = number;
\r
370 if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value))
\r
371 return E_INVALIDARG;
\r
373 oneMethodInfo.Props.Add(prop);
\r
377 HRESULT COutHandler::SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString)
\r
379 UStringVector params;
\r
380 SplitParams(srcString, params);
\r
381 if (params.Size() > 0)
\r
382 oneMethodInfo.MethodName = params[0];
\r
383 for (int i = 1; i < params.Size(); i++)
\r
385 const UString ¶m = params[i];
\r
386 UString name, value;
\r
387 SplitParam(param, name, value);
\r
388 RINOK(SetParam(oneMethodInfo, name, value));
\r
393 HRESULT COutHandler::SetSolidSettings(const UString &s)
\r
397 for (int i = 0; i < s2.Length();)
\r
399 const wchar_t *start = ((const wchar_t *)s2) + i;
\r
400 const wchar_t *end;
\r
401 UInt64 v = ConvertStringToUInt64(start, &end);
\r
404 if (s2[i++] != 'E')
\r
405 return E_INVALIDARG;
\r
406 _solidExtension = true;
\r
409 i += (int)(end - start);
\r
410 if (i == s2.Length())
\r
411 return E_INVALIDARG;
\r
412 wchar_t c = s2[i++];
\r
418 _numSolidFiles = v;
\r
421 _numSolidBytes = v;
\r
422 _numSolidBytesDefined = true;
\r
425 _numSolidBytes = (v << 10);
\r
426 _numSolidBytesDefined = true;
\r
429 _numSolidBytes = (v << 20);
\r
430 _numSolidBytesDefined = true;
\r
433 _numSolidBytes = (v << 30);
\r
434 _numSolidBytesDefined = true;
\r
437 return E_INVALIDARG;
\r
443 HRESULT COutHandler::SetSolidSettings(const PROPVARIANT &value)
\r
452 isSolid = (value.boolVal != VARIANT_FALSE);
\r
455 if (StringToBool(value.bstrVal, isSolid))
\r
457 return SetSolidSettings(value.bstrVal);
\r
459 return E_INVALIDARG;
\r
464 _numSolidFiles = 1;
\r
468 void COutHandler::Init()
\r
470 _removeSfxBlock = false;
\r
471 _compressHeaders = true;
\r
472 _encryptHeadersSpecified = false;
\r
473 _encryptHeaders = false;
\r
475 WriteCTime = false;
\r
476 WriteATime = false;
\r
480 _numThreads = NSystem::GetNumberOfProcessors();
\r
484 _autoFilter = true;
\r
485 _volumeMode = false;
\r
490 void COutHandler::BeforeSetProperty()
\r
494 numProcessors = NSystem::GetNumberOfProcessors();
\r
497 mainDicSize = 0xFFFFFFFF;
\r
498 mainDicMethodIndex = 0xFFFFFFFF;
\r
503 HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
\r
505 UString name = nameSpec;
\r
507 if (name.IsEmpty())
\r
508 return E_INVALIDARG;
\r
510 if (name[0] == 'X')
\r
514 return ParsePropValue(name, value, _level);
\r
517 if (name[0] == L'S')
\r
520 if (name.IsEmpty())
\r
521 return SetSolidSettings(value);
\r
522 if (value.vt != VT_EMPTY)
\r
523 return E_INVALIDARG;
\r
524 return SetSolidSettings(name);
\r
527 if (name == L"CRC")
\r
531 return ParsePropValue(name, value, _crcSize);
\r
535 int index = ParseStringToUInt32(name, number);
\r
536 UString realName = name.Mid(index);
\r
539 if(name.Left(2).CompareNoCase(L"MT") == 0)
\r
542 RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
\r
546 if (name.CompareNoCase(L"RSFX") == 0) return SetBoolProperty(_removeSfxBlock, value);
\r
547 if (name.CompareNoCase(L"F") == 0) return SetBoolProperty(_autoFilter, value);
\r
548 if (name.CompareNoCase(L"HC") == 0) return SetBoolProperty(_compressHeaders, value);
\r
549 if (name.CompareNoCase(L"HCF") == 0)
\r
551 bool compressHeadersFull = true;
\r
552 RINOK(SetBoolProperty(compressHeadersFull, value));
\r
553 if (!compressHeadersFull)
\r
554 return E_INVALIDARG;
\r
557 if (name.CompareNoCase(L"HE") == 0)
\r
559 RINOK(SetBoolProperty(_encryptHeaders, value));
\r
560 _encryptHeadersSpecified = true;
\r
563 if (name.CompareNoCase(L"TC") == 0) return SetBoolProperty(WriteCTime, value);
\r
564 if (name.CompareNoCase(L"TA") == 0) return SetBoolProperty(WriteATime, value);
\r
565 if (name.CompareNoCase(L"TM") == 0) return SetBoolProperty(WriteMTime, value);
\r
566 if (name.CompareNoCase(L"V") == 0) return SetBoolProperty(_volumeMode, value);
\r
569 if (number > 10000)
\r
571 if (number < minNumber)
\r
572 return E_INVALIDARG;
\r
573 number -= minNumber;
\r
574 for(int j = _methods.Size(); j <= (int)number; j++)
\r
576 COneMethodInfo oneMethodInfo;
\r
577 _methods.Add(oneMethodInfo);
\r
580 COneMethodInfo &oneMethodInfo = _methods[number];
\r
582 if (realName.Length() == 0)
\r
584 if (value.vt != VT_BSTR)
\r
585 return E_INVALIDARG;
\r
587 RINOK(SetParams(oneMethodInfo, value.bstrVal));
\r
591 int index = FindPropIdStart(realName);
\r
593 return E_INVALIDARG;
\r
594 const CNameToPropID &nameToPropID = g_NameToPropID[index];
\r
596 prop.Id = nameToPropID.PropID;
\r
598 if (prop.Id == NCoderPropID::kBlockSize ||
\r
599 prop.Id == NCoderPropID::kDictionarySize ||
\r
600 prop.Id == NCoderPropID::kUsedMemorySize)
\r
603 RINOK(ParsePropDictionaryValue(realName.Mid(MyStringLen(nameToPropID.Name)), value, dicSize));
\r
604 prop.Value = dicSize;
\r
605 if (number <= mainDicMethodIndex)
\r
606 mainDicSize = dicSize;
\r
610 int index = FindPropIdExact(realName);
\r
612 return E_INVALIDARG;
\r
613 const CNameToPropID &nameToPropID = g_NameToPropID[index];
\r
614 prop.Id = nameToPropID.PropID;
\r
615 if (!ConvertProperty(value, nameToPropID.VarType, prop.Value))
\r
616 return E_INVALIDARG;
\r
618 oneMethodInfo.Props.Add(prop);
\r