diff options
Diffstat (limited to 'src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandlerOut.cpp')
-rw-r--r-- | src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandlerOut.cpp | 708 |
1 files changed, 550 insertions, 158 deletions
diff --git a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandlerOut.cpp index a8ccab6df..7de5b8140 100644 --- a/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandlerOut.cpp +++ b/src/libs/7zip/unix/CPP/7zip/Archive/7z/7zHandlerOut.cpp @@ -2,12 +2,9 @@ #include "StdAfx.h" -#include "../../../Windows/PropVariant.h" - #include "../../../Common/ComTry.h" #include "../../../Common/StringToInt.h" - -#include "../../ICoder.h" +#include "../../../Common/Wildcard.h" #include "../Common/ItemNameUtils.h" #include "../Common/ParseProperties.h" @@ -21,24 +18,19 @@ using namespace NWindows; namespace NArchive { namespace N7z { -static const wchar_t *kLZMAMethodName = L"LZMA"; -static const wchar_t *kCopyMethod = L"Copy"; -static const wchar_t *kDefaultMethodName = kLZMAMethodName; +static const wchar_t *k_LZMA_Name = L"LZMA"; +static const wchar_t *kDefaultMethodName = L"LZMA2"; +static const wchar_t *k_Copy_Name = L"Copy"; -static const UInt32 kLzmaAlgorithmX5 = 1; -static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2"; -static const UInt32 kDictionaryForHeaders = +static const wchar_t *k_MatchFinder_ForHeaders = L"BT2"; +static const UInt32 k_NumFastBytes_ForHeaders = 273; +static const UInt32 k_Level_ForHeaders = 5; +static const UInt32 k_Dictionary_ForHeaders = #ifdef UNDER_CE - 1 << 18 + 1 << 18; #else - 1 << 20 + 1 << 20; #endif -; -static const UInt32 kNumFastBytesForHeaders = 273; -static const UInt32 kAlgorithmForHeaders = kLzmaAlgorithmX5; - -static inline bool IsCopyMethod(const UString &methodName) - { return (methodName.CompareNoCase(kCopyMethod) == 0); } STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) { @@ -46,132 +38,112 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) return S_OK; } -HRESULT CHandler::SetCompressionMethod( - CCompressionMethodMode &methodMode, - CCompressionMethodMode &headerMethod) +HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m) { - HRESULT res = SetCompressionMethod(methodMode, _methods - #ifndef _7ZIP_ST - , _numThreads - #endif - ); - RINOK(res); - methodMode.Binds = _binds; + if (!FindMethod( + EXTERNAL_CODECS_VARS + m.MethodName, dest.Id, dest.NumInStreams, dest.NumOutStreams)) + return E_INVALIDARG; + (CProps &)dest = (CProps &)m; + return S_OK; +} - if (_compressHeaders) - { - // headerMethod.Methods.Add(methodMode.Methods.Back()); +HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod) +{ + if (!_compressHeaders) + return S_OK; + COneMethodInfo m; + m.MethodName = k_LZMA_Name; + m.AddPropString(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders); + m.AddProp32(NCoderPropID::kLevel, k_Level_ForHeaders); + m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders); + m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders); + m.AddNumThreadsProp(1); + + CMethodFull methodFull; + RINOK(PropsMethod_To_FullMethod(methodFull, m)); + headerMethod.Methods.Add(methodFull); + return S_OK; +} - CObjectVector<COneMethodInfo> headerMethodInfoVector; - COneMethodInfo oneMethodInfo; - oneMethodInfo.MethodName = kLZMAMethodName; - { - CProp prop; - prop.Id = NCoderPropID::kMatchFinder; - prop.Value = kLzmaMatchFinderForHeaders; - oneMethodInfo.Props.Add(prop); - } - { - CProp prop; - prop.Id = NCoderPropID::kAlgorithm; - prop.Value = kAlgorithmForHeaders; - oneMethodInfo.Props.Add(prop); - } - { - CProp prop; - prop.Id = NCoderPropID::kNumFastBytes; - prop.Value = (UInt32)kNumFastBytesForHeaders; - oneMethodInfo.Props.Add(prop); - } - { - CProp prop; - prop.Id = NCoderPropID::kDictionarySize; - prop.Value = (UInt32)kDictionaryForHeaders; - oneMethodInfo.Props.Add(prop); - } - headerMethodInfoVector.Add(oneMethodInfo); - HRESULT res = SetCompressionMethod(headerMethod, headerMethodInfoVector - #ifndef _7ZIP_ST - , 1 - #endif - ); - RINOK(res); +void CHandler::AddDefaultMethod() +{ + FOR_VECTOR (i, _methods) + { + UString &methodName = _methods[i].MethodName; + if (methodName.IsEmpty()) + methodName = kDefaultMethodName; + } + if (_methods.IsEmpty()) + { + COneMethodInfo m; + m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName); + _methods.Add(m); } - return S_OK; } -HRESULT CHandler::SetCompressionMethod( +HRESULT CHandler::SetMainMethod( CCompressionMethodMode &methodMode, - CObjectVector<COneMethodInfo> &methodsInfo + CObjectVector<COneMethodInfo> &methods #ifndef _7ZIP_ST , UInt32 numThreads #endif ) { - UInt32 level = _level; - - if (methodsInfo.IsEmpty()) - { - COneMethodInfo oneMethodInfo; - oneMethodInfo.MethodName = ((level == 0) ? kCopyMethod : kDefaultMethodName); - methodsInfo.Add(oneMethodInfo); - } + AddDefaultMethod(); + + const UInt64 kSolidBytes_Min = (1 << 24); + const UInt64 kSolidBytes_Max = ((UInt64)1 << 32) - 1; bool needSolid = false; - for(int i = 0; i < methodsInfo.Size(); i++) + FOR_VECTOR (i, methods) { - COneMethodInfo &oneMethodInfo = methodsInfo[i]; - SetCompressionMethod2(oneMethodInfo + COneMethodInfo &oneMethodInfo = methods[i]; + SetGlobalLevelAndThreads(oneMethodInfo #ifndef _7ZIP_ST , numThreads #endif ); - if (!IsCopyMethod(oneMethodInfo.MethodName)) - needSolid = true; - CMethodFull methodFull; - - if (!FindMethod( - EXTERNAL_CODECS_VARS - oneMethodInfo.MethodName, methodFull.Id, methodFull.NumInStreams, methodFull.NumOutStreams)) - return E_INVALIDARG; - methodFull.Props = oneMethodInfo.Props; + RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo)); methodMode.Methods.Add(methodFull); - if (!_numSolidBytesDefined) + if (methodFull.Id != k_Copy) + needSolid = true; + + if (_numSolidBytesDefined) + continue; + + UInt32 dicSize; + switch (methodFull.Id) { - for (int j = 0; j < methodFull.Props.Size(); j++) - { - const CProp &prop = methodFull.Props[j]; - if ((prop.Id == NCoderPropID::kDictionarySize || - prop.Id == 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; - } - } + case k_LZMA: + case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break; + case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break; + case k_Deflate: dicSize = (UInt32)1 << 15; break; + case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break; + default: continue; } - } - - if (!needSolid && !_numSolidBytesDefined) - { + _numSolidBytes = (UInt64)dicSize << 7; + if (_numSolidBytes < kSolidBytes_Min) _numSolidBytes = kSolidBytes_Min; + if (_numSolidBytes > kSolidBytes_Max) _numSolidBytes = kSolidBytes_Max; _numSolidBytesDefined = true; - _numSolidBytes = 0; } + + if (!_numSolidBytesDefined) + if (needSolid) + _numSolidBytes = kSolidBytes_Max; + else + _numSolidBytes = 0; + _numSolidBytesDefined = true; return S_OK; } -static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, bool writeTime, PROPID propID, UInt64 &ft, bool &ftDefined) +static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, UInt64 &ft, bool &ftDefined) { - ft = 0; - ftDefined = false; - if (!writeTime) - return S_OK; + // ft = 0; + // ftDefined = false; NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(index, propID, &prop)); if (prop.vt == VT_FILETIME) @@ -181,15 +153,87 @@ static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, bool w } else if (prop.vt != VT_EMPTY) return E_INVALIDARG; + else + { + ft = 0; + ftDefined = false; + } return S_OK; } +/* + +#ifdef _WIN32 +static const wchar_t kDirDelimiter1 = L'\\'; +#endif +static const wchar_t kDirDelimiter2 = L'/'; + +static inline bool IsCharDirLimiter(wchar_t c) +{ + return ( + #ifdef _WIN32 + c == kDirDelimiter1 || + #endif + c == kDirDelimiter2); +} + +static int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex) +{ + CTreeFolder &tf = treeFolders[cur]; + tf.SortIndex = curSortIndex++; + for (int i = 0; i < tf.SubFolders.Size(); i++) + curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex); + tf.SortIndexEnd = curSortIndex; + return curSortIndex; +} + +static int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos) +{ + const CIntVector &subFolders = treeFolders[cur].SubFolders; + int left = 0, right = subFolders.Size(); + insertPos = -1; + for (;;) + { + if (left == right) + { + insertPos = left; + return -1; + } + int mid = (left + right) / 2; + int midFolder = subFolders[mid]; + int compare = CompareFileNames(name, treeFolders[midFolder].Name); + if (compare == 0) + return midFolder; + if (compare < 0) + right = mid; + else + left = mid + 1; + } +} + +static int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name) +{ + int insertPos; + int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos); + if (folderIndex < 0) + { + folderIndex = treeFolders.Size(); + CTreeFolder &newFolder = treeFolders.AddNew(); + newFolder.Parent = cur; + newFolder.Name = name; + treeFolders[cur].SubFolders.Insert(insertPos, folderIndex); + } + // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234; + return folderIndex; +} +*/ + STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) { COM_TRY_BEGIN - const CArchiveDatabaseEx *db = 0; + const CDbEx *db = 0; #ifdef _7Z_VOL if (_volumes.Size() > 1) return E_FAIL; @@ -204,8 +248,35 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt db = &_db; #endif + /* + CMyComPtr<IArchiveGetRawProps> getRawProps; + updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps); + + CUniqBlocks secureBlocks; + secureBlocks.AddUniq(NULL, 0); + + CObjectVector<CTreeFolder> treeFolders; + { + CTreeFolder folder; + folder.Parent = -1; + treeFolders.Add(folder); + } + */ + CObjectVector<CUpdateItem> updateItems; - + + bool need_CTime = (Write_CTime.Def && Write_CTime.Val); + bool need_ATime = (Write_ATime.Def && Write_ATime.Val); + bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def); + if (db) + { + if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); + if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); + if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty(); + } + + UString s; + for (UInt32 i = 0; i < numItems; i++) { Int32 newData, newProps; @@ -221,24 +292,32 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt ui.IsAnti = false; ui.Size = 0; + UString name; + // bool isAltStream = false; if (ui.IndexInArchive != -1) { - if (db == 0 || ui.IndexInArchive >= db->Files.Size()) + if (db == 0 || (unsigned)ui.IndexInArchive >= db->Files.Size()) return E_INVALIDARG; const CFileItem &fi = db->Files[ui.IndexInArchive]; - ui.Name = fi.Name; + if (!ui.NewProps) + { + _db.GetPath(ui.IndexInArchive, name); + } ui.IsDir = fi.IsDir; ui.Size = fi.Size; + // isAltStream = fi.IsAltStream; ui.IsAnti = db->IsItemAnti(ui.IndexInArchive); - - ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime); - ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime); - ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime); + + if (!ui.NewProps) + { + ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime); + ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime); + ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime); + } } if (ui.NewProps) { - bool nameIsDefined; bool folderStatusIsDefined; { NCOM::CPropVariant prop; @@ -253,23 +332,37 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt ui.AttribDefined = true; } } - + // we need MTime to sort files. - RINOK(GetTime(updateCallback, i, WriteCTime, kpidCTime, ui.CTime, ui.CTimeDefined)); - RINOK(GetTime(updateCallback, i, WriteATime, kpidATime, ui.ATime, ui.ATimeDefined)); - RINOK(GetTime(updateCallback, i, true, kpidMTime, ui.MTime, ui.MTimeDefined)); + if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined)); + if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined)); + if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined)); + + /* + if (getRawProps) + { + const void *data; + UInt32 dataSize; + UInt32 propType; + + getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType); + if (dataSize != 0 && propType != NPropDataType::kRaw) + return E_FAIL; + ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize); + } + */ { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidPath, &prop)); if (prop.vt == VT_EMPTY) - nameIsDefined = false; + { + } else if (prop.vt != VT_BSTR) return E_INVALIDARG; else { - ui.Name = NItemName::MakeLegalName(prop.bstrVal); - nameIsDefined = true; + name = NItemName::MakeLegalName(prop.bstrVal); } } { @@ -297,6 +390,19 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt ui.IsAnti = (prop.boolVal != VARIANT_FALSE); } + /* + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop)); + if (prop.vt == VT_EMPTY) + isAltStream = false; + else if (prop.vt != VT_BOOL) + return E_INVALIDARG; + else + isAltStream = (prop.boolVal != VARIANT_FALSE); + } + */ + if (ui.IsAnti) { ui.AttribDefined = false; @@ -304,13 +410,87 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt ui.CTimeDefined = false; ui.ATimeDefined = false; ui.MTimeDefined = false; - + ui.Size = 0; } if (!folderStatusIsDefined && ui.AttribDefined) ui.SetDirStatusFromAttrib(); } + else + { + /* + if (_db.SecureIDs.IsEmpty()) + ui.SecureIndex = secureBlocks.AddUniq(NULL, 0); + else + { + int id = _db.SecureIDs[ui.IndexInArchive]; + size_t offs = _db.SecureOffsets[id]; + size_t size = _db.SecureOffsets[id + 1] - offs; + ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size); + } + */ + } + + /* + { + int folderIndex = 0; + if (_useParents) + { + int j; + s.Empty(); + for (j = 0; j < name.Len(); j++) + { + wchar_t c = name[j]; + if (IsCharDirLimiter(c)) + { + folderIndex = AddFolder(treeFolders, folderIndex, s); + s.Empty(); + continue; + } + s += c; + } + if (isAltStream) + { + int colonPos = s.Find(':'); + if (colonPos < 0) + { + // isAltStream = false; + return E_INVALIDARG; + } + UString mainName = s.Left(colonPos); + int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName); + if (treeFolders[newFolderIndex].UpdateItemIndex < 0) + { + for (int j = updateItems.Size() - 1; j >= 0; j--) + { + CUpdateItem &ui2 = updateItems[j]; + if (ui2.ParentFolderIndex == folderIndex + && ui2.Name == mainName) + { + ui2.TreeFolderIndex = newFolderIndex; + treeFolders[newFolderIndex].UpdateItemIndex = j; + } + } + } + folderIndex = newFolderIndex; + s.Delete(0, colonPos + 1); + } + ui.Name = s; + } + else + ui.Name = name; + ui.IsAltStream = isAltStream; + ui.ParentFolderIndex = folderIndex; + ui.TreeFolderIndex = -1; + if (ui.IsDir && !s.IsEmpty()) + { + ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s); + treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size(); + } + } + */ + ui.Name = name; if (ui.NewData) { @@ -325,8 +505,27 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt updateItems.Add(ui); } + /* + FillSortIndex(treeFolders, 0, 0); + for (i = 0; i < (UInt32)updateItems.Size(); i++) + { + CUpdateItem &ui = updateItems[i]; + ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex; + ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd; + } + */ + CCompressionMethodMode methodMode, headerMethod; - RINOK(SetCompressionMethod(methodMode, headerMethod)); + + HRESULT res = SetMainMethod(methodMode, _methods + #ifndef _7ZIP_ST + , _numThreads + #endif + ); + RINOK(res); + methodMode.Binds = _binds; + + RINOK(SetHeaderMethod(headerMethod)); #ifndef _7ZIP_ST methodMode.NumThreads = _numThreads; headerMethod.NumThreads = 1; @@ -335,17 +534,17 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt CMyComPtr<ICryptoGetTextPassword2> getPassword2; updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2); + methodMode.PasswordIsDefined = false; + methodMode.Password.Empty(); if (getPassword2) { CMyComBSTR password; Int32 passwordIsDefined; RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password)); methodMode.PasswordIsDefined = IntToBool(passwordIsDefined); - if (methodMode.PasswordIsDefined) + if (methodMode.PasswordIsDefined && (BSTR)password) methodMode.Password = password; } - else - methodMode.PasswordIsDefined = false; bool compressMainHeader = _compressHeaders; // check it @@ -373,14 +572,17 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt CUpdateOptions options; options.Method = &methodMode; options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : 0; - options.UseFilters = _level != 0 && _autoFilter; - options.MaxFilter = _level >= 8; + int level = GetLevel(); + options.UseFilters = level != 0 && _autoFilter; + options.MaxFilter = level >= 8; options.HeaderOptions.CompressMainHeader = compressMainHeader; - options.HeaderOptions.WriteCTime = WriteCTime; - options.HeaderOptions.WriteATime = WriteATime; - options.HeaderOptions.WriteMTime = WriteMTime; - + /* + options.HeaderOptions.WriteCTime = Write_CTime; + options.HeaderOptions.WriteATime = Write_ATime; + options.HeaderOptions.WriteMTime = Write_MTime; + */ + options.NumSolidFiles = _numSolidFiles; options.NumSolidBytes = _numSolidBytes; options.SolidExtension = _solidExtension; @@ -388,12 +590,24 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt options.VolumeMode = _volumeMode; COutArchive archive; - CArchiveDatabase newDatabase; + CArchiveDatabaseOut newDatabase; CMyComPtr<ICryptoGetTextPassword> getPassword; updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword); - - HRESULT res = Update( + + /* + if (secureBlocks.Sorted.Size() > 1) + { + secureBlocks.GetReverseMap(); + for (int i = 0; i < updateItems.Size(); i++) + { + int &secureIndex = updateItems[i].SecureIndex; + secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex]; + } + } + */ + + res = Update( EXTERNAL_CODECS_VARS #ifdef _7Z_VOL volume ? volume->Stream: 0, @@ -403,6 +617,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt db, #endif updateItems, + // treeFolders, + // secureBlocks, archive, newDatabase, outStream, updateCallback, options #ifndef _NO_CRYPTO , getPassword @@ -426,7 +642,7 @@ static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream if (index == 0) return E_INVALIDARG; srcString.Delete(0, index); - if (srcString[0] == 'S') + if (srcString[0] == 's') { srcString.Delete(0); int index = ParseStringToUInt32(srcString, stream); @@ -437,38 +653,173 @@ static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream return S_OK; } -static HRESULT GetBindInfo(UString &srcString, CBind &bind) +void COutHandler::InitProps() { - 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; + CMultiMethodProps::Init(); + + _removeSfxBlock = false; + _compressHeaders = true; + _encryptHeadersSpecified = false; + _encryptHeaders = false; + // _useParents = false; + + Write_CTime.Init(); + Write_ATime.Init(); + Write_MTime.Init(); + + _volumeMode = false; + InitSolid(); +} + +HRESULT COutHandler::SetSolidFromString(const UString &s) +{ + UString s2 = s; + s2.MakeLower_Ascii(); + for (unsigned i = 0; i < s2.Len();) + { + 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.Len()) + return E_INVALIDARG; + wchar_t c = s2[i++]; + if (c == 'f') + { + if (v < 1) + v = 1; + _numSolidFiles = v; + } + else + { + unsigned numBits; + switch (c) + { + case 'b': numBits = 0; break; + case 'k': numBits = 10; break; + case 'm': numBits = 20; break; + case 'g': numBits = 30; break; + case 't': numBits = 40; break; + default: return E_INVALIDARG; + } + _numSolidBytes = (v << numBits); + _numSolidBytesDefined = true; + } + } return S_OK; } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) +HRESULT COutHandler::SetSolidFromPROPVARIANT(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 SetSolidFromString(value.bstrVal); + default: return E_INVALIDARG; + } + if (isSolid) + InitSolid(); + else + _numSolidFiles = 1; + return S_OK; +} + +static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest) +{ + RINOK(PROPVARIANT_to_bool(prop, dest.Val)); + dest.Def = true; + return S_OK; +} + +HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) +{ + UString name = nameSpec; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + if (name[0] == L's') + { + name.Delete(0); + if (name.IsEmpty()) + return SetSolidFromPROPVARIANT(value); + if (value.vt != VT_EMPTY) + return E_INVALIDARG; + return SetSolidFromString(name); + } + + UInt32 number; + int index = ParseStringToUInt32(name, number); + UString realName = name.Ptr(index); + if (index == 0) + { + if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock); + if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders); + // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents); + + if (name.IsEqualTo("hcf")) + { + bool compressHeadersFull = true; + RINOK(PROPVARIANT_to_bool(value, compressHeadersFull)); + return compressHeadersFull ? S_OK: E_INVALIDARG; + } + + if (name.IsEqualTo("he")) + { + RINOK(PROPVARIANT_to_bool(value, _encryptHeaders)); + _encryptHeadersSpecified = true; + return S_OK; + } + + if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime); + if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime); + if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime); + + if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode); + } + return CMultiMethodProps::SetProperty(name, value); +} + +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN _binds.Clear(); - BeforeSetProperty(); + InitProps(); - for (int i = 0; i < numProperties; i++) + for (UInt32 i = 0; i < numProps; i++) { UString name = names[i]; - name.MakeUpper(); + name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &value = values[i]; - if (name[0] == 'B') + if (name[0] == 'b') { + if (value.vt != VT_EMPTY) + return E_INVALIDARG; name.Delete(0); CBind bind; - RINOK(GetBindInfo(name, bind)); + RINOK(GetBindInfoPart(name, bind.OutCoder, bind.OutStream)); + if (name[0] != ':') + return E_INVALIDARG; + name.Delete(0); + RINOK(GetBindInfoPart(name, bind.InCoder, bind.InStream)); + if (!name.IsEmpty()) + return E_INVALIDARG; _binds.Add(bind); continue; } @@ -476,6 +827,47 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v RINOK(SetProperty(name, value)); } + unsigned numEmptyMethods = GetNumEmptyMethods(); + if (numEmptyMethods > 0) + { + unsigned k; + for (k = 0; k < _binds.Size(); k++) + { + const CBind &bind = _binds[k]; + if (bind.InCoder < (UInt32)numEmptyMethods || + bind.OutCoder < (UInt32)numEmptyMethods) + return E_INVALIDARG; + } + for (k = 0; k < _binds.Size(); k++) + { + CBind &bind = _binds[k]; + bind.InCoder -= (UInt32)numEmptyMethods; + bind.OutCoder -= (UInt32)numEmptyMethods; + } + _methods.DeleteFrontal(numEmptyMethods); + } + + AddDefaultMethod(); + + if (!_filterMethod.MethodName.IsEmpty()) + { + FOR_VECTOR (k, _binds) + { + CBind &bind = _binds[k]; + bind.InCoder++; + bind.OutCoder++; + } + _methods.Insert(0, _filterMethod); + } + + FOR_VECTOR (k, _binds) + { + const CBind &bind = _binds[k]; + if (bind.InCoder >= (UInt32)_methods.Size() || + bind.OutCoder >= (UInt32)_methods.Size()) + return E_INVALIDARG; + } + return S_OK; COM_TRY_END } |