| // HandlerOut.cpp |
| |
| #include "StdAfx.h" |
| |
| #include "../../../Common/StringToInt.h" |
| |
| #include "../../../Windows/PropVariant.h" |
| |
| #ifndef _7ZIP_ST |
| #include "../../../Windows/System.h" |
| #endif |
| |
| #include "../../ICoder.h" |
| |
| #include "../Common/ParseProperties.h" |
| |
| #include "HandlerOut.h" |
| |
| using namespace NWindows; |
| |
| namespace NArchive { |
| |
| static const wchar_t *kCopyMethod = L"Copy"; |
| static const wchar_t *kLZMAMethodName = L"LZMA"; |
| static const wchar_t *kLZMA2MethodName = L"LZMA2"; |
| static const wchar_t *kBZip2MethodName = L"BZip2"; |
| static const wchar_t *kPpmdMethodName = L"PPMd"; |
| static const wchar_t *kDeflateMethodName = L"Deflate"; |
| static const wchar_t *kDeflate64MethodName = L"Deflate64"; |
| |
| static const wchar_t *kLzmaMatchFinderX1 = L"HC4"; |
| static const wchar_t *kLzmaMatchFinderX5 = L"BT4"; |
| |
| static const UInt32 kLzmaAlgoX1 = 0; |
| static const UInt32 kLzmaAlgoX5 = 1; |
| |
| static const UInt32 kLzmaDicSizeX1 = 1 << 16; |
| static const UInt32 kLzmaDicSizeX3 = 1 << 20; |
| static const UInt32 kLzmaDicSizeX5 = 1 << 24; |
| static const UInt32 kLzmaDicSizeX7 = 1 << 25; |
| static const UInt32 kLzmaDicSizeX9 = 1 << 26; |
| |
| static const UInt32 kLzmaFastBytesX1 = 32; |
| static const UInt32 kLzmaFastBytesX7 = 64; |
| |
| static const UInt32 kPpmdMemSizeX1 = (1 << 22); |
| static const UInt32 kPpmdMemSizeX5 = (1 << 24); |
| static const UInt32 kPpmdMemSizeX7 = (1 << 26); |
| static const UInt32 kPpmdMemSizeX9 = (192 << 20); |
| |
| static const UInt32 kPpmdOrderX1 = 4; |
| static const UInt32 kPpmdOrderX5 = 6; |
| static const UInt32 kPpmdOrderX7 = 16; |
| static const UInt32 kPpmdOrderX9 = 32; |
| |
| static const UInt32 kDeflateAlgoX1 = 0; |
| static const UInt32 kDeflateAlgoX5 = 1; |
| |
| static const UInt32 kDeflateFastBytesX1 = 32; |
| static const UInt32 kDeflateFastBytesX7 = 64; |
| static const UInt32 kDeflateFastBytesX9 = 128; |
| |
| static const UInt32 kDeflatePassesX1 = 1; |
| static const UInt32 kDeflatePassesX7 = 3; |
| static const UInt32 kDeflatePassesX9 = 10; |
| |
| static const UInt32 kBZip2NumPassesX1 = 1; |
| static const UInt32 kBZip2NumPassesX7 = 2; |
| static const UInt32 kBZip2NumPassesX9 = 7; |
| |
| static const UInt32 kBZip2DicSizeX1 = 100000; |
| static const UInt32 kBZip2DicSizeX3 = 500000; |
| static const UInt32 kBZip2DicSizeX5 = 900000; |
| |
| static const wchar_t *kDefaultMethodName = kLZMAMethodName; |
| |
| static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2"; |
| static const UInt32 kDictionaryForHeaders = 1 << 20; |
| static const UInt32 kNumFastBytesForHeaders = 273; |
| static const UInt32 kAlgorithmForHeaders = kLzmaAlgoX5; |
| |
| static bool AreEqual(const UString &methodName, const wchar_t *s) |
| { return (methodName.CompareNoCase(s) == 0); } |
| |
| bool COneMethodInfo::IsLzma() const |
| { |
| return |
| AreEqual(MethodName, kLZMAMethodName) || |
| AreEqual(MethodName, kLZMA2MethodName); |
| } |
| |
| static inline bool IsBZip2Method(const UString &methodName) |
| { return AreEqual(methodName, kBZip2MethodName); } |
| |
| static inline bool IsPpmdMethod(const UString &methodName) |
| { return AreEqual(methodName, kPpmdMethodName); } |
| |
| static inline bool IsDeflateMethod(const UString &methodName) |
| { |
| return |
| AreEqual(methodName, kDeflateMethodName) || |
| AreEqual(methodName, kDeflate64MethodName); |
| } |
| |
| struct CNameToPropID |
| { |
| PROPID PropID; |
| VARTYPE VarType; |
| const wchar_t *Name; |
| }; |
| |
| static CNameToPropID g_NameToPropID[] = |
| { |
| { NCoderPropID::kBlockSize, VT_UI4, L"C" }, |
| { NCoderPropID::kDictionarySize, VT_UI4, L"D" }, |
| { NCoderPropID::kUsedMemorySize, VT_UI4, L"MEM" }, |
| |
| { NCoderPropID::kOrder, VT_UI4, L"O" }, |
| { NCoderPropID::kPosStateBits, VT_UI4, L"PB" }, |
| { NCoderPropID::kLitContextBits, VT_UI4, L"LC" }, |
| { NCoderPropID::kLitPosBits, VT_UI4, L"LP" }, |
| { NCoderPropID::kEndMarker, VT_BOOL, L"eos" }, |
| |
| { NCoderPropID::kNumPasses, VT_UI4, L"Pass" }, |
| { NCoderPropID::kNumFastBytes, VT_UI4, L"fb" }, |
| { NCoderPropID::kMatchFinderCycles, VT_UI4, L"mc" }, |
| { NCoderPropID::kAlgorithm, VT_UI4, L"a" }, |
| { NCoderPropID::kMatchFinder, VT_BSTR, L"mf" }, |
| { NCoderPropID::kNumThreads, VT_UI4, L"mt" }, |
| { NCoderPropID::kDefaultProp, VT_UI4, L"" } |
| }; |
| |
| static bool ConvertProperty(PROPVARIANT srcProp, VARTYPE varType, NCOM::CPropVariant &destProp) |
| { |
| if (varType == srcProp.vt) |
| { |
| destProp = srcProp; |
| return true; |
| } |
| if (varType == VT_UI1) |
| { |
| if (srcProp.vt == VT_UI4) |
| { |
| UInt32 value = srcProp.ulVal; |
| if (value > 0xFF) |
| return false; |
| destProp = (Byte)value; |
| return true; |
| } |
| } |
| else if (varType == VT_BOOL) |
| { |
| bool res; |
| if (SetBoolProperty(res, srcProp) != S_OK) |
| return false; |
| destProp = res; |
| return true; |
| } |
| return false; |
| } |
| |
| static int FindPropIdExact(const UString &name) |
| { |
| for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++) |
| if (name.CompareNoCase(g_NameToPropID[i].Name) == 0) |
| return i; |
| return -1; |
| } |
| |
| static int FindPropIdStart(const UString &name) |
| { |
| for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++) |
| { |
| UString t = g_NameToPropID[i].Name; |
| if (t.CompareNoCase(name.Left(t.Length())) == 0) |
| return i; |
| } |
| return -1; |
| } |
| |
| static void SetMethodProp(COneMethodInfo &m, PROPID propID, const NCOM::CPropVariant &value) |
| { |
| for (int j = 0; j < m.Props.Size(); j++) |
| if (m.Props[j].Id == propID) |
| return; |
| CProp prop; |
| prop.Id = propID; |
| prop.Value = value; |
| m.Props.Add(prop); |
| } |
| |
| void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo |
| #ifndef _7ZIP_ST |
| , UInt32 numThreads |
| #endif |
| ) |
| { |
| UInt32 level = _level; |
| if (oneMethodInfo.MethodName.IsEmpty()) |
| oneMethodInfo.MethodName = kDefaultMethodName; |
| |
| if (oneMethodInfo.IsLzma()) |
| { |
| UInt32 dicSize = |
| (level >= 9 ? kLzmaDicSizeX9 : |
| (level >= 7 ? kLzmaDicSizeX7 : |
| (level >= 5 ? kLzmaDicSizeX5 : |
| (level >= 3 ? kLzmaDicSizeX3 : |
| kLzmaDicSizeX1)))); |
| |
| UInt32 algo = |
| (level >= 5 ? kLzmaAlgoX5 : |
| kLzmaAlgoX1); |
| |
| UInt32 fastBytes = |
| (level >= 7 ? kLzmaFastBytesX7 : |
| kLzmaFastBytesX1); |
| |
| const wchar_t *matchFinder = |
| (level >= 5 ? kLzmaMatchFinderX5 : |
| kLzmaMatchFinderX1); |
| |
| SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize); |
| SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo); |
| SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes); |
| SetMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder); |
| #ifndef _7ZIP_ST |
| SetMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); |
| #endif |
| } |
| else if (IsDeflateMethod(oneMethodInfo.MethodName)) |
| { |
| UInt32 fastBytes = |
| (level >= 9 ? kDeflateFastBytesX9 : |
| (level >= 7 ? kDeflateFastBytesX7 : |
| kDeflateFastBytesX1)); |
| |
| UInt32 numPasses = |
| (level >= 9 ? kDeflatePassesX9 : |
| (level >= 7 ? kDeflatePassesX7 : |
| kDeflatePassesX1)); |
| |
| UInt32 algo = |
| (level >= 5 ? kDeflateAlgoX5 : |
| kDeflateAlgoX1); |
| |
| SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo); |
| SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes); |
| SetMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses); |
| } |
| else if (IsBZip2Method(oneMethodInfo.MethodName)) |
| { |
| UInt32 numPasses = |
| (level >= 9 ? kBZip2NumPassesX9 : |
| (level >= 7 ? kBZip2NumPassesX7 : |
| kBZip2NumPassesX1)); |
| |
| UInt32 dicSize = |
| (level >= 5 ? kBZip2DicSizeX5 : |
| (level >= 3 ? kBZip2DicSizeX3 : |
| kBZip2DicSizeX1)); |
| |
| SetMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses); |
| SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize); |
| #ifndef _7ZIP_ST |
| SetMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); |
| #endif |
| } |
| else if (IsPpmdMethod(oneMethodInfo.MethodName)) |
| { |
| UInt32 useMemSize = |
| (level >= 9 ? kPpmdMemSizeX9 : |
| (level >= 7 ? kPpmdMemSizeX7 : |
| (level >= 5 ? kPpmdMemSizeX5 : |
| kPpmdMemSizeX1))); |
| |
| UInt32 order = |
| (level >= 9 ? kPpmdOrderX9 : |
| (level >= 7 ? kPpmdOrderX7 : |
| (level >= 5 ? kPpmdOrderX5 : |
| kPpmdOrderX1))); |
| |
| SetMethodProp(oneMethodInfo, NCoderPropID::kUsedMemorySize, useMemSize); |
| SetMethodProp(oneMethodInfo, NCoderPropID::kOrder, order); |
| } |
| } |
| |
| static void SplitParams(const UString &srcString, UStringVector &subStrings) |
| { |
| subStrings.Clear(); |
| UString name; |
| int len = srcString.Length(); |
| if (len == 0) |
| return; |
| for (int i = 0; i < len; i++) |
| { |
| wchar_t c = srcString[i]; |
| if (c == L':') |
| { |
| subStrings.Add(name); |
| name.Empty(); |
| } |
| else |
| name += c; |
| } |
| subStrings.Add(name); |
| } |
| |
| static void SplitParam(const UString ¶m, UString &name, UString &value) |
| { |
| int eqPos = param.Find(L'='); |
| if (eqPos >= 0) |
| { |
| name = param.Left(eqPos); |
| value = param.Mid(eqPos + 1); |
| return; |
| } |
| for(int i = 0; i < param.Length(); i++) |
| { |
| wchar_t c = param[i]; |
| if (c >= L'0' && c <= L'9') |
| { |
| name = param.Left(i); |
| value = param.Mid(i); |
| return; |
| } |
| } |
| name = param; |
| } |
| |
| HRESULT COutHandler::SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value) |
| { |
| CProp prop; |
| int index = FindPropIdExact(name); |
| if (index < 0) |
| return E_INVALIDARG; |
| const CNameToPropID &nameToPropID = g_NameToPropID[index]; |
| prop.Id = nameToPropID.PropID; |
| |
| if (prop.Id == NCoderPropID::kBlockSize || |
| prop.Id == NCoderPropID::kDictionarySize || |
| prop.Id == NCoderPropID::kUsedMemorySize) |
| { |
| UInt32 dicSize; |
| RINOK(ParsePropDictionaryValue(value, dicSize)); |
| prop.Value = dicSize; |
| } |
| else |
| { |
| NCOM::CPropVariant propValue; |
| |
| if (nameToPropID.VarType == VT_BSTR) |
| propValue = value; |
| else if (nameToPropID.VarType == VT_BOOL) |
| { |
| bool res; |
| if (!StringToBool(value, res)) |
| return E_INVALIDARG; |
| propValue = res; |
| } |
| else |
| { |
| UInt32 number; |
| if (ParseStringToUInt32(value, number) == value.Length()) |
| propValue = number; |
| else |
| propValue = value; |
| } |
| |
| if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value)) |
| return E_INVALIDARG; |
| } |
| oneMethodInfo.Props.Add(prop); |
| return S_OK; |
| } |
| |
| HRESULT COutHandler::SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString) |
| { |
| UStringVector params; |
| SplitParams(srcString, params); |
| if (params.Size() > 0) |
| oneMethodInfo.MethodName = params[0]; |
| for (int i = 1; i < params.Size(); i++) |
| { |
| const UString ¶m = params[i]; |
| UString name, value; |
| SplitParam(param, name, value); |
| RINOK(SetParam(oneMethodInfo, name, value)); |
| } |
| return S_OK; |
| } |
| |
| HRESULT COutHandler::SetSolidSettings(const UString &s) |
| { |
| UString s2 = s; |
| s2.MakeUpper(); |
| for (int i = 0; i < s2.Length();) |
| { |
| const wchar_t *start = ((const wchar_t *)s2) + i; |
| const wchar_t *end; |
| UInt64 v = ConvertStringToUInt64(start, &end); |
| if (start == end) |
| { |
| if (s2[i++] != 'E') |
| return E_INVALIDARG; |
| _solidExtension = true; |
| continue; |
| } |
| i += (int)(end - start); |
| if (i == s2.Length()) |
| return E_INVALIDARG; |
| wchar_t c = s2[i++]; |
| switch(c) |
| { |
| case 'F': |
| if (v < 1) |
| v = 1; |
| _numSolidFiles = v; |
| break; |
| case 'B': |
| _numSolidBytes = v; |
| _numSolidBytesDefined = true; |
| break; |
| case 'K': |
| _numSolidBytes = (v << 10); |
| _numSolidBytesDefined = true; |
| break; |
| case 'M': |
| _numSolidBytes = (v << 20); |
| _numSolidBytesDefined = true; |
| break; |
| case 'G': |
| _numSolidBytes = (v << 30); |
| _numSolidBytesDefined = true; |
| break; |
| default: |
| return E_INVALIDARG; |
| } |
| } |
| return S_OK; |
| } |
| |
| HRESULT COutHandler::SetSolidSettings(const PROPVARIANT &value) |
| { |
| bool isSolid; |
| switch(value.vt) |
| { |
| case VT_EMPTY: |
| isSolid = true; |
| break; |
| case VT_BOOL: |
| isSolid = (value.boolVal != VARIANT_FALSE); |
| break; |
| case VT_BSTR: |
| if (StringToBool(value.bstrVal, isSolid)) |
| break; |
| return SetSolidSettings(value.bstrVal); |
| default: |
| return E_INVALIDARG; |
| } |
| if (isSolid) |
| InitSolid(); |
| else |
| _numSolidFiles = 1; |
| return S_OK; |
| } |
| |
| void COutHandler::Init() |
| { |
| _removeSfxBlock = false; |
| _compressHeaders = true; |
| _encryptHeadersSpecified = false; |
| _encryptHeaders = false; |
| |
| WriteCTime = false; |
| WriteATime = false; |
| WriteMTime = true; |
| |
| #ifndef _7ZIP_ST |
| _numThreads = NSystem::GetNumberOfProcessors(); |
| #endif |
| |
| _level = 5; |
| _autoFilter = true; |
| _volumeMode = false; |
| _crcSize = 4; |
| InitSolid(); |
| } |
| |
| void COutHandler::BeforeSetProperty() |
| { |
| Init(); |
| #ifndef _7ZIP_ST |
| numProcessors = NSystem::GetNumberOfProcessors(); |
| #endif |
| |
| mainDicSize = 0xFFFFFFFF; |
| mainDicMethodIndex = 0xFFFFFFFF; |
| minNumber = 0; |
| _crcSize = 4; |
| } |
| |
| HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) |
| { |
| UString name = nameSpec; |
| name.MakeUpper(); |
| if (name.IsEmpty()) |
| return E_INVALIDARG; |
| |
| if (name[0] == 'X') |
| { |
| name.Delete(0); |
| _level = 9; |
| return ParsePropValue(name, value, _level); |
| } |
| |
| if (name[0] == L'S') |
| { |
| name.Delete(0); |
| if (name.IsEmpty()) |
| return SetSolidSettings(value); |
| if (value.vt != VT_EMPTY) |
| return E_INVALIDARG; |
| return SetSolidSettings(name); |
| } |
| |
| if (name == L"CRC") |
| { |
| _crcSize = 4; |
| name.Delete(0, 3); |
| return ParsePropValue(name, value, _crcSize); |
| } |
| |
| UInt32 number; |
| int index = ParseStringToUInt32(name, number); |
| UString realName = name.Mid(index); |
| if (index == 0) |
| { |
| if(name.Left(2).CompareNoCase(L"MT") == 0) |
| { |
| #ifndef _7ZIP_ST |
| RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads)); |
| #endif |
| return S_OK; |
| } |
| if (name.CompareNoCase(L"RSFX") == 0) return SetBoolProperty(_removeSfxBlock, value); |
| if (name.CompareNoCase(L"F") == 0) return SetBoolProperty(_autoFilter, value); |
| if (name.CompareNoCase(L"HC") == 0) return SetBoolProperty(_compressHeaders, value); |
| if (name.CompareNoCase(L"HCF") == 0) |
| { |
| bool compressHeadersFull = true; |
| RINOK(SetBoolProperty(compressHeadersFull, value)); |
| if (!compressHeadersFull) |
| return E_INVALIDARG; |
| return S_OK; |
| } |
| if (name.CompareNoCase(L"HE") == 0) |
| { |
| RINOK(SetBoolProperty(_encryptHeaders, value)); |
| _encryptHeadersSpecified = true; |
| return S_OK; |
| } |
| if (name.CompareNoCase(L"TC") == 0) return SetBoolProperty(WriteCTime, value); |
| if (name.CompareNoCase(L"TA") == 0) return SetBoolProperty(WriteATime, value); |
| if (name.CompareNoCase(L"TM") == 0) return SetBoolProperty(WriteMTime, value); |
| if (name.CompareNoCase(L"V") == 0) return SetBoolProperty(_volumeMode, value); |
| number = 0; |
| } |
| if (number > 10000) |
| return E_FAIL; |
| if (number < minNumber) |
| return E_INVALIDARG; |
| number -= minNumber; |
| for(int j = _methods.Size(); j <= (int)number; j++) |
| { |
| COneMethodInfo oneMethodInfo; |
| _methods.Add(oneMethodInfo); |
| } |
| |
| COneMethodInfo &oneMethodInfo = _methods[number]; |
| |
| if (realName.Length() == 0) |
| { |
| if (value.vt != VT_BSTR) |
| return E_INVALIDARG; |
| |
| RINOK(SetParams(oneMethodInfo, value.bstrVal)); |
| } |
| else |
| { |
| int index = FindPropIdStart(realName); |
| if (index < 0) |
| return E_INVALIDARG; |
| const CNameToPropID &nameToPropID = g_NameToPropID[index]; |
| CProp prop; |
| prop.Id = nameToPropID.PropID; |
| |
| if (prop.Id == NCoderPropID::kBlockSize || |
| prop.Id == NCoderPropID::kDictionarySize || |
| prop.Id == NCoderPropID::kUsedMemorySize) |
| { |
| UInt32 dicSize; |
| RINOK(ParsePropDictionaryValue(realName.Mid(MyStringLen(nameToPropID.Name)), value, dicSize)); |
| prop.Value = dicSize; |
| if (number <= mainDicMethodIndex) |
| mainDicSize = dicSize; |
| } |
| else |
| { |
| int index = FindPropIdExact(realName); |
| if (index < 0) |
| return E_INVALIDARG; |
| const CNameToPropID &nameToPropID = g_NameToPropID[index]; |
| prop.Id = nameToPropID.PropID; |
| if (!ConvertProperty(value, nameToPropID.VarType, prop.Value)) |
| return E_INVALIDARG; |
| } |
| oneMethodInfo.Props.Add(prop); |
| } |
| return S_OK; |
| } |
| |
| } |