// 7z/OutHandler.cpp #include "StdAfx.h" #include "7zHandler.h" #include "7zOut.h" #include "7zUpdate.h" #include "../../../Windows/PropVariant.h" #include "../../../Common/ComTry.h" #include "../../../Common/StringToInt.h" #include "../../IPassword.h" #include "../../ICoder.h" #include "../Common/ItemNameUtils.h" #include "../Common/ParseProperties.h" using namespace NWindows; namespace NArchive { namespace N7z { const wchar_t *kCopyMethod = L"Copy"; const wchar_t *kLZMAMethodName = L"LZMA"; const wchar_t *kLZMA2MethodName = L"LZMA2"; const wchar_t *kBZip2MethodName = L"BZip2"; const wchar_t *kPpmdMethodName = L"PPMd"; const wchar_t *kDeflateMethodName = L"Deflate"; const wchar_t *kDeflate64MethodName = L"Deflate64"; static const wchar_t *kLzmaMatchFinderX1 = L"HC4"; static const wchar_t *kLzmaMatchFinderX5 = L"BT4"; static const UInt32 kLzmaAlgorithmX1 = 0; static const UInt32 kLzmaAlgorithmX5 = 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 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; 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 = kLzmaAlgorithmX5; static bool IsCopyMethod(const UString &methodName) { return (methodName.CompareNoCase(kCopyMethod) == 0); } static bool IsLZMAMethod(const UString &methodName) { return (methodName.CompareNoCase(kLZMAMethodName) == 0) || (methodName.CompareNoCase(kLZMA2MethodName) == 0); } /* static bool IsLZMethod(const UString &methodName) { return IsLZMAMethod(methodName); } */ static bool IsBZip2Method(const UString &methodName) { return (methodName.CompareNoCase(kBZip2MethodName) == 0); } static bool IsPpmdMethod(const UString &methodName) { return (methodName.CompareNoCase(kPpmdMethodName) == 0); } static bool IsDeflateMethod(const UString &methodName) { return (methodName.CompareNoCase(kDeflateMethodName) == 0) || (methodName.CompareNoCase(kDeflate64MethodName) == 0); } STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) { *type = NFileTimeType::kWindows; return S_OK; } HRESULT CHandler::SetPassword(CCompressionMethodMode &methodMode, IArchiveUpdateCallback *updateCallback) { CMyComPtr getTextPassword; if (!getTextPassword) { CMyComPtr udateCallback2(updateCallback); udateCallback2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword); } if (getTextPassword) { CMyComBSTR password; Int32 passwordIsDefined; RINOK(getTextPassword->CryptoGetTextPassword2( &passwordIsDefined, &password)); methodMode.PasswordIsDefined = IntToBool(passwordIsDefined); if (methodMode.PasswordIsDefined) methodMode.Password = password; } else methodMode.PasswordIsDefined = false; return S_OK; } struct CNameToPropID { PROPID PropID; VARTYPE VarType; const wchar_t *Name; }; CNameToPropID g_NameToPropID[] = { { 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::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" } }; 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; } } return false; } const int kNumNameToPropIDItems = sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); int FindPropIdFromStringName(const UString &name) { for (int i = 0; i < kNumNameToPropIDItems; i++) if (name.CompareNoCase(g_NameToPropID[i].Name) == 0) return i; return -1; } HRESULT CHandler::SetCompressionMethod( CCompressionMethodMode &methodMode, CCompressionMethodMode &headerMethod) { HRESULT res = SetCompressionMethod(methodMode, _methods #ifdef COMPRESS_MT , _numThreads #endif ); RINOK(res); methodMode.Binds = _binds; if (_compressHeaders) { // headerMethod.Methods.Add(methodMode.Methods.Back()); CObjectVector headerMethodInfoVector; COneMethodInfo oneMethodInfo; oneMethodInfo.MethodName = kLZMAMethodName; { CProperty property; property.PropID = NCoderPropID::kMatchFinder; property.Value = kLzmaMatchFinderForHeaders; oneMethodInfo.CoderProperties.Add(property); } { CProperty property; property.PropID = NCoderPropID::kAlgorithm; property.Value = kAlgorithmForHeaders; oneMethodInfo.CoderProperties.Add(property); } { CProperty property; property.PropID = NCoderPropID::kNumFastBytes; property.Value = UInt32(kNumFastBytesForHeaders); oneMethodInfo.CoderProperties.Add(property); } { CProperty property; property.PropID = NCoderPropID::kDictionarySize; property.Value = UInt32(kDictionaryForHeaders); oneMethodInfo.CoderProperties.Add(property); } headerMethodInfoVector.Add(oneMethodInfo); HRESULT res = SetCompressionMethod(headerMethod, headerMethodInfoVector #ifdef COMPRESS_MT ,1 #endif ); RINOK(res); } return S_OK; } static void SetOneMethodProp(COneMethodInfo &oneMethodInfo, PROPID propID, const NWindows::NCOM::CPropVariant &value) { int j; for (j = 0; j < oneMethodInfo.CoderProperties.Size(); j++) if (oneMethodInfo.CoderProperties[j].PropID == propID) break; if (j != oneMethodInfo.CoderProperties.Size()) return; CProperty property; property.PropID = propID; property.Value = value; oneMethodInfo.CoderProperties.Add(property); } HRESULT CHandler::SetCompressionMethod( CCompressionMethodMode &methodMode, CObjectVector &methodsInfo #ifdef COMPRESS_MT , UInt32 numThreads #endif ) { UInt32 level = _level; if (methodsInfo.IsEmpty()) { COneMethodInfo oneMethodInfo; oneMethodInfo.MethodName = ((level == 0) ? kCopyMethod : kDefaultMethodName); methodsInfo.Add(oneMethodInfo); } bool needSolid = false; for(int i = 0; i < methodsInfo.Size(); i++) { COneMethodInfo &oneMethodInfo = methodsInfo[i]; if (oneMethodInfo.MethodName.IsEmpty()) oneMethodInfo.MethodName = kDefaultMethodName; if (!IsCopyMethod(oneMethodInfo.MethodName)) needSolid = true; if (IsLZMAMethod(oneMethodInfo.MethodName)) { UInt32 dicSize = (level >= 9 ? kLzmaDicSizeX9 : (level >= 7 ? kLzmaDicSizeX7 : (level >= 5 ? kLzmaDicSizeX5 : (level >= 3 ? kLzmaDicSizeX3 : kLzmaDicSizeX1)))); UInt32 algorithm = (level >= 5 ? kLzmaAlgorithmX5 : kLzmaAlgorithmX1); UInt32 fastBytes = (level >= 7 ? kLzmaFastBytesX7 : kLzmaFastBytesX1); const wchar_t *matchFinder = (level >= 5 ? kLzmaMatchFinderX5 : kLzmaMatchFinderX1); SetOneMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize); SetOneMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algorithm); SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes); SetOneMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder); #ifdef COMPRESS_MT SetOneMethodProp(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)); SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes); SetOneMethodProp(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)); SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses); SetOneMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize); #ifdef COMPRESS_MT SetOneMethodProp(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))); SetOneMethodProp(oneMethodInfo, NCoderPropID::kUsedMemorySize, useMemSize); SetOneMethodProp(oneMethodInfo, NCoderPropID::kOrder, order); } CMethodFull methodFull; if (!FindMethod( EXTERNAL_CODECS_VARS oneMethodInfo.MethodName, methodFull.MethodID, methodFull.NumInStreams, methodFull.NumOutStreams)) return E_INVALIDARG; methodFull.CoderProperties = oneMethodInfo.CoderProperties; methodMode.Methods.Add(methodFull); if (!_numSolidBytesDefined) { for (int j = 0; j < methodFull.CoderProperties.Size(); j++) { const CProperty &prop = methodFull.CoderProperties[j]; if ((prop.PropID == NCoderPropID::kDictionarySize || prop.PropID == NCoderPropID::kUsedMemorySize) && prop.Value.vt == VT_UI4) { _numSolidBytes = ((UInt64)prop.Value.ulVal) << 7; const UInt64 kMinSize = (1 << 24); if (_numSolidBytes < kMinSize) _numSolidBytes = kMinSize; _numSolidBytesDefined = true; break; } } } } if (!needSolid && !_numSolidBytesDefined) { _numSolidBytesDefined = true; _numSolidBytes = 0; } return S_OK; } static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, CArchiveFileTime &filetime, bool &filetimeIsDefined) { filetimeIsDefined = false; NCOM::CPropVariant propVariant; RINOK(updateCallback->GetProperty(index, propID, &propVariant)); if (propVariant.vt == VT_FILETIME) { filetime = propVariant.filetime; filetimeIsDefined = true; } else if (propVariant.vt != VT_EMPTY) return E_INVALIDARG; return S_OK; } STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) { COM_TRY_BEGIN const CArchiveDatabaseEx *database = 0; #ifdef _7Z_VOL if(_volumes.Size() > 1) return E_FAIL; const CVolume *volume = 0; if (_volumes.Size() == 1) { volume = &_volumes.Front(); database = &volume->Database; } #else if (_inStream != 0) database = &_database; #endif // CRecordVector compressStatuses; CObjectVector updateItems; // CRecordVector copyIndices; // CMyComPtr updateCallback2; // updateCallback->QueryInterface(&updateCallback2); for(UInt32 i = 0; i < numItems; i++) { Int32 newData; Int32 newProperties; UInt32 indexInArchive; if (!updateCallback) return E_FAIL; RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProperties, &indexInArchive)); CUpdateItem updateItem; updateItem.NewProperties = IntToBool(newProperties); updateItem.NewData = IntToBool(newData); updateItem.IndexInArchive = indexInArchive; updateItem.IndexInClient = i; updateItem.IsAnti = false; updateItem.Size = 0; if (updateItem.IndexInArchive != -1) { const CFileItem &fileItem = database->Files[updateItem.IndexInArchive]; updateItem.Name = fileItem.Name; updateItem.IsDirectory = fileItem.IsDirectory; updateItem.Size = fileItem.UnPackSize; updateItem.IsAnti = fileItem.IsAnti; updateItem.CreationTime = fileItem.CreationTime; updateItem.IsCreationTimeDefined = fileItem.IsCreationTimeDefined; updateItem.LastWriteTime = fileItem.LastWriteTime; updateItem.IsLastWriteTimeDefined = fileItem.IsLastWriteTimeDefined; updateItem.LastAccessTime = fileItem.LastAccessTime; updateItem.IsLastAccessTimeDefined = fileItem.IsLastAccessTimeDefined; } if (updateItem.NewProperties) { bool nameIsDefined; bool folderStatusIsDefined; { NCOM::CPropVariant propVariant; RINOK(updateCallback->GetProperty(i, kpidAttributes, &propVariant)); if (propVariant.vt == VT_EMPTY) updateItem.AttributesAreDefined = false; else if (propVariant.vt != VT_UI4) return E_INVALIDARG; else { updateItem.Attributes = propVariant.ulVal; updateItem.AttributesAreDefined = true; } } RINOK(GetTime(updateCallback, i, kpidCreationTime, updateItem.CreationTime, updateItem.IsCreationTimeDefined)); RINOK(GetTime(updateCallback, i, kpidLastWriteTime, updateItem.LastWriteTime , updateItem.IsLastWriteTimeDefined)); RINOK(GetTime(updateCallback, i, kpidLastAccessTime, updateItem.LastAccessTime, updateItem.IsLastAccessTimeDefined)); { NCOM::CPropVariant propVariant; RINOK(updateCallback->GetProperty(i, kpidPath, &propVariant)); if (propVariant.vt == VT_EMPTY) nameIsDefined = false; else if (propVariant.vt != VT_BSTR) return E_INVALIDARG; else { updateItem.Name = NItemName::MakeLegalName(propVariant.bstrVal); nameIsDefined = true; } } { NCOM::CPropVariant propVariant; RINOK(updateCallback->GetProperty(i, kpidIsFolder, &propVariant)); if (propVariant.vt == VT_EMPTY) folderStatusIsDefined = false; else if (propVariant.vt != VT_BOOL) return E_INVALIDARG; else { updateItem.IsDirectory = (propVariant.boolVal != VARIANT_FALSE); folderStatusIsDefined = true; } } { NCOM::CPropVariant propVariant; RINOK(updateCallback->GetProperty(i, kpidIsAnti, &propVariant)); if (propVariant.vt == VT_EMPTY) updateItem.IsAnti = false; else if (propVariant.vt != VT_BOOL) return E_INVALIDARG; else updateItem.IsAnti = (propVariant.boolVal != VARIANT_FALSE); } if (updateItem.IsAnti) { updateItem.AttributesAreDefined = false; updateItem.IsCreationTimeDefined = false; updateItem.IsLastWriteTimeDefined = false; updateItem.IsLastAccessTimeDefined = false; updateItem.Size = 0; } if (!folderStatusIsDefined && updateItem.AttributesAreDefined) updateItem.SetDirectoryStatusFromAttributes(); } if (updateItem.NewData) { NCOM::CPropVariant propVariant; RINOK(updateCallback->GetProperty(i, kpidSize, &propVariant)); if (propVariant.vt != VT_UI8) return E_INVALIDARG; updateItem.Size = (UInt64)propVariant.uhVal.QuadPart; if (updateItem.Size != 0 && updateItem.IsAnti) return E_INVALIDARG; } updateItems.Add(updateItem); } CCompressionMethodMode methodMode, headerMethod; RINOK(SetCompressionMethod(methodMode, headerMethod)); #ifdef COMPRESS_MT methodMode.NumThreads = _numThreads; headerMethod.NumThreads = 1; #endif RINOK(SetPassword(methodMode, updateCallback)); bool compressMainHeader = _compressHeaders; // check it if (methodMode.PasswordIsDefined) { compressMainHeader = true; if(_encryptHeaders) RINOK(SetPassword(headerMethod, updateCallback)); } if (numItems < 2) compressMainHeader = false; CUpdateOptions options; options.Method = &methodMode; options.HeaderMethod = (_compressHeaders || (methodMode.PasswordIsDefined && _encryptHeaders)) ? &headerMethod : 0; options.UseFilters = _level != 0 && _autoFilter; options.MaxFilter = _level >= 8; options.HeaderOptions.CompressMainHeader = compressMainHeader; options.HeaderOptions.WriteModified = WriteModified; options.HeaderOptions.WriteCreated = WriteCreated; options.HeaderOptions.WriteAccessed = WriteAccessed; options.NumSolidFiles = _numSolidFiles; options.NumSolidBytes = _numSolidBytes; options.SolidExtension = _solidExtension; options.RemoveSfxBlock = _removeSfxBlock; options.VolumeMode = _volumeMode; return Update( EXTERNAL_CODECS_VARS #ifdef _7Z_VOL volume ? volume->Stream: 0, volume ? database: 0, #else _inStream, database, #endif updateItems, outStream, updateCallback, options); COM_TRY_END } static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream) { stream = 0; int index = ParseStringToUInt32(srcString, coder); if (index == 0) return E_INVALIDARG; srcString.Delete(0, index); if (srcString[0] == 'S') { srcString.Delete(0); int index = ParseStringToUInt32(srcString, stream); if (index == 0) return E_INVALIDARG; srcString.Delete(0, index); } return S_OK; } static HRESULT GetBindInfo(UString &srcString, CBind &bind) { RINOK(GetBindInfoPart(srcString, bind.OutCoder, bind.OutStream)); if (srcString[0] != ':') return E_INVALIDARG; srcString.Delete(0); RINOK(GetBindInfoPart(srcString, bind.InCoder, bind.InStream)); if (!srcString.IsEmpty()) return E_INVALIDARG; return S_OK; } 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 CHandler::SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value) { CProperty property; if (name.CompareNoCase(L"D") == 0 || name.CompareNoCase(L"MEM") == 0) { UInt32 dicSize; RINOK(ParsePropDictionaryValue(value, dicSize)); if (name.CompareNoCase(L"D") == 0) property.PropID = NCoderPropID::kDictionarySize; else property.PropID = NCoderPropID::kUsedMemorySize; property.Value = dicSize; oneMethodInfo.CoderProperties.Add(property); } else { int index = FindPropIdFromStringName(name); if (index < 0) return E_INVALIDARG; const CNameToPropID &nameToPropID = g_NameToPropID[index]; property.PropID = nameToPropID.PropID; NCOM::CPropVariant propValue; if (nameToPropID.VarType == VT_BSTR) propValue = value; else { UInt32 number; if (ParseStringToUInt32(value, number) == value.Length()) propValue = number; else propValue = value; } if (!ConvertProperty(propValue, nameToPropID.VarType, property.Value)) return E_INVALIDARG; oneMethodInfo.CoderProperties.Add(property); } return S_OK; } HRESULT CHandler::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 CHandler::SetSolidSettings(const UString &s) { UString s2 = s; s2.MakeUpper(); if (s2.IsEmpty() || s2.Compare(L"ON") == 0) { InitSolid(); return S_OK; } if (s2.Compare(L"OFF") == 0) { _numSolidFiles = 1; return S_OK; } 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 CHandler::SetSolidSettings(const PROPVARIANT &value) { switch(value.vt) { case VT_EMPTY: InitSolid(); return S_OK; case VT_BSTR: return SetSolidSettings(value.bstrVal); default: return E_INVALIDARG; } } STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) { COM_TRY_BEGIN _methods.Clear(); _binds.Clear(); Init(); #ifdef COMPRESS_MT const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); #endif UInt32 mainDicSize = 0xFFFFFFFF; UInt32 mainDicMethodIndex = 0xFFFFFFFF; UInt32 minNumber = 0; for (int i = 0; i < numProperties; i++) { UString name = names[i]; name.MakeUpper(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &value = values[i]; if (name[0] == 'X') { name.Delete(0); _level = 9; RINOK(ParsePropValue(name, value, _level)); continue; } if (name[0] == 'B') { name.Delete(0); CBind bind; RINOK(GetBindInfo(name, bind)); _binds.Add(bind); continue; } if (name[0] == L'S') { name.Delete(0); if (name.IsEmpty()) { RINOK(SetSolidSettings(value)); } else { RINOK(SetSolidSettings(name)); } continue; } UInt32 number; int index = ParseStringToUInt32(name, number); UString realName = name.Mid(index); if (index == 0) { if(name.Left(2).CompareNoCase(L"MT") == 0) { #ifdef COMPRESS_MT RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads)); #endif continue; } else if (name.CompareNoCase(L"RSFX") == 0) { RINOK(SetBoolProperty(_removeSfxBlock, value)); continue; } else if (name.CompareNoCase(L"F") == 0) { RINOK(SetBoolProperty(_autoFilter, value)); continue; } else if (name.CompareNoCase(L"HC") == 0) { RINOK(SetBoolProperty(_compressHeaders, value)); continue; } else if (name.CompareNoCase(L"HCF") == 0) { bool compressHeadersFull = true; RINOK(SetBoolProperty(compressHeadersFull, value)); if (!compressHeadersFull) return E_INVALIDARG; continue; } else if (name.CompareNoCase(L"HE") == 0) { RINOK(SetBoolProperty(_encryptHeaders, value)); continue; } else if (name.CompareNoCase(L"TM") == 0) { RINOK(SetBoolProperty(WriteModified, value)); continue; } else if (name.CompareNoCase(L"TC") == 0) { RINOK(SetBoolProperty(WriteCreated, value)); continue; } else if (name.CompareNoCase(L"TA") == 0) { RINOK(SetBoolProperty(WriteAccessed, value)); continue; } else if (name.CompareNoCase(L"V") == 0) { RINOK(SetBoolProperty(_volumeMode, value)); continue; } 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; // oneMethodInfo.MethodName = UnicodeStringToMultiByte(UString(value.bstrVal)); RINOK(SetParams(oneMethodInfo, value.bstrVal)); } else { CProperty property; if (realName.Left(1).CompareNoCase(L"D") == 0) { UInt32 dicSize; RINOK(ParsePropDictionaryValue(realName.Mid(1), value, dicSize)); property.PropID = NCoderPropID::kDictionarySize; property.Value = dicSize; oneMethodInfo.CoderProperties.Add(property); if (number <= mainDicMethodIndex) mainDicSize = dicSize; } else if (realName.Left(3).CompareNoCase(L"MEM") == 0) { UInt32 dicSize; RINOK(ParsePropDictionaryValue(realName.Mid(3), value, dicSize)); property.PropID = NCoderPropID::kUsedMemorySize; property.Value = dicSize; oneMethodInfo.CoderProperties.Add(property); if (number <= mainDicMethodIndex) mainDicSize = dicSize; } else { int index = FindPropIdFromStringName(realName); if (index < 0) return E_INVALIDARG; const CNameToPropID &nameToPropID = g_NameToPropID[index]; property.PropID = nameToPropID.PropID; if (!ConvertProperty(value, nameToPropID.VarType, property.Value)) return E_INVALIDARG; oneMethodInfo.CoderProperties.Add(property); } } } return S_OK; COM_TRY_END } }}