diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2011-04-11 04:00:00 +0400 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:05 +0300 |
commit | 35596517f203f1c4970413b3b5b2e216b849e462 (patch) | |
tree | 93240df3eb4ddbd8eebbe6a5fc65e93f2ccb6495 /CPP/7zip/Archive | |
parent | de4f8c22fe4b9e59b60495b84db2e81de50999a9 (diff) |
9.219.21
Diffstat (limited to 'CPP/7zip/Archive')
65 files changed, 3599 insertions, 2061 deletions
diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.h b/CPP/7zip/Archive/7z/7zCompressionMode.h index 55bbc68e..5cde97c3 100755 --- a/CPP/7zip/Archive/7z/7zCompressionMode.h +++ b/CPP/7zip/Archive/7z/7zCompressionMode.h @@ -3,19 +3,18 @@ #ifndef __7Z_COMPRESSION_MODE_H #define __7Z_COMPRESSION_MODE_H -#include "../../../Common/MyString.h" - -#include "../../../Windows/PropVariant.h" - +#include "../../Common/MethodId.h" #include "../../Common/MethodProps.h" namespace NArchive { namespace N7z { -struct CMethodFull: public CMethod +struct CMethodFull: public CProps { + CMethodId Id; UInt32 NumInStreams; UInt32 NumOutStreams; + bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); } }; diff --git a/CPP/7zip/Archive/7z/7zEncode.cpp b/CPP/7zip/Archive/7z/7zEncode.cpp index 87996bc0..614f9913 100755 --- a/CPP/7zip/Archive/7z/7zEncode.cpp +++ b/CPP/7zip/Archive/7z/7zEncode.cpp @@ -49,6 +49,15 @@ static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindIn folder.PackStreams.Add(bindInfo.InStreams[i]); } +static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder) +{ + CMyComPtr<ICompressSetCoderProperties> setCoderProperties; + coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties); + if (setCoderProperties) + return props.SetCoderProps(setCoderProperties, dataSizeReduce); + return props.AreThereNonOptionalProps() ? E_INVALIDARG : S_OK; +} + HRESULT CEncoder::CreateMixerCoder( DECL_EXTERNAL_CODECS_LOC_VARS const UInt64 *inSizeForReduce) @@ -86,8 +95,7 @@ HRESULT CEncoder::CreateMixerCoder( } #endif - - RINOK(SetMethodProperties(methodFull, inSizeForReduce, encoderCommon)); + RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon)); /* CMyComPtr<ICryptoResetSalt> resetSalt; diff --git a/CPP/7zip/Archive/7z/7zHandler.cpp b/CPP/7zip/Archive/7z/7zHandler.cpp index 4ab7afa8..93d4f51e 100755 --- a/CPP/7zip/Archive/7z/7zHandler.cpp +++ b/CPP/7zip/Archive/7z/7zHandler.cpp @@ -24,25 +24,20 @@ using namespace NWindows; -extern UString ConvertMethodIdToString(UInt64 id); - namespace NArchive { namespace N7z { CHandler::CHandler() { - _crcSize = 4; - #ifndef _NO_CRYPTO _passwordIsDefined = false; #endif #ifdef EXTRACT_ONLY + _crcSize = 4; #ifdef __7Z_SET_PROPERTIES _numThreads = NSystem::GetNumberOfProcessors(); #endif - #else - Init(); #endif } @@ -70,7 +65,7 @@ STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */, #else -STATPROPSTG kArcProps[] = +static const STATPROPSTG kArcProps[] = { { NULL, kpidMethod, VT_BSTR}, { NULL, kpidSolid, VT_BOOL}, @@ -80,6 +75,25 @@ STATPROPSTG kArcProps[] = { NULL, kpidOffset, VT_UI8} }; +static inline wchar_t GetHex(Byte value) +{ + return (wchar_t)((value < 10) ? ('0' + value) : ('A' + (value - 10))); +} + +static UString ConvertMethodIdToString(UInt64 id) +{ + wchar_t s[32]; + int len = 32; + s[--len] = 0; + do + { + s[--len] = GetHex((Byte)id & 0xF); id >>= 4; + s[--len] = GetHex((Byte)id & 0xF); id >>= 4; + } + while (id != 0); + return s + len; +} + STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN @@ -172,22 +186,18 @@ static UString GetStringForSizeValue(UInt32 value) return result; } -static const UInt64 k_Copy = 0x0; -static const UInt64 k_Delta = 3; -static const UInt64 k_LZMA2 = 0x21; -static const UInt64 k_LZMA = 0x030101; -static const UInt64 k_PPMD = 0x030401; - -static wchar_t GetHex(Byte value) -{ - return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10))); -} static inline void AddHexToString(UString &res, Byte value) { res += GetHex((Byte)(value >> 4)); res += GetHex((Byte)(value & 0xF)); } +static void AddProp32(UString &s, const wchar_t *name, UInt32 v) +{ + s += name; + s += ConvertUInt32ToString(v); +} + #endif bool CHandler::IsEncrypted(UInt32 index2) const @@ -283,6 +293,14 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va { UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1); propsString = GetStringForSizeValue(dicSize); + UInt32 d = coder.Props[0]; + UInt32 lc = d % 9; + d /= 9; + UInt32 pb = d / 5; + UInt32 lp = d % 5; + if (lc != 3) AddProp32(propsString, L":lc", lc); + if (lp != 0) AddProp32(propsString, L":lp", lp); + if (pb != 2) AddProp32(propsString, L":pb", pb); } else if (coder.MethodID == k_LZMA2 && coder.Props.GetCapacity() == 1) { diff --git a/CPP/7zip/Archive/7z/7zHandler.h b/CPP/7zip/Archive/7z/7zHandler.h index 56062d46..247b55f7 100755 --- a/CPP/7zip/Archive/7z/7zHandler.h +++ b/CPP/7zip/Archive/7z/7zHandler.h @@ -18,6 +18,16 @@ namespace NArchive { namespace N7z { +const UInt32 k_Copy = 0x0; +const UInt32 k_Delta = 3; +const UInt32 k_LZMA2 = 0x21; +const UInt32 k_LZMA = 0x030101; +const UInt32 k_PPMD = 0x030401; +const UInt32 k_BCJ = 0x03030103; +const UInt32 k_BCJ2 = 0x0303011B; +const UInt32 k_Deflate = 0x040108; +const UInt32 k_BZip2 = 0x040202; + #ifndef __7Z_SET_PROPERTIES #ifdef EXTRACT_ONLY @@ -31,9 +41,52 @@ namespace N7z { #endif +#ifndef EXTRACT_ONLY + +class COutHandler: public CMultiMethodProps +{ + HRESULT SetSolidFromString(const UString &s); + HRESULT SetSolidFromPROPVARIANT(const PROPVARIANT &value); +public: + bool _removeSfxBlock; + + UInt64 _numSolidFiles; + UInt64 _numSolidBytes; + bool _numSolidBytesDefined; + bool _solidExtension; + + bool _compressHeaders; + bool _encryptHeadersSpecified; + bool _encryptHeaders; + + bool WriteCTime; + bool WriteATime; + bool WriteMTime; + + bool _volumeMode; + + void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); } + void InitSolidSize() { _numSolidBytes = (UInt64)(Int64)(-1); } + void InitSolid() + { + InitSolidFiles(); + InitSolidSize(); + _solidExtension = false; + _numSolidBytesDefined = false; + } + + void InitProps(); + + COutHandler() { InitProps(); } + + HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); +}; + +#endif + class CHandler: #ifndef EXTRACT_ONLY - public NArchive::COutHandler, + public COutHandler, #endif public IInArchive, #ifdef __7Z_SET_PROPERTIES @@ -90,16 +143,16 @@ private: CRecordVector<CBind> _binds; - HRESULT SetCompressionMethod(CCompressionMethodMode &method, + HRESULT PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m); + HRESULT SetHeaderMethod(CCompressionMethodMode &headerMethod); + void AddDefaultMethod(); + HRESULT SetMainMethod(CCompressionMethodMode &method, CObjectVector<COneMethodInfo> &methodsInfo #ifndef _7ZIP_ST , UInt32 numThreads #endif ); - HRESULT SetCompressionMethod( - CCompressionMethodMode &method, - CCompressionMethodMode &headerMethod); #endif diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp index a8ccab6d..dd73ee84 100755 --- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp +++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp @@ -2,13 +2,9 @@ #include "StdAfx.h" -#include "../../../Windows/PropVariant.h" - #include "../../../Common/ComTry.h" #include "../../../Common/StringToInt.h" -#include "../../ICoder.h" - #include "../Common/ItemNameUtils.h" #include "../Common/ParseProperties.h" @@ -21,24 +17,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 = k_LZMA_Name; +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,123 +37,105 @@ 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 (int i = 0; i < _methods.Size(); i++) + { + UString &methodName = _methods[0].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 (int i = 0; i < methods.Size(); i++) { - 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; } @@ -326,7 +299,16 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt } 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; @@ -373,8 +355,9 @@ 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; @@ -393,7 +376,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt CMyComPtr<ICryptoGetTextPassword> getPassword; updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword); - HRESULT res = Update( + res = Update( EXTERNAL_CODECS_VARS #ifdef _7Z_VOL volume ? volume->Stream: 0, @@ -437,25 +420,138 @@ 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; + + WriteCTime = false; + WriteATime = false; + WriteMTime = true; + + _volumeMode = false; + InitSolid(); +} + +HRESULT COutHandler::SetSolidFromString(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++]; + 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; + default: return E_INVALIDARG; + } + _numSolidBytes = (v << numBits); + _numSolidBytesDefined = true; + } + } + return S_OK; +} + +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; } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) +HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) +{ + UString name = nameSpec; + name.MakeUpper(); + 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.Mid(index); + if (index == 0) + { + if (name.CompareNoCase(L"RSFX") == 0) return PROPVARIANT_to_bool(value, _removeSfxBlock); + if (name.CompareNoCase(L"HC") == 0) return PROPVARIANT_to_bool(value, _compressHeaders); + if (name.CompareNoCase(L"HCF") == 0) + { + bool compressHeadersFull = true; + RINOK(PROPVARIANT_to_bool(value, compressHeadersFull)); + return compressHeadersFull ? S_OK: E_INVALIDARG; + } + if (name.CompareNoCase(L"HE") == 0) + { + RINOK(PROPVARIANT_to_bool(value, _encryptHeaders)); + _encryptHeadersSpecified = true; + return S_OK; + } + if (name.CompareNoCase(L"TC") == 0) return PROPVARIANT_to_bool(value, WriteCTime); + if (name.CompareNoCase(L"TA") == 0) return PROPVARIANT_to_bool(value, WriteATime); + if (name.CompareNoCase(L"TM") == 0) return PROPVARIANT_to_bool(value, WriteMTime); + if (name.CompareNoCase(L"V") == 0) return PROPVARIANT_to_bool(value, _volumeMode); + } + return CMultiMethodProps::SetProperty(name, value); +} + +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) { COM_TRY_BEGIN _binds.Clear(); - BeforeSetProperty(); + InitProps(); - for (int i = 0; i < numProperties; i++) + for (int i = 0; i < numProps; i++) { UString name = names[i]; name.MakeUpper(); @@ -466,9 +562,17 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v 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 +580,47 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v RINOK(SetProperty(name, value)); } + int numEmptyMethods = GetNumEmptyMethods(); + if (numEmptyMethods > 0) + { + int 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.Delete(0, numEmptyMethods); + } + + AddDefaultMethod(); + + if (!_filterMethod.MethodName.IsEmpty()) + { + for (int k = 0; k < _binds.Size(); k++) + { + CBind &bind = _binds[k]; + bind.InCoder++; + bind.OutCoder++; + } + _methods.Insert(0, _filterMethod); + } + + for (int k = 0; k < _binds.Size(); k++) + { + 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 } diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp index 0feb81d2..fd751a74 100755 --- a/CPP/7zip/Archive/7z/7zIn.cpp +++ b/CPP/7zip/Archive/7z/7zIn.cpp @@ -317,7 +317,6 @@ HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *search const UInt32 kBufferSize = (1 << 16); byteBuffer.SetCapacity(kBufferSize); Byte *buffer = byteBuffer; - UInt32 numPrevBytes = kHeaderSize; memcpy(buffer, _header, kHeaderSize); UInt64 curTestPos = _arhiveBeginStreamPosition; for (;;) @@ -325,21 +324,14 @@ HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *search if (searchHeaderSizeLimit != NULL) if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit) break; - do - { - UInt32 numReadBytes = kBufferSize - numPrevBytes; - UInt32 processedSize; - RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize)); - numPrevBytes += processedSize; - if (processedSize == 0) - return S_FALSE; - } - while (numPrevBytes <= kHeaderSize); - UInt32 numTests = numPrevBytes - kHeaderSize; - for (UInt32 pos = 0; pos < numTests; pos++) + UInt32 processedSize; + RINOK(stream->Read(buffer + kHeaderSize, kBufferSize - kHeaderSize, &processedSize)); + if (processedSize == 0) + return S_FALSE; + for (UInt32 pos = 1; pos <= processedSize; pos++) { - for (; buffer[pos] != '7' && pos < numTests; pos++); - if (pos == numTests) + for (; buffer[pos] != '7' && pos <= processedSize; pos++); + if (pos > processedSize) break; if (TestSignature(buffer + pos)) { @@ -349,9 +341,8 @@ HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *search return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL); } } - curTestPos += numTests; - numPrevBytes -= numTests; - memmove(buffer, buffer + numTests, numPrevBytes); + curTestPos += processedSize; + memmove(buffer, buffer + processedSize, kHeaderSize); } return S_FALSE; } @@ -362,6 +353,8 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) HeadersSize = 0; Close(); RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition)) + RINOK(stream->Seek(0, STREAM_SEEK_END, &_fileEndPosition)) + RINOK(stream->Seek(_arhiveBeginStreamPosition, STREAM_SEEK_SET, NULL)) RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit)); _stream = stream; return S_OK; @@ -1194,12 +1187,14 @@ HRESULT CInArchive::ReadDatabase2( if (nextHeaderSize == 0) return S_OK; - if (nextHeaderSize > (UInt64)0xFFFFFFFF) + if (nextHeaderSize > (UInt64)(UInt32)0xFFFFFFFF) return S_FALSE; if ((Int64)nextHeaderOffset < 0) return S_FALSE; + if (db.ArchiveInfo.StartPositionAfterHeader + nextHeaderOffset > _fileEndPosition) + return S_FALSE; RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL)); CByteBuffer buffer2; diff --git a/CPP/7zip/Archive/7z/7zIn.h b/CPP/7zip/Archive/7z/7zIn.h index 971f27b2..4305a8c5 100755 --- a/CPP/7zip/Archive/7z/7zIn.h +++ b/CPP/7zip/Archive/7z/7zIn.h @@ -133,6 +133,7 @@ class CInArchive CInByte2 *_inByteBack; UInt64 _arhiveBeginStreamPosition; + UInt64 _fileEndPosition; Byte _header[kHeaderSize]; diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp index ee7f55c0..e63b09d2 100755 --- a/CPP/7zip/Archive/7z/7zUpdate.cpp +++ b/CPP/7zip/Archive/7z/7zUpdate.cpp @@ -24,15 +24,6 @@ namespace NArchive { namespace N7z { -static const UInt64 k_LZMA = 0x030101; -static const UInt64 k_BCJ = 0x03030103; -static const UInt64 k_BCJ2 = 0x0303011B; - -static const wchar_t *kMatchFinderForBCJ2_LZMA = L"BT2"; -static const UInt32 kDictionaryForBCJ2_LZMA = 1 << 20; -static const UInt32 kAlgorithmForBCJ2_LZMA = 1; -static const UInt32 kNumFastBytesForBCJ2_LZMA = 64; - #ifdef MY_CPU_X86_OR_AMD64 #define USE_86_FILTER #endif @@ -339,90 +330,74 @@ static bool IsExeExt(const UString &ext) return false; } -#ifdef USE_86_FILTER -static inline void GetMethodFull(UInt64 methodID, UInt32 numInStreams, CMethodFull &methodResult) +static inline void GetMethodFull(UInt64 methodID, UInt32 numInStreams, CMethodFull &m) { - methodResult.Id = methodID; - methodResult.NumInStreams = numInStreams; - methodResult.NumOutStreams = 1; + m.Id = methodID; + m.NumInStreams = numInStreams; + m.NumOutStreams = 1; +} + +static void AddBcj2Methods(CCompressionMethodMode &mode) +{ + CMethodFull m; + GetMethodFull(k_LZMA, 1, m); + + m.AddProp32(NCoderPropID::kDictionarySize, 1 << 20); + m.AddProp32(NCoderPropID::kNumFastBytes, 128); + m.AddProp32(NCoderPropID::kNumThreads, 1); + m.AddProp32(NCoderPropID::kLitPosBits, 2); + m.AddProp32(NCoderPropID::kLitContextBits, 0); + // m.AddPropString(NCoderPropID::kMatchFinder, L"BT2"); + + mode.Methods.Add(m); + mode.Methods.Add(m); + + CBind bind; + bind.OutCoder = 0; + bind.InStream = 0; + bind.InCoder = 1; bind.OutStream = 0; mode.Binds.Add(bind); + bind.InCoder = 2; bind.OutStream = 1; mode.Binds.Add(bind); + bind.InCoder = 3; bind.OutStream = 2; mode.Binds.Add(bind); } -static void MakeExeMethod(const CCompressionMethodMode &method, - bool bcj2Filter, CCompressionMethodMode &exeMethod) +static void MakeExeMethod(CCompressionMethodMode &mode, + bool useFilters, bool addFilter, bool bcj2Filter) { - exeMethod = method; + if (!mode.Binds.IsEmpty() || !useFilters || mode.Methods.Size() > 2) + return; + if (mode.Methods.Size() == 2) + { + if (mode.Methods[0].Id == k_BCJ2) + AddBcj2Methods(mode); + return; + } + if (!addFilter) + return; + bcj2Filter = bcj2Filter; + #ifdef USE_86_FILTER if (bcj2Filter) { - CMethodFull methodFull; - GetMethodFull(k_BCJ2, 4, methodFull); - exeMethod.Methods.Insert(0, methodFull); - GetMethodFull(k_LZMA, 1, methodFull); - { - CProp prop; - prop.Id = NCoderPropID::kAlgorithm; - prop.Value = kAlgorithmForBCJ2_LZMA; - methodFull.Props.Add(prop); - } - { - CProp prop; - prop.Id = NCoderPropID::kMatchFinder; - prop.Value = kMatchFinderForBCJ2_LZMA; - methodFull.Props.Add(prop); - } - { - CProp prop; - prop.Id = NCoderPropID::kDictionarySize; - prop.Value = kDictionaryForBCJ2_LZMA; - methodFull.Props.Add(prop); - } - { - CProp prop; - prop.Id = NCoderPropID::kNumFastBytes; - prop.Value = kNumFastBytesForBCJ2_LZMA; - methodFull.Props.Add(prop); - } - { - CProp prop; - prop.Id = NCoderPropID::kNumThreads; - prop.Value = (UInt32)1; - methodFull.Props.Add(prop); - } - - exeMethod.Methods.Add(methodFull); - exeMethod.Methods.Add(methodFull); - CBind bind; - - bind.OutCoder = 0; - bind.InStream = 0; - - bind.InCoder = 1; - bind.OutStream = 0; - exeMethod.Binds.Add(bind); - - bind.InCoder = 2; - bind.OutStream = 1; - exeMethod.Binds.Add(bind); - - bind.InCoder = 3; - bind.OutStream = 2; - exeMethod.Binds.Add(bind); + CMethodFull m; + GetMethodFull(k_BCJ2, 4, m); + mode.Methods.Insert(0, m); + AddBcj2Methods(mode); } else { - CMethodFull methodFull; - GetMethodFull(k_BCJ, 1, methodFull); - exeMethod.Methods.Insert(0, methodFull); + CMethodFull m; + GetMethodFull(k_BCJ, 1, m); + mode.Methods.Insert(0, m); CBind bind; bind.OutCoder = 0; bind.InStream = 0; bind.InCoder = 1; bind.OutStream = 0; - exeMethod.Binds.Add(bind); + mode.Binds.Add(bind); } + #endif } -#endif static void FromUpdateItemToFileItem(const CUpdateItem &ui, CFileItem &file, CFileItem2 &file2) @@ -601,6 +576,7 @@ public: Fos = FosSpec; Result = E_FAIL; } + ~CThreadDecoder() { CVirtThread::WaitThreadFinish(); } virtual void Execute(); }; @@ -669,9 +645,7 @@ STDMETHODIMP CCryptoGetTextPassword::CryptoGetTextPassword(BSTR *password) static const int kNumGroupsMax = 4; -#ifdef USE_86_FILTER static bool Is86Group(int group) { return (group & 1) != 0; } -#endif static bool IsEncryptedGroup(int group) { return (group & 2) != 0; } static int GetGroupIndex(bool encrypted, int bcjFiltered) { return (encrypted ? 2 : 0) + (bcjFiltered ? 1 : 0); } @@ -789,16 +763,15 @@ HRESULT Update( if (inSizeForReduce2 > inSizeForReduce) inSizeForReduce = inSizeForReduce2; - const UInt32 kMinReduceSize = (1 << 16); - if (inSizeForReduce < kMinReduceSize) - inSizeForReduce = kMinReduceSize; - RINOK(updateCallback->SetTotal(complexity)); CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(updateCallback, true); + CStreamBinder sb; + RINOK(sb.CreateEvents()); + CThreadDecoder threadDecoder; if (!folderRefs.IsEmpty()) { @@ -870,13 +843,8 @@ HRESULT Update( { const CSolidGroup &group = groups[groupIndex]; - CCompressionMethodMode method; - #ifdef USE_86_FILTER - if (Is86Group(groupIndex)) - MakeExeMethod(*options.Method, options.MaxFilter, method); - else - #endif - method = *options.Method; + CCompressionMethodMode method = *options.Method; + MakeExeMethod(method, options.UseFilters, Is86Group(groupIndex), options.MaxFilter); if (IsEncryptedGroup(groupIndex)) { @@ -923,11 +891,6 @@ HRESULT Update( } else { - CStreamBinder sb; - RINOK(sb.CreateEvents()); - CMyComPtr<ISequentialOutStream> sbOutStream; - CMyComPtr<ISequentialInStream> sbInStream; - sb.CreateStreams(&sbInStream, &sbOutStream); CBoolVector extractStatuses; CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex]; @@ -946,24 +909,31 @@ HRESULT Update( extractStatuses.Add(needExtract); } - RINOK(threadDecoder.FosSpec->Init(db, db->FolderStartFileIndex[folderIndex], &extractStatuses, sbOutStream)); - sbOutStream.Release(); - - threadDecoder.InStream = inStream; - threadDecoder.Folder = &db->Folders[folderIndex]; - threadDecoder.StartPos = db->GetFolderStreamPos(folderIndex, 0); - threadDecoder.PackSizes = &db->PackSizes[db->FolderStartPackStreamIndex[folderIndex]]; - - threadDecoder.Start(); - int startPackIndex = newDatabase.PackSizes.Size(); CFolder newFolder; - RINOK(encoder.Encode( - EXTERNAL_CODECS_LOC_VARS - sbInStream, NULL, &inSizeForReduce, newFolder, - archive.SeqStream, newDatabase.PackSizes, progress)); - - threadDecoder.WaitFinish(); + { + CMyComPtr<ISequentialInStream> sbInStream; + { + CMyComPtr<ISequentialOutStream> sbOutStream; + sb.CreateStreams(&sbInStream, &sbOutStream); + sb.ReInit(); + RINOK(threadDecoder.FosSpec->Init(db, db->FolderStartFileIndex[folderIndex], &extractStatuses, sbOutStream)); + } + + threadDecoder.InStream = inStream; + threadDecoder.Folder = &db->Folders[folderIndex]; + threadDecoder.StartPos = db->GetFolderStreamPos(folderIndex, 0); + threadDecoder.PackSizes = &db->PackSizes[db->FolderStartPackStreamIndex[folderIndex]]; + + threadDecoder.Start(); + + RINOK(encoder.Encode( + EXTERNAL_CODECS_LOC_VARS + sbInStream, NULL, &inSizeForReduce, newFolder, + archive.SeqStream, newDatabase.PackSizes, progress)); + + threadDecoder.WaitExecuteFinish(); + } RINOK(threadDecoder.Result); @@ -1134,6 +1104,8 @@ HRESULT Update( if (folderRefIndex != folderRefs.Size()) return E_FAIL; + RINOK(lps->SetCur()); + /* folderRefs.ClearAndFree(); fileIndexToUpdateIndexMap.ClearAndFree(); @@ -1169,7 +1141,7 @@ HRESULT Update( newDatabase.AddFile(file, file2); } } - + newDatabase.ReserveDown(); return S_OK; } diff --git a/CPP/7zip/Archive/Bz2Handler.cpp b/CPP/7zip/Archive/Bz2Handler.cpp index 98cbcc18..49ae8c79 100755 --- a/CPP/7zip/Archive/Bz2Handler.cpp +++ b/CPP/7zip/Archive/Bz2Handler.cpp @@ -4,13 +4,6 @@ #include "Common/ComTry.h" -#include "Windows/PropVariant.h" - -#ifndef _7ZIP_ST -#include "../../Windows/System.h" -#endif - -#include "../Common/CreateCoder.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" @@ -20,21 +13,13 @@ #include "../Compress/CopyCoder.h" #include "Common/DummyOutStream.h" -#include "Common/ParseProperties.h" +#include "Common/HandlerOut.h" using namespace NWindows; namespace NArchive { namespace NBz2 { -static const UInt32 kNumPassesX1 = 1; -static const UInt32 kNumPassesX7 = 2; -static const UInt32 kNumPassesX9 = 7; - -static const UInt32 kDicSizeX1 = 100000; -static const UInt32 kDicSizeX3 = 500000; -static const UInt32 kDicSizeX5 = 900000; - class CHandler: public IInArchive, public IArchiveOpenSeq, @@ -48,22 +33,7 @@ class CHandler: UInt64 _startPosition; bool _packSizeDefined; - UInt32 _level; - UInt32 _dicSize; - UInt32 _numPasses; - #ifndef _7ZIP_ST - UInt32 _numThreads; - #endif - - void InitMethodProperties() - { - _level = 5; - _dicSize = - _numPasses = 0xFFFFFFFF; - #ifndef _7ZIP_ST - _numThreads = NWindows::NSystem::GetNumberOfProcessors();; - #endif - } + CSingleMethodProps _props; public: MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties) @@ -73,10 +43,10 @@ public: STDMETHOD(OpenSeq)(ISequentialInStream *stream); STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps); - CHandler() { InitMethodProperties(); } + CHandler() { } }; -STATPROPSTG kProps[] = +static const STATPROPSTG kProps[] = { { NULL, kpidPackSize, VT_UI8} }; @@ -87,7 +57,7 @@ IMP_IInArchive_ArcProps_NO_Table STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidPhySize: if (_packSizeDefined) prop = _packSize; break; } @@ -104,7 +74,7 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { NWindows::NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidPackSize: if (_packSizeDefined) prop = _packSize; break; } @@ -188,7 +158,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, decoderSpec->SetInStream(_seqStream); #ifndef _7ZIP_ST - RINOK(decoderSpec->SetNumberOfThreads(_numThreads)); + RINOK(decoderSpec->SetNumberOfThreads(_props._numThreads)); #endif CDummyOutStream *outStreamSpec = new CDummyOutStream; @@ -246,50 +216,19 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, static HRESULT UpdateArchive( UInt64 unpackSize, ISequentialOutStream *outStream, - int indexInClient, - UInt32 dictionary, - UInt32 numPasses, - #ifndef _7ZIP_ST - UInt32 numThreads, - #endif + const CProps &props, IArchiveUpdateCallback *updateCallback) { RINOK(updateCallback->SetTotal(unpackSize)); - UInt64 complexity = 0; - RINOK(updateCallback->SetCompleted(&complexity)); - CMyComPtr<ISequentialInStream> fileInStream; - - RINOK(updateCallback->GetStream(indexInClient, &fileInStream)); - + RINOK(updateCallback->GetStream(0, &fileInStream)); CLocalProgress *localProgressSpec = new CLocalProgress; CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec; localProgressSpec->Init(updateCallback, true); - NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder; CMyComPtr<ICompressCoder> encoder = encoderSpec; - { - NWindows::NCOM::CPropVariant properties[] = - { - dictionary, - numPasses - #ifndef _7ZIP_ST - , numThreads - #endif - }; - PROPID propIDs[] = - { - NCoderPropID::kDictionarySize, - NCoderPropID::kNumPasses - #ifndef _7ZIP_ST - , NCoderPropID::kNumThreads - #endif - }; - RINOK(encoderSpec->SetCoderProperties(propIDs, properties, sizeof(propIDs) / sizeof(propIDs[0]))); - } - + RINOK(props.SetCoderProps(encoderSpec, NULL)); RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); - return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); } @@ -336,25 +275,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return E_INVALIDARG; size = prop.uhVal.QuadPart; } - - UInt32 dicSize = _dicSize; - if (dicSize == 0xFFFFFFFF) - dicSize = (_level >= 5 ? kDicSizeX5 : - (_level >= 3 ? kDicSizeX3 : - kDicSizeX1)); - - UInt32 numPasses = _numPasses; - if (numPasses == 0xFFFFFFFF) - numPasses = (_level >= 9 ? kNumPassesX9 : - (_level >= 7 ? kNumPassesX7 : - kNumPassesX1)); - - return UpdateArchive( - size, outStream, 0, dicSize, numPasses, - #ifndef _7ZIP_ST - _numThreads, - #endif - updateCallback); + return UpdateArchive(size, outStream, _props, updateCallback); } if (indexInArchive != 0) return E_INVALIDARG; @@ -365,47 +286,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) { - InitMethodProperties(); - #ifndef _7ZIP_ST - const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); - _numThreads = numProcessors; - #endif - - for (int i = 0; i < numProps; i++) - { - UString name = names[i]; - name.MakeUpper(); - if (name.IsEmpty()) - return E_INVALIDARG; - const PROPVARIANT &prop = values[i]; - if (name[0] == L'X') - { - UInt32 level = 9; - RINOK(ParsePropValue(name.Mid(1), prop, level)); - _level = level; - } - else if (name[0] == L'D') - { - UInt32 dicSize = kDicSizeX5; - RINOK(ParsePropDictionaryValue(name.Mid(1), prop, dicSize)); - _dicSize = dicSize; - } - else if (name.Left(4) == L"PASS") - { - UInt32 num = kNumPassesX9; - RINOK(ParsePropValue(name.Mid(4), prop, num)); - _numPasses = num; - } - else if (name.Left(2) == L"MT") - { - #ifndef _7ZIP_ST - RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _numThreads)); - #endif - } - else - return E_INVALIDARG; - } - return S_OK; + return _props.SetProperties(names, values, numProps); } static IInArchive *CreateArc() { return new CHandler; } diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp index 20f670d3..fd707fe5 100755 --- a/CPP/7zip/Archive/Cab/CabHandler.cpp +++ b/CPP/7zip/Archive/Cab/CabHandler.cpp @@ -4,9 +4,7 @@ #include "../../../../C/Alloc.h" -#include "Common/Buffer.h" #include "Common/ComTry.h" -#include "Common/Defs.h" #include "Common/IntToString.h" #include "Common/StringConvert.h" #include "Common/UTFConvert.h" @@ -654,7 +652,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, bool allFilesMode = (numItems == (UInt32)-1); if (allFilesMode) numItems = m_Database.Items.Size(); - if(numItems == 0) + if (numItems == 0) return S_OK; bool testMode = (testModeSpec != 0); UInt64 totalUnPacked = 0; @@ -780,12 +778,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, curUnpack, extractCallback, testMode); cabBlockInStreamSpec->MsZip = false; + HRESULT res = S_OK; switch(folder.GetCompressionMethod()) { case NHeader::NCompressionMethodMajor::kNone: break; case NHeader::NCompressionMethodMajor::kMSZip: - if(deflateDecoderSpec == NULL) + if (!deflateDecoder) { deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder; deflateDecoder = deflateDecoderSpec; @@ -793,33 +792,35 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, cabBlockInStreamSpec->MsZip = true; break; case NHeader::NCompressionMethodMajor::kLZX: - if(lzxDecoderSpec == NULL) + if (!lzxDecoder) { lzxDecoderSpec = new NCompress::NLzx::CDecoder; lzxDecoder = lzxDecoderSpec; } - RINOK(lzxDecoderSpec->SetParams(folder.CompressionTypeMinor)); + res = lzxDecoderSpec->SetParams(folder.CompressionTypeMinor); break; case NHeader::NCompressionMethodMajor::kQuantum: - if(quantumDecoderSpec == NULL) + if (!quantumDecoder) { quantumDecoderSpec = new NCompress::NQuantum::CDecoder; quantumDecoder = quantumDecoderSpec; } - quantumDecoderSpec->SetParams(folder.CompressionTypeMinor); + res = quantumDecoderSpec->SetParams(folder.CompressionTypeMinor); break; default: - { - RINOK(cabFolderOutStream->Unsupported()); - totalUnPacked += curUnpack; - continue; - } + res = E_INVALIDARG; + break; } - cabBlockInStreamSpec->InitForNewFolder(); - - HRESULT res = S_OK; + if (res == E_INVALIDARG) + { + RINOK(cabFolderOutStream->Unsupported()); + totalUnPacked += curUnpack; + continue; + } + RINOK(res); + cabBlockInStreamSpec->InitForNewFolder(); { int volIndex = mvItem.VolumeIndex; int locFolderIndex = item.GetFolderIndex(db.Folders.Size()); diff --git a/CPP/7zip/Archive/Chm/ChmIn.h b/CPP/7zip/Archive/Chm/ChmIn.h index 4719a484..4b1ac7a6 100755 --- a/CPP/7zip/Archive/Chm/ChmIn.h +++ b/CPP/7zip/Archive/Chm/ChmIn.h @@ -39,7 +39,7 @@ struct CItem { if (Name.Length() == 0) return false; - return (Name[Name.Length() - 1] == '/'); + return (Name.Back() == '/'); } }; diff --git a/CPP/7zip/Archive/Common/CoderMixer2MT.cpp b/CPP/7zip/Archive/Common/CoderMixer2MT.cpp index d76450bd..87686e85 100755 --- a/CPP/7zip/Archive/Common/CoderMixer2MT.cpp +++ b/CPP/7zip/Archive/Common/CoderMixer2MT.cpp @@ -214,7 +214,7 @@ STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams, for (i = 0; i < _coders.Size(); i++) if (i != _progressCoderIndex) - _coders[i].WaitFinish(); + _coders[i].WaitExecuteFinish(); RINOK(ReturnIfError(E_ABORT)); RINOK(ReturnIfError(E_OUTOFMEMORY)); diff --git a/CPP/7zip/Archive/Common/CoderMixer2MT.h b/CPP/7zip/Archive/Common/CoderMixer2MT.h index d1c7f4d0..81bb3f0b 100755 --- a/CPP/7zip/Archive/Common/CoderMixer2MT.h +++ b/CPP/7zip/Archive/Common/CoderMixer2MT.h @@ -19,6 +19,7 @@ struct CCoder2: public CCoderInfo2, public CVirtThread CRecordVector<ISequentialOutStream*> OutStreamPointers; CCoder2(UInt32 numInStreams, UInt32 numOutStreams); + ~CCoder2() { CVirtThread::WaitThreadFinish(); } void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes); virtual void Execute(); void Code(ICompressProgressInfo *progress); diff --git a/CPP/7zip/Archive/Common/CoderMixer2ST.cpp b/CPP/7zip/Archive/Common/CoderMixer2ST.cpp index a59ce5fc..a21ca0c0 100755 --- a/CPP/7zip/Archive/Common/CoderMixer2ST.cpp +++ b/CPP/7zip/Archive/Common/CoderMixer2ST.cpp @@ -4,7 +4,7 @@ #include "CoderMixer2ST.h" -namespace NCoderMixer2 { +namespace NCoderMixer { CCoderMixer2ST::CCoderMixer2ST() {} @@ -42,7 +42,7 @@ HRESULT CCoderMixer2ST::GetInStream( { CMyComPtr<ISequentialInStream> seqInStream; int i; - for(i = 0; i < _bindInfo.InStreams.Size(); i++) + for (i = 0; i < _bindInfo.InStreams.Size(); i++) if (_bindInfo.InStreams[i] == streamIndex) { seqInStream = inStreams[i]; @@ -57,7 +57,7 @@ HRESULT CCoderMixer2ST::GetInStream( _bindInfo.FindOutStream(_bindInfo.BindPairs[binderIndex].OutIndex, coderIndex, coderStreamIndex); - CCoderInfo &coder = _coders[coderIndex]; + CCoderInfo2 &coder = _coders[coderIndex]; if (!coder.Coder) return E_NOTIMPL; coder.Coder.QueryInterface(IID_ISequentialInStream, &seqInStream); @@ -91,7 +91,7 @@ HRESULT CCoderMixer2ST::GetOutStream( { CMyComPtr<ISequentialOutStream> seqOutStream; int i; - for(i = 0; i < _bindInfo.OutStreams.Size(); i++) + for (i = 0; i < _bindInfo.OutStreams.Size(); i++) if (_bindInfo.OutStreams[i] == streamIndex) { seqOutStream = outStreams[i]; @@ -106,7 +106,7 @@ HRESULT CCoderMixer2ST::GetOutStream( _bindInfo.FindInStream(_bindInfo.BindPairs[binderIndex].InIndex, coderIndex, coderStreamIndex); - CCoderInfo &coder = _coders[coderIndex]; + CCoderInfo2 &coder = _coders[coderIndex]; if (!coder.Coder) return E_NOTIMPL; coder.Coder.QueryInterface(IID_ISequentialOutStream, &seqOutStream); @@ -169,7 +169,7 @@ STDMETHODIMP CCoderMixer2ST::Code(ISequentialInStream **inStreams, // _mainCoderIndex = 0; // _mainCoderIndex = _coders.Size() - 1; - CCoderInfo &mainCoder = _coders[_mainCoderIndex]; + CCoderInfo2 &mainCoder = _coders[_mainCoderIndex]; CObjectVector< CMyComPtr<ISequentialInStream> > seqInStreams; CObjectVector< CMyComPtr<ISequentialOutStream> > seqOutStreams; @@ -198,7 +198,7 @@ STDMETHODIMP CCoderMixer2ST::Code(ISequentialInStream **inStreams, { if (i == _mainCoderIndex) continue; - CCoderInfo &coder = _coders[i]; + CCoderInfo2 &coder = _coders[i]; CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize; coder.Coder.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize); if (setOutStreamSize) diff --git a/CPP/7zip/Archive/Common/CoderMixer2ST.h b/CPP/7zip/Archive/Common/CoderMixer2ST.h index a4ea7e80..d35655ba 100755 --- a/CPP/7zip/Archive/Common/CoderMixer2ST.h +++ b/CPP/7zip/Archive/Common/CoderMixer2ST.h @@ -7,7 +7,7 @@ #include "../../../Common/MyCom.h" #include "../../ICoder.h" -namespace NCoderMixer2 { +namespace NCoderMixer { // SetBindInfo() // for each coder @@ -26,11 +26,11 @@ namespace NCoderMixer2 { // Code // } -struct CSTCoderInfo: public CCoderInfo +struct CSTCoderInfo: public CCoderInfo2 { bool IsMain; CSTCoderInfo(UInt32 numInStreams, UInt32 numOutStreams, bool isMain): - CCoderInfo(numInStreams, numOutStreams),IsMain(isMain) {} + CCoderInfo2(numInStreams, numOutStreams), IsMain(isMain) {} }; class CCoderMixer2ST: @@ -84,5 +84,5 @@ public: }; } -#endif +#endif diff --git a/CPP/7zip/Archive/Common/CoderMixerMT.cpp b/CPP/7zip/Archive/Common/CoderMixerMT.cpp index f43d1612..96ea76a3 100755 --- a/CPP/7zip/Archive/Common/CoderMixerMT.cpp +++ b/CPP/7zip/Archive/Common/CoderMixerMT.cpp @@ -73,7 +73,7 @@ STDMETHODIMP CCoderMixerMT::Code(ISequentialInStream *inStream, for (i = 0; i < _coders.Size(); i++) if (i != _progressCoderIndex) - _coders[i].WaitFinish(); + _coders[i].WaitExecuteFinish(); RINOK(ReturnIfError(E_ABORT)); RINOK(ReturnIfError(E_OUTOFMEMORY)); diff --git a/CPP/7zip/Archive/Common/CoderMixerMT.h b/CPP/7zip/Archive/Common/CoderMixerMT.h index c70e1829..9491a965 100755 --- a/CPP/7zip/Archive/Common/CoderMixerMT.h +++ b/CPP/7zip/Archive/Common/CoderMixerMT.h @@ -18,6 +18,7 @@ struct CCoder: public CCoderInfo, public CVirtThread virtual void Execute(); void Code(ICompressProgressInfo *progress); + ~CCoder() { CVirtThread::WaitThreadFinish(); } }; /* diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp index 70ad47aa..7e6f4602 100755 --- a/CPP/7zip/Archive/Common/HandlerOut.cpp +++ b/CPP/7zip/Archive/Common/HandlerOut.cpp @@ -2,16 +2,10 @@ #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" @@ -20,487 +14,40 @@ 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) +static void SetMethodProp32(COneMethodInfo &m, PROPID propID, UInt32 value) { - 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; + if (m.FindProp(propID) < 0) + m.AddProp32(propID, value); } -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 +void CMultiMethodProps::SetGlobalLevelAndThreads(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; - + if (level != (UInt32)(UInt32)-1) + SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level); #ifndef _7ZIP_ST - _numThreads = NSystem::GetNumberOfProcessors(); + SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); #endif - - _level = 5; - _autoFilter = true; - _volumeMode = false; - _crcSize = 4; - InitSolid(); } -void COutHandler::BeforeSetProperty() +void CMultiMethodProps::Init() { - Init(); #ifndef _7ZIP_ST - numProcessors = NSystem::GetNumberOfProcessors(); + _numProcessors = _numThreads = NSystem::GetNumberOfProcessors(); #endif - - mainDicSize = 0xFFFFFFFF; - mainDicMethodIndex = 0xFFFFFFFF; - minNumber = 0; + + _level = (UInt32)(UInt32)-1; + _autoFilter = true; _crcSize = 4; + _filterMethod.Clear(); + _methods.Clear(); } -HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) +HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) { UString name = nameSpec; name.MakeUpper(); @@ -511,24 +58,14 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val { 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); + return ParsePropToUInt32(name, value, _level); } if (name == L"CRC") { - _crcSize = 4; name.Delete(0, 3); - return ParsePropValue(name, value, _crcSize); + _crcSize = 4; + return ParsePropToUInt32(name, value, _crcSize); } UInt32 number; @@ -536,86 +73,67 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val UString realName = name.Mid(index); if (index == 0) { - if(name.Left(2).CompareNoCase(L"MT") == 0) + if (name.Left(2).CompareNoCase(L"MT") == 0) { #ifndef _7ZIP_ST - RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads)); + 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) + if (name.CompareNoCase(L"F") == 0) { - bool compressHeadersFull = true; - RINOK(SetBoolProperty(compressHeadersFull, value)); - if (!compressHeadersFull) + HRESULT res = PROPVARIANT_to_bool(value, _autoFilter); + if (res == S_OK) + return res; + if (value.vt != VT_BSTR) return E_INVALIDARG; - return S_OK; + return _filterMethod.ParseMethodFromPROPVARIANT(L"", value); } - 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) + if (number > 64) 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 + for (int j = _methods.Size(); j <= (int)number; j++) + _methods.Add(COneMethodInfo()); + return _methods[number].ParseMethodFromPROPVARIANT(realName, value); +} + +void CSingleMethodProps::Init() +{ + Clear(); + #ifndef _7ZIP_ST + _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors(); + AddNumThreadsProp(_numThreads); + #endif + _level = (UInt32)(UInt32)-1; +} + +HRESULT CSingleMethodProps::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) +{ + Init(); + for (int i = 0; i < numProps; i++) { - int index = FindPropIdStart(realName); - if (index < 0) + UString name = names[i]; + name.MakeUpper(); + if (name.IsEmpty()) 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) + const PROPVARIANT &value = values[i]; + if (name[0] == L'X') { - UInt32 dicSize; - RINOK(ParsePropDictionaryValue(realName.Mid(MyStringLen(nameToPropID.Name)), value, dicSize)); - prop.Value = dicSize; - if (number <= mainDicMethodIndex) - mainDicSize = dicSize; + UInt32 a = 9; + RINOK(ParsePropToUInt32(name.Mid(1), value, a)); + _level = a; + AddLevelProp(a); } - else + else if (name.Left(2).CompareNoCase(L"MT") == 0) { - 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; + #ifndef _7ZIP_ST + RINOK(ParseMtProp(name.Mid(2), value, _numProcessors, _numThreads)); + AddNumThreadsProp(_numThreads); + #endif } - oneMethodInfo.Props.Add(prop); + else + return ParseParamsFromPROPVARIANT(name, value); } return S_OK; } diff --git a/CPP/7zip/Archive/Common/HandlerOut.h b/CPP/7zip/Archive/Common/HandlerOut.h index 72ea4032..d3c9a237 100755 --- a/CPP/7zip/Archive/Common/HandlerOut.h +++ b/CPP/7zip/Archive/Common/HandlerOut.h @@ -3,83 +3,61 @@ #ifndef __HANDLER_OUT_H #define __HANDLER_OUT_H -#include "../../../Common/MyString.h" #include "../../Common/MethodProps.h" namespace NArchive { -struct COneMethodInfo -{ - CObjectVector<CProp> Props; - UString MethodName; - - bool IsLzma() const; -}; - -class COutHandler +class CMultiMethodProps { + UInt32 _level; public: - HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); - - HRESULT SetSolidSettings(const UString &s); - HRESULT SetSolidSettings(const PROPVARIANT &value); - #ifndef _7ZIP_ST UInt32 _numThreads; + UInt32 _numProcessors; #endif UInt32 _crcSize; - CObjectVector<COneMethodInfo> _methods; - bool _removeSfxBlock; - - UInt64 _numSolidFiles; - UInt64 _numSolidBytes; - bool _numSolidBytesDefined; - bool _solidExtension; - - bool _compressHeaders; - bool _encryptHeadersSpecified; - bool _encryptHeaders; - - bool WriteCTime; - bool WriteATime; - bool WriteMTime; - + COneMethodInfo _filterMethod; bool _autoFilter; - UInt32 _level; - bool _volumeMode; - - HRESULT SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value); - HRESULT SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString); - - void SetCompressionMethod2(COneMethodInfo &oneMethodInfo + void SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo #ifndef _7ZIP_ST , UInt32 numThreads #endif ); - void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); } - void InitSolidSize() { _numSolidBytes = (UInt64)(Int64)(-1); } - void InitSolid() + int GetNumEmptyMethods() const { - InitSolidFiles(); - InitSolidSize(); - _solidExtension = false; - _numSolidBytesDefined = false; + int i; + for (i = 0; i < _methods.Size(); i++) + if (!_methods[i].IsEmpty()) + break; + return i; } + int GetLevel() const { return _level == (UInt32)(UInt32)-1 ? 5 : (int)_level; } + void Init(); - COutHandler() { Init(); } + CMultiMethodProps() { Init(); } + HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); +}; - void BeforeSetProperty(); +class CSingleMethodProps: public CMethodProps +{ + UInt32 _level; + + void Init(); +public: + #ifndef _7ZIP_ST + UInt32 _numThreads; + UInt32 _numProcessors; + #endif - UInt32 minNumber; - UInt32 numProcessors; - UInt32 mainDicSize; - UInt32 mainDicMethodIndex; + CSingleMethodProps() { Init(); } + int GetLevel() const { return _level == (UInt32)(UInt32)-1 ? 5 : (int)_level; } + HRESULT SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps); }; } diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/CPP/7zip/Archive/Common/ItemNameUtils.cpp index a5e0dc0b..cc476fad 100755 --- a/CPP/7zip/Archive/Common/ItemNameUtils.cpp +++ b/CPP/7zip/Archive/Common/ItemNameUtils.cpp @@ -31,8 +31,8 @@ UString GetOSName2(const UString &name) if (name.IsEmpty()) return UString(); UString newName = GetOSName(name); - if (newName[newName.Length() - 1] == kOSDirDelimiter) - newName.Delete(newName.Length() - 1); + if (newName.Back() == kOSDirDelimiter) + newName.DeleteBack(); return newName; } diff --git a/CPP/7zip/Archive/Common/ParseProperties.cpp b/CPP/7zip/Archive/Common/ParseProperties.cpp index 5cd849e2..63e4f3ef 100755 --- a/CPP/7zip/Archive/Common/ParseProperties.cpp +++ b/CPP/7zip/Archive/Common/ParseProperties.cpp @@ -1,177 +1,3 @@ // ParseProperties.cpp #include "StdAfx.h" - -#include "ParseProperties.h" - -#include "Common/StringToInt.h" -#include "Common/MyCom.h" - -HRESULT ParsePropValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue) -{ - if (prop.vt == VT_UI4) - { - if (!name.IsEmpty()) - return E_INVALIDARG; - resValue = prop.ulVal; - } - else if (prop.vt == VT_EMPTY) - { - if(!name.IsEmpty()) - { - const wchar_t *start = name; - const wchar_t *end; - UInt64 v = ConvertStringToUInt64(start, &end); - if (end - start != name.Length()) - return E_INVALIDARG; - resValue = (UInt32)v; - } - } - else - return E_INVALIDARG; - return S_OK; -} - -static const int kLogarithmicSizeLimit = 32; -static const wchar_t kByteSymbol = L'B'; -static const wchar_t kKiloByteSymbol = L'K'; -static const wchar_t kMegaByteSymbol = L'M'; - -HRESULT ParsePropDictionaryValue(const UString &srcStringSpec, UInt32 &dicSize) -{ - UString srcString = srcStringSpec; - srcString.MakeUpper(); - - const wchar_t *start = srcString; - const wchar_t *end; - UInt64 number = ConvertStringToUInt64(start, &end); - int numDigits = (int)(end - start); - if (numDigits == 0 || srcString.Length() > numDigits + 1) - return E_INVALIDARG; - if (srcString.Length() == numDigits) - { - if (number >= kLogarithmicSizeLimit) - return E_INVALIDARG; - dicSize = (UInt32)1 << (int)number; - return S_OK; - } - switch (srcString[numDigits]) - { - case kByteSymbol: - if (number >= ((UInt64)1 << kLogarithmicSizeLimit)) - return E_INVALIDARG; - dicSize = (UInt32)number; - break; - case kKiloByteSymbol: - if (number >= ((UInt64)1 << (kLogarithmicSizeLimit - 10))) - return E_INVALIDARG; - dicSize = (UInt32)(number << 10); - break; - case kMegaByteSymbol: - if (number >= ((UInt64)1 << (kLogarithmicSizeLimit - 20))) - return E_INVALIDARG; - dicSize = (UInt32)(number << 20); - break; - default: - return E_INVALIDARG; - } - return S_OK; -} - -HRESULT ParsePropDictionaryValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue) -{ - if (name.IsEmpty()) - { - if (prop.vt == VT_UI4) - { - UInt32 logDicSize = prop.ulVal; - if (logDicSize >= 32) - return E_INVALIDARG; - resValue = (UInt32)1 << logDicSize; - return S_OK; - } - if (prop.vt == VT_BSTR) - return ParsePropDictionaryValue(prop.bstrVal, resValue); - return E_INVALIDARG; - } - return ParsePropDictionaryValue(name, resValue); -} - -bool StringToBool(const UString &s, bool &res) -{ - if (s.IsEmpty() || s.CompareNoCase(L"ON") == 0 || s.Compare(L"+") == 0) - { - res = true; - return true; - } - if (s.CompareNoCase(L"OFF") == 0 || s.Compare(L"-") == 0) - { - res = false; - return true; - } - return false; -} - -HRESULT SetBoolProperty(bool &dest, const PROPVARIANT &value) -{ - switch(value.vt) - { - case VT_EMPTY: - dest = true; - return S_OK; - case VT_BOOL: - dest = (value.boolVal != VARIANT_FALSE); - return S_OK; - /* - case VT_UI4: - dest = (value.ulVal != 0); - break; - */ - case VT_BSTR: - return StringToBool(value.bstrVal, dest) ? S_OK : E_INVALIDARG; - } - return E_INVALIDARG; -} - -int ParseStringToUInt32(const UString &srcString, UInt32 &number) -{ - const wchar_t *start = srcString; - const wchar_t *end; - UInt64 number64 = ConvertStringToUInt64(start, &end); - if (number64 > 0xFFFFFFFF) - { - number = 0; - return 0; - } - number = (UInt32)number64; - return (int)(end - start); -} - -HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads) -{ - if (name.IsEmpty()) - { - switch(prop.vt) - { - case VT_UI4: - numThreads = prop.ulVal; - break; - default: - { - bool val; - RINOK(SetBoolProperty(val, prop)); - numThreads = (val ? defaultNumThreads : 1); - break; - } - } - } - else - { - UInt32 number; - int index = ParseStringToUInt32(name, number); - if (index != name.Length()) - return E_INVALIDARG; - numThreads = number; - } - return S_OK; -} diff --git a/CPP/7zip/Archive/Common/ParseProperties.h b/CPP/7zip/Archive/Common/ParseProperties.h index 6f80f634..1038a8c0 100755 --- a/CPP/7zip/Archive/Common/ParseProperties.h +++ b/CPP/7zip/Archive/Common/ParseProperties.h @@ -1,18 +1,6 @@ // ParseProperties.h -#ifndef __PARSEPROPERTIES_H -#define __PARSEPROPERTIES_H - -#include "Common/MyString.h" -#include "Common/Types.h" - -HRESULT ParsePropValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue); -HRESULT ParsePropDictionaryValue(const UString &srcStringSpec, UInt32 &dicSize); -HRESULT ParsePropDictionaryValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue); - -bool StringToBool(const UString &s, bool &res); -HRESULT SetBoolProperty(bool &dest, const PROPVARIANT &value); -int ParseStringToUInt32(const UString &srcString, UInt32 &number); -HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads); +#ifndef __PARSE_PROPERTIES_H +#define __PARSE_PROPERTIES_H #endif diff --git a/CPP/7zip/Archive/DeflateProps.cpp b/CPP/7zip/Archive/DeflateProps.cpp index 8498e056..ca3dc6f5 100755 --- a/CPP/7zip/Archive/DeflateProps.cpp +++ b/CPP/7zip/Archive/DeflateProps.cpp @@ -1,118 +1,3 @@ // DeflateProps.cpp #include "StdAfx.h" - -#include "Windows/PropVariant.h" - -#include "Common/ParseProperties.h" - -#include "DeflateProps.h" - -namespace NArchive { - -static const UInt32 kAlgo1 = 0; -static const UInt32 kAlgo5 = 1; - -static const UInt32 kPasses1 = 1; -static const UInt32 kPasses7 = 3; -static const UInt32 kPasses9 = 10; - -static const UInt32 kFb1 = 32; -static const UInt32 kFb7 = 64; -static const UInt32 kFb9 = 128; - -void CDeflateProps::Normalize() -{ - UInt32 level = Level; - if (level == 0xFFFFFFFF) - level = 5; - - if (Algo == 0xFFFFFFFF) - Algo = (level >= 5 ? - kAlgo5 : - kAlgo1); - - if (NumPasses == 0xFFFFFFFF) - NumPasses = - (level >= 9 ? kPasses9 : - (level >= 7 ? kPasses7 : - kPasses1)); - if (Fb == 0xFFFFFFFF) - Fb = - (level >= 9 ? kFb9 : - (level >= 7 ? kFb7 : - kFb1)); -} - -HRESULT CDeflateProps::SetCoderProperties(ICompressSetCoderProperties *setCoderProperties) -{ - Normalize(); - - NWindows::NCOM::CPropVariant props[] = - { - Algo, - NumPasses, - Fb, - Mc - }; - PROPID propIDs[] = - { - NCoderPropID::kAlgorithm, - NCoderPropID::kNumPasses, - NCoderPropID::kNumFastBytes, - NCoderPropID::kMatchFinderCycles - }; - int numProps = sizeof(propIDs) / sizeof(propIDs[0]); - if (!McDefined) - numProps--; - return setCoderProperties->SetCoderProperties(propIDs, props, numProps); -} - -HRESULT CDeflateProps::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) -{ - Init(); - for (int i = 0; i < numProps; i++) - { - UString name = names[i]; - name.MakeUpper(); - if (name.IsEmpty()) - return E_INVALIDARG; - const PROPVARIANT &prop = values[i]; - if (name[0] == L'X') - { - UInt32 a = 9; - RINOK(ParsePropValue(name.Mid(1), prop, a)); - Level = a; - } - else if (name.Left(1) == L"A") - { - UInt32 a = kAlgo5; - RINOK(ParsePropValue(name.Mid(1), prop, a)); - Algo = a; - } - else if (name.Left(4) == L"PASS") - { - UInt32 a = kPasses9; - RINOK(ParsePropValue(name.Mid(4), prop, a)); - NumPasses = a; - } - else if (name.Left(2) == L"FB") - { - UInt32 a = kFb9; - RINOK(ParsePropValue(name.Mid(2), prop, a)); - Fb = a; - } - else if (name.Left(2) == L"MC") - { - UInt32 a = 0xFFFFFFFF; - RINOK(ParsePropValue(name.Mid(2), prop, a)); - Mc = a; - McDefined = true; - } - else - return E_INVALIDARG; - } - return S_OK; -} - -} diff --git a/CPP/7zip/Archive/DeflateProps.h b/CPP/7zip/Archive/DeflateProps.h index e05a9d4a..9fd2c2e9 100755 --- a/CPP/7zip/Archive/DeflateProps.h +++ b/CPP/7zip/Archive/DeflateProps.h @@ -3,33 +3,4 @@ #ifndef __DEFLATE_PROPS_H #define __DEFLATE_PROPS_H -#include "../ICoder.h" - -namespace NArchive { - -class CDeflateProps -{ - UInt32 Level; - UInt32 NumPasses; - UInt32 Fb; - UInt32 Algo; - UInt32 Mc; - bool McDefined; - - void Init() - { - Level = NumPasses = Fb = Algo = Mc = 0xFFFFFFFF; - McDefined = false; - } - void Normalize(); -public: - CDeflateProps() { Init(); } - bool IsMaximum() const { return Algo > 0; } - - HRESULT SetCoderProperties(ICompressSetCoderProperties *setCoderProperties); - HRESULT SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps); -}; - -} - #endif diff --git a/CPP/7zip/Archive/GzHandler.cpp b/CPP/7zip/Archive/GzHandler.cpp index 7b73bddc..ede6b01b 100755 --- a/CPP/7zip/Archive/GzHandler.cpp +++ b/CPP/7zip/Archive/GzHandler.cpp @@ -18,11 +18,10 @@ #include "../Compress/DeflateDecoder.h" #include "../Compress/DeflateEncoder.h" +#include "Common/HandlerOut.h" #include "Common/InStreamWithCRC.h" #include "Common/OutStreamWithCRC.h" -#include "DeflateProps.h" - #define Get32(p) GetUi32(p) using namespace NWindows; @@ -305,7 +304,7 @@ class CHandler: CMyComPtr<ICompressCoder> _decoder; NCompress::NDeflate::NDecoder::CCOMCoder *_decoderSpec; - CDeflateProps _method; + CSingleMethodProps _props; public: MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties) @@ -321,7 +320,7 @@ public: } }; -STATPROPSTG kProps[] = +static STATPROPSTG const kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidSize, VT_UI8}, @@ -545,7 +544,7 @@ static HRESULT UpdateArchive( ISequentialOutStream *outStream, UInt64 unpackSize, const CItem &newItem, - CDeflateProps &deflateProps, + const CSingleMethodProps &props, IArchiveUpdateCallback *updateCallback) { UInt64 complexity = 0; @@ -567,7 +566,7 @@ static HRESULT UpdateArchive( CItem item = newItem; item.Method = NHeader::NCompressionMethod::kDeflate; - item.ExtraFlags = deflateProps.IsMaximum() ? + item.ExtraFlags = props.GetLevel() >= 7 ? NHeader::NExtraFlags::kMaximum : NHeader::NExtraFlags::kFastest; @@ -577,7 +576,7 @@ static HRESULT UpdateArchive( NCompress::NDeflate::NEncoder::CCOMCoder *deflateEncoderSpec = new NCompress::NDeflate::NEncoder::CCOMCoder; CMyComPtr<ICompressCoder> deflateEncoder = deflateEncoderSpec; - RINOK(deflateProps.SetCoderProperties(deflateEncoderSpec)); + RINOK(props.SetCoderProps(deflateEncoderSpec, NULL)); RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress)); item.Crc = inStreamSpec->GetCRC(); @@ -616,8 +615,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (prop.vt != VT_FILETIME) return E_INVALIDARG; utcTime = prop.filetime; - if (!NTime::FileTimeToUnixTime(utcTime, newItem.Time)) - return E_INVALIDARG; + NTime::FileTimeToUnixTime(utcTime, newItem.Time); } { NCOM::CPropVariant prop; @@ -658,8 +656,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return E_INVALIDARG; size = prop.uhVal.QuadPart; } - - return UpdateArchive(outStream, size, newItem, _method, updateCallback); + return UpdateArchive(outStream, size, newItem, _props, updateCallback); } if (indexInArchive != 0) @@ -680,7 +677,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) { - return _method.SetProperties(names, values, numProps); + return _props.SetProperties(names, values, numProps); } static IInArchive *CreateArc() { return new CHandler; } diff --git a/CPP/7zip/Archive/Icons/bz2.ico b/CPP/7zip/Archive/Icons/bz2.ico Binary files differindex 614e3540..f22abebc 100755 --- a/CPP/7zip/Archive/Icons/bz2.ico +++ b/CPP/7zip/Archive/Icons/bz2.ico diff --git a/CPP/7zip/Archive/Icons/cab.ico b/CPP/7zip/Archive/Icons/cab.ico Binary files differindex cc2007fc..c96c0f01 100755 --- a/CPP/7zip/Archive/Icons/cab.ico +++ b/CPP/7zip/Archive/Icons/cab.ico diff --git a/CPP/7zip/Archive/Icons/fat.ico b/CPP/7zip/Archive/Icons/fat.ico Binary files differindex 882753ac..7503d933 100755 --- a/CPP/7zip/Archive/Icons/fat.ico +++ b/CPP/7zip/Archive/Icons/fat.ico diff --git a/CPP/7zip/Archive/Icons/gz.ico b/CPP/7zip/Archive/Icons/gz.ico Binary files differindex f50d8c08..d402a698 100755 --- a/CPP/7zip/Archive/Icons/gz.ico +++ b/CPP/7zip/Archive/Icons/gz.ico diff --git a/CPP/7zip/Archive/Icons/hfs.ico b/CPP/7zip/Archive/Icons/hfs.ico Binary files differindex 92a46b81..bf2c1986 100755 --- a/CPP/7zip/Archive/Icons/hfs.ico +++ b/CPP/7zip/Archive/Icons/hfs.ico diff --git a/CPP/7zip/Archive/Icons/iso.ico b/CPP/7zip/Archive/Icons/iso.ico Binary files differindex 2538e408..b3e3ac2f 100755 --- a/CPP/7zip/Archive/Icons/iso.ico +++ b/CPP/7zip/Archive/Icons/iso.ico diff --git a/CPP/7zip/Archive/Icons/split.ico b/CPP/7zip/Archive/Icons/split.ico Binary files differindex 79cb089b..65723ff3 100755 --- a/CPP/7zip/Archive/Icons/split.ico +++ b/CPP/7zip/Archive/Icons/split.ico diff --git a/CPP/7zip/Archive/Icons/squashfs.ico b/CPP/7zip/Archive/Icons/squashfs.ico Binary files differindex 551a7439..b802d942 100755 --- a/CPP/7zip/Archive/Icons/squashfs.ico +++ b/CPP/7zip/Archive/Icons/squashfs.ico diff --git a/CPP/7zip/Archive/Icons/xz.ico b/CPP/7zip/Archive/Icons/xz.ico Binary files differindex 02707351..bc07a7eb 100755 --- a/CPP/7zip/Archive/Icons/xz.ico +++ b/CPP/7zip/Archive/Icons/xz.ico diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp index 4bfb7dc6..f040b033 100755 --- a/CPP/7zip/Archive/Iso/IsoHandler.cpp +++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp @@ -172,11 +172,11 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val int pos = s.ReverseFind(L';'); if (pos >= 0 && pos == s.Length() - 2) - if (s[s.Length() - 1] == L'1') + if (s.Back() == L'1') s = s.Left(pos); if (!s.IsEmpty()) - if (s[s.Length() - 1] == L'.') - s = s.Left(s.Length() - 1); + if (s.Back() == L'.') + s.DeleteBack(); prop = (const wchar_t *)NItemName::GetOSName2(s); } break; @@ -211,19 +211,18 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, return S_OK; UInt64 totalSize = 0; UInt32 i; - for(i = 0; i < numItems; i++) + for (i = 0; i < numItems; i++) { UInt32 index = (allFilesMode ? i : indices[i]); if (index < (UInt32)_archive.Refs.Size()) { const CRef &ref = _archive.Refs[index]; const CDir &item = ref.Dir->_subItems[ref.Index]; - totalSize += item.DataLength; + if (!item.IsDir()) + totalSize += item.DataLength; } else - { totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size()); - } } extractCallback->SetTotal(totalSize); diff --git a/CPP/7zip/Archive/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp index 95efc501..194de47e 100755 --- a/CPP/7zip/Archive/LzhHandler.cpp +++ b/CPP/7zip/Archive/LzhHandler.cpp @@ -177,47 +177,6 @@ struct CItem } }; -struct CItemEx: public CItem -{ - UInt64 DataPosition; -}; - -class CInArchive -{ - CMyComPtr<IInStream> m_Stream; - UInt64 m_Position; - - HRESULT ReadBytes(void *data, UInt32 size, UInt32 &processedSize); - HRESULT CheckReadBytes(void *data, UInt32 size); -public: - HRESULT Open(IInStream *inStream); - HRESULT GetNextItem(bool &filled, CItemEx &itemInfo); - HRESULT Skip(UInt64 numBytes); -}; - -HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize) -{ - size_t realProcessedSize = size; - RINOK(ReadStream(m_Stream, data, &realProcessedSize)); - processedSize = (UInt32)realProcessedSize; - m_Position += processedSize; - return S_OK; -} - -HRESULT CInArchive::CheckReadBytes(void *data, UInt32 size) -{ - UInt32 processedSize; - RINOK(ReadBytes(data, size, processedSize)); - return (processedSize == size) ? S_OK: S_FALSE; -} - -HRESULT CInArchive::Open(IInStream *inStream) -{ - RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position)); - m_Stream = inStream; - return S_OK; -} - static const Byte *ReadUInt16(const Byte *p, UInt16 &v) { v = Get16(p); @@ -245,13 +204,13 @@ static Byte CalcSum(const Byte *data, size_t size) return sum; } -HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item) +static HRESULT GetNextItem(ISequentialInStream *stream, bool &filled, CItem &item) { filled = false; - UInt32 processedSize; + size_t processedSize = 2; Byte startHeader[2]; - RINOK(ReadBytes(startHeader, 2, processedSize)) + RINOK(ReadStream(stream, startHeader, &processedSize)) if (processedSize == 0) return S_OK; if (processedSize == 1) @@ -261,7 +220,8 @@ HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item) Byte header[256]; const UInt32 kBasicPartSize = 22; - RINOK(ReadBytes(header, kBasicPartSize, processedSize)); + processedSize = kBasicPartSize; + RINOK(ReadStream(stream, header, &processedSize)); if (processedSize != kBasicPartSize) return (startHeader[0] == 0) ? S_OK: S_FALSE; @@ -284,8 +244,7 @@ HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item) headerSize = startHeader[0]; if (headerSize < kBasicPartSize) return S_FALSE; - UInt32 remain = headerSize - kBasicPartSize; - RINOK(CheckReadBytes(header + kBasicPartSize, remain)); + RINOK(ReadStream_FALSE(stream, header + kBasicPartSize, headerSize - kBasicPartSize)); if (startHeader[1] != CalcSum(header, headerSize)) return S_FALSE; size_t nameLength = *p++; @@ -294,13 +253,13 @@ HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item) p = ReadString(p, nameLength, item.Name); } else - headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8); + headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8); p = ReadUInt16(p, item.CRC); if (item.Level != 0) { if (item.Level == 2) { - RINOK(CheckReadBytes(header + kBasicPartSize, 2)); + RINOK(ReadStream_FALSE(stream, header + kBasicPartSize, 2)); } if ((size_t)(p - header) + 3 > headerSize) return S_FALSE; @@ -317,39 +276,30 @@ HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item) return S_FALSE; item.PackSize -= nextSize; } + if (item.Extensions.Size() >= (1 << 8)) + return S_FALSE; CExtension ext; - RINOK(CheckReadBytes(&ext.Type, 1)) + RINOK(ReadStream_FALSE(stream, &ext.Type, 1)) nextSize -= 3; ext.Data.SetCapacity(nextSize); - RINOK(CheckReadBytes((Byte *)ext.Data, nextSize)) + RINOK(ReadStream_FALSE(stream, (Byte *)ext.Data, nextSize)) item.Extensions.Add(ext); Byte hdr2[2]; - RINOK(CheckReadBytes(hdr2, 2)); + RINOK(ReadStream_FALSE(stream, hdr2, 2)); ReadUInt16(hdr2, nextSize); } } - item.DataPosition = m_Position; filled = true; return S_OK; } -HRESULT CInArchive::Skip(UInt64 numBytes) -{ - UInt64 newPostion; - RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion)); - m_Position += numBytes; - if (m_Position != newPostion) - return E_FAIL; - return S_OK; -} - struct COsPair { Byte Id; const char *Name; }; -static COsPair g_OsPairs[] = +static const COsPair g_OsPairs[] = { { 0, "MS-DOS" }, { 'M', "MS-DOS" }, @@ -380,7 +330,7 @@ static const char *GetOS(Byte osId) return kUnknownOS; } -static STATPROPSTG kProps[] = +static const STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidIsDir, VT_BOOL}, @@ -393,6 +343,11 @@ static STATPROPSTG kProps[] = { NULL, kpidHostOS, VT_BSTR} }; +static const STATPROPSTG kArcProps[] = +{ + { NULL, kpidPhySize, VT_UI8} +}; + class CCRC { UInt16 _value; @@ -479,12 +434,19 @@ STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *pro return result; } +struct CItemEx: public CItem +{ + UInt64 DataPosition; +}; + class CHandler: public IInArchive, public CMyUnknownImp { CObjectVector<CItemEx> _items; CMyComPtr<IInStream> _stream; + UInt64 _phySize; + AString _errorMessage; public: MY_UNKNOWN_IMP1(IInArchive) INTERFACE_IInArchive(;) @@ -492,7 +454,7 @@ public: }; IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO +IMP_IInArchive_ArcProps CHandler::CHandler() {} @@ -502,6 +464,18 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + NCOM::CPropVariant prop; + switch(propID) + { + case kpidPhySize: prop = _phySize; break; + case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + } + prop.Detach(value); + return S_OK; +} + STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN @@ -514,8 +488,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va UString s = NItemName::WinNameToOSName(MultiByteToUnicodeString(item.GetName(), CP_OEMCP)); if (!s.IsEmpty()) { - if (s[s.Length() - 1] == WCHAR_PATH_SEPARATOR) - s.Delete(s.Length() - 1); + if (s.Back() == WCHAR_PATH_SEPARATOR) + s.DeleteBack(); prop = s; } break; @@ -567,32 +541,43 @@ STDMETHODIMP CHandler::Open(IInStream *stream, try { _items.Clear(); - CInArchive archive; UInt64 endPos = 0; bool needSetTotal = true; - if (callback != NULL) - { - RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); - RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); - } + RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); - RINOK(archive.Open(stream)); + _phySize = 0; for (;;) { CItemEx item; bool filled; - HRESULT result = archive.GetNextItem(filled, item); + HRESULT result = GetNextItem(stream, filled, item); + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &item.DataPosition)); if (result == S_FALSE) - return S_FALSE; + { + _errorMessage = "Incorrect header"; + break; + } + if (result != S_OK) return S_FALSE; + _phySize = item.DataPosition; if (!filled) break; _items.Add(item); - archive.Skip(item.PackSize); - if (callback != NULL) + + UInt64 newPostion; + RINOK(stream->Seek(item.PackSize, STREAM_SEEK_CUR, &newPostion)); + if (newPostion > endPos) + { + _phySize = endPos; + _errorMessage = "Unexpected end of archive"; + break; + } + _phySize = newPostion; + if (callback) { if (needSetTotal) { @@ -622,6 +607,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, STDMETHODIMP CHandler::Close() { + _errorMessage.Empty(); _items.Clear(); _stream.Release(); return S_OK; diff --git a/CPP/7zip/Archive/LzmaHandler.cpp b/CPP/7zip/Archive/LzmaHandler.cpp index a83e6a1a..778c2fd8 100755 --- a/CPP/7zip/Archive/LzmaHandler.cpp +++ b/CPP/7zip/Archive/LzmaHandler.cpp @@ -296,7 +296,8 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); _packSize = endPos - _startPosition; _packSizeDefined = true; - + if (_packSize >= 24 && _header.Size == 0 && _header.FilterID == 0 && _header.LzmaProps[0] == 0) + return S_FALSE; _stream = inStream; _seqStream = inStream; return S_OK; diff --git a/CPP/7zip/Archive/MubHandler.cpp b/CPP/7zip/Archive/MubHandler.cpp index da4df24c..5ebda099 100755 --- a/CPP/7zip/Archive/MubHandler.cpp +++ b/CPP/7zip/Archive/MubHandler.cpp @@ -15,7 +15,7 @@ #include "../Compress/CopyCoder.h" -#define Get32(p) GetBe32(p) +static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); } namespace NArchive { namespace NMub { @@ -116,8 +116,16 @@ HRESULT CHandler::Open2(IInStream *stream) RINOK(ReadStream(stream, buf, &processed)); if (processed < kHeaderSize) return S_FALSE; - UInt32 num = Get32(buf + 4); - if (Get32(buf) != 0xCAFEBABE || num > kNumFilesMax || processed < kHeaderSize + num * kRecordSize) + + bool be; + switch (GetBe32(buf)) + { + case 0xCAFEBABE: be = true; break; + case 0xB9FAF10E: be = false; break; + default: return S_FALSE; + } + UInt32 num = Get32(buf + 4, be); + if (num > kNumFilesMax || processed < kHeaderSize + num * kRecordSize) return S_FALSE; UInt64 endPosMax = kHeaderSize; for (UInt32 i = 0; i < num; i++) @@ -125,11 +133,11 @@ HRESULT CHandler::Open2(IInStream *stream) const Byte *p = buf + kHeaderSize + i * kRecordSize; CItem &sb = _items[i]; sb.IsTail = false; - sb.Type = Get32(p); - sb.SubType = Get32(p + 4); - sb.Offset = Get32(p + 8); - sb.Size = Get32(p + 12); - sb.Align = Get32(p + 16); + sb.Type = Get32(p, be); + sb.SubType = Get32(p + 4, be); + sb.Offset = Get32(p + 8, be); + sb.Size = Get32(p + 12, be); + sb.Align = Get32(p + 16, be); if ((sb.Type & ~MACH_TYPE_ABI64) >= 0x100 || (sb.SubType & ~MACH_SUBTYPE_ABI64) >= 0x100 || diff --git a/CPP/7zip/Archive/Nsis/NsisIn.h b/CPP/7zip/Archive/Nsis/NsisIn.h index 87ae3f1c..7ca719e4 100755 --- a/CPP/7zip/Archive/Nsis/NsisIn.h +++ b/CPP/7zip/Archive/Nsis/NsisIn.h @@ -87,7 +87,7 @@ struct CItem else s = MultiByteToUnicodeString(PrefixA); if (s.Length() > 0) - if (s[s.Length() - 1] != L'\\') + if (s.Back() != L'\\') s += L'\\'; if (unicode) s += NameU; diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp index c64067aa..e5946969 100755 --- a/CPP/7zip/Archive/PeHandler.cpp +++ b/CPP/7zip/Archive/PeHandler.cpp @@ -631,7 +631,7 @@ enum // kpidBaseOfData32, }; -STATPROPSTG kArcProps[] = +static const STATPROPSTG kArcProps[] = { { NULL, kpidCpu, VT_BSTR}, { NULL, kpidBit64, VT_BOOL}, @@ -662,7 +662,7 @@ STATPROPSTG kArcProps[] = // { L"Base Of Data", kpidBaseOfData32, VT_UI8}, }; -STATPROPSTG kProps[] = +static const STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidSize, VT_UI8}, @@ -1749,4 +1749,335 @@ static CArcInfo g_ArcInfo = REGISTER_ARC(Pe) -}} +} + + + + +namespace NTe { + +// Terse Executable (TE) image + +/* +struct CDataDir +{ + UInt32 Va; + UInt32 Size; +}; +*/ + +static const UInt32 kHeaderSize = 40; + +static bool FindValue(const CUInt32PCharPair *pairs, unsigned num, UInt32 value) +{ + for (unsigned i = 0; i < num; i++) + if (pairs[i].Value == value) + return true; + return false; +} + +#define MY_FIND_VALUE(pairs, value) FindValue(pairs, sizeof(pairs) / sizeof(pairs[0]), value) + +struct CHeader +{ + UInt16 Machine; + Byte NumSections; + Byte SubSystem; + UInt16 StrippedSize; + /* + UInt32 AddressOfEntryPoint; + UInt32 BaseOfCode; + UInt64 ImageBase; + CDataDir DataDir[2]; // base relocation and debug directory + */ + + UInt32 ConvertPa(UInt32 pa) const { return pa - StrippedSize + kHeaderSize; } + + bool Parse(const Byte *p) + { + if (p[0] != 'V' || p[1] != 'Z') + return false; + Machine = Get16(p + 2); + NumSections = p[4]; + SubSystem = p[5]; + StrippedSize = Get16(p + 6); + /* + AddressOfEntryPoint = Get32(p + 8); + BaseOfCode = Get32(p + 12); + ImageBase = Get64(p + 16); + for (int i = 0; i < 2; i++) + { + const Byte *p2 = p + 24 + i * 8; + DataDir[i].Va = Get32(p2); + DataDir[i].Size = Get32(p2 + 4); + } + */ + return NumSections <= 64 && + MY_FIND_VALUE(NPe::g_MachinePairs, Machine) && + MY_FIND_VALUE(NPe::g_SubSystems, SubSystem); + } +}; + +struct CSection +{ + Byte Name[8]; + + // UInt32 VSize; + UInt32 Va; + UInt32 PSize; + UInt32 Pa; + UInt32 Flags; + // UInt16 NumRelocs; + + void Parse(const Byte *p) + { + memcpy(Name, p, 8); + // VSize = Get32(p + 8); + Va = Get32(p + 12); + PSize = Get32(p + 16); + Pa = Get32(p + 20); + // NumRelocs = Get16(p + 32); + Flags = Get32(p + 36); + } + + bool Check() const { return (PSize + Pa > Pa); } + + void UpdateTotalSize(UInt32 &totalSize) + { + UInt32 t = Pa + PSize; + if (t > totalSize) + totalSize = t; + } +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + UInt32 _totalSize; + CMyComPtr<IInStream> _stream; + CObjectVector<CSection> _items; + CHeader _h; + UInt64 _fileSize; + + HRESULT Open2(IInStream *stream); +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +static const STATPROPSTG kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidSize, VT_UI4}, + { NULL, kpidPackSize, VT_UI4}, + { NULL, kpidCharacts, VT_BSTR}, + { NULL, kpidOffset, VT_UI4}, + { NULL, kpidVa, VT_UI8} +}; + +enum +{ + kpidSubSystem + // , kpidImageBase +}; + +static const STATPROPSTG kArcProps[] = +{ + { NULL, kpidPhySize, VT_UI4}, + // { NULL, kpidHeadersSize, VT_UI4}, + { NULL, kpidCpu, VT_BSTR}, + { L"Subsystem", kpidSubSystem, VT_BSTR}, + // { L"Image Base", kpidImageBase, VT_UI8} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_WITH_NAME + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch(propID) + { + case kpidPhySize: prop = _totalSize; break; + case kpidCpu: PAIR_TO_PROP(NPe::g_MachinePairs, _h.Machine, prop); break; + case kpidSubSystem: PAIR_TO_PROP(NPe::g_SubSystems, _h.SubSystem, prop); break; + /* + case kpidImageBase: prop = _h.ImageBase; break; + case kpidAddressOfEntryPoint: prop = _h.AddressOfEntryPoint; break; + case kpidBaseOfCode: prop = _h.BaseOfCode; break; + */ + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + { + const CSection &item = _items[index]; + switch(propID) + { + case kpidPath: StringToProp(NPe::GetName(item.Name), prop); break; + case kpidSize: + case kpidPackSize: prop = (UInt64)item.PSize; break; + case kpidOffset: prop = item.Pa; break; + case kpidVa: prop = item.Va; break; + case kpidCharacts: FLAGS_TO_PROP(NPe::g_SectFlags, item.Flags, prop); break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +HRESULT CHandler::Open2(IInStream *stream) +{ + Byte h[kHeaderSize]; + RINOK(ReadStream_FALSE(stream, h, kHeaderSize)); + if (!_h.Parse(h)) + return S_FALSE; + + CByteBuffer buf; + UInt32 headerSize = NPe::kSectionSize * _h.NumSections; + buf.SetCapacity(headerSize); + RINOK(ReadStream_FALSE(stream, buf, headerSize)); + + _totalSize = kHeaderSize + headerSize; + + for (UInt32 i = 0; i < headerSize; i += NPe::kSectionSize) + { + CSection sect; + sect.Parse(buf + i); + sect.Pa = _h.ConvertPa(sect.Pa); + _items.Add(sect); + sect.UpdateTotalSize(_totalSize); + if (!sect.Check()) + return S_FALSE; + } + + return stream->Seek(0, STREAM_SEEK_END, &_fileSize); +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + try + { + if (Open2(inStream) != S_OK) + return S_FALSE; + _stream = inStream; + } + catch(...) { return S_FALSE; } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _stream.Release(); + _items.Clear(); + _totalSize = 0; + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _items[allFilesMode ? i : indices[i]].PSize; + extractCallback->SetTotal(totalSize); + + UInt64 currentTotalSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream(streamSpec); + streamSpec->SetStream(_stream); + + for (i = 0; i < numItems; i++) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + CMyComPtr<ISequentialOutStream> realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + const CSection &item = _items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + currentTotalSize += item.PSize; + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + int res = NExtract::NOperationResult::kDataError; + if (item.Pa <= _fileSize) + { + if (testMode) + { + if (item.Pa + item.PSize <= _fileSize) + res = NExtract::NOperationResult::kOK; + } + else + { + RINOK(_stream->Seek(item.Pa, STREAM_SEEK_SET, NULL)); + streamSpec->Init(item.PSize); + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize == item.PSize) + res = NExtract::NOperationResult::kOK; + } + } + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(res)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + const CSection &item = _items[index]; + return CreateLimitedInStream(_stream, item.Pa, item.PSize, stream); + COM_TRY_END +} + +static IInArchive *CreateArc() { return new CHandler; } + +static CArcInfo g_ArcInfo = + { L"TE", L"te", 0, 0xCF, { 'V', 'Z' }, 2, false, CreateArc, 0 }; + +REGISTER_ARC(TE) + +} +} diff --git a/CPP/7zip/Archive/Rar/RarIn.cpp b/CPP/7zip/Archive/Rar/RarIn.cpp index e4c23752..a7d018ff 100755 --- a/CPP/7zip/Archive/Rar/RarIn.cpp +++ b/CPP/7zip/Archive/Rar/RarIn.cpp @@ -112,7 +112,7 @@ HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit (UInt32)Get16(buf) != (CrcCalc(buf + 2, headerSize - 2) & 0xFFFF)) return S_FALSE; - size_t commentSize = blockSize - headerSize; + size_t commentSize = blockSize - headerSize; _comment.SetCapacity(commentSize); RINOK(ReadStream_FALSE(stream, _comment, commentSize)); AddToSeekValue(commentSize); diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp index 2cc1219a..efaffed1 100755 --- a/CPP/7zip/Archive/SquashfsHandler.cpp +++ b/CPP/7zip/Archive/SquashfsHandler.cpp @@ -5,6 +5,7 @@ #include "../../../C/7zCrc.h" #include "../../../C/Alloc.h" #include "../../../C/CpuArch.h" +#include "../../../C/Xz.h" #include "Common/ComTry.h" #include "Common/IntToString.h" @@ -13,6 +14,7 @@ #include "Windows/PropVariantUtils.h" #include "Windows/Time.h" +#include "../Common/CWrappers.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" @@ -26,6 +28,10 @@ namespace NArchive { namespace NSquashfs { +static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } +static void SzFree(void *p, void *address) { p = p; MyFree(address); } +static ISzAlloc g_Alloc = { SzAlloc, SzFree }; + static const UInt32 kNumFilesMax = (1 << 28); static const unsigned kNumDirLevelsMax = (1 << 10); @@ -62,13 +68,15 @@ static const UInt32 kSignature32_LZ = 0x71736873; #define kMethod_ZLIB 1 #define kMethod_LZMA 2 #define kMethod_LZO 3 +#define kMethod_XZ 4 static const char *k_Methods[] = { "Unknown", "ZLIB", "LZMA", - "LZO" + "LZO", + "XZ" }; static const UInt32 kMetadataBlockSizeLog = 13; @@ -860,6 +868,8 @@ class CHandler: NCompress::NZlib::CDecoder *_zlibDecoderSpec; CMyComPtr<ICompressCoder> _zlibDecoder; + CXzUnpacker _xz; + CByteBuffer _inputBuffer; CDynBufSeqOutStream *_dynOutStreamSpec; @@ -886,6 +896,11 @@ class CHandler: public: CHandler(); + ~CHandler() + { + XzUnpacker_Free(&_xz); + } + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); @@ -895,6 +910,8 @@ public: CHandler::CHandler() { + XzUnpacker_Construct(&_xz, &g_Alloc); + _limitedInStreamSpec = new CLimitedSequentialInStream; _limitedInStream = _limitedInStreamSpec; @@ -1104,33 +1121,16 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL)); } - if (method == kMethod_LZO) + if (method == kMethod_ZLIB) { - if (_inputBuffer.GetCapacity() < inSize) - { - _inputBuffer.Free(); - _inputBuffer.SetCapacity(inSize); - } - RINOK(ReadStream_FALSE(_stream, _inputBuffer, inSize)); - - Byte *dest = outBuf; - if (!outBuf) + if (!_zlibDecoder) { - dest = _dynOutStreamSpec->GetBufPtrForWriting(outSizeMax); - if (!dest) - return E_OUTOFMEMORY; + _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); + _zlibDecoder = _zlibDecoderSpec; } - SizeT destLen = outSizeMax, srcLen = inSize; - RINOK(LzoDecode(dest, &destLen, _inputBuffer, &srcLen)); - if (inSize != srcLen) + RINOK(_zlibDecoder->Code(_limitedInStream, outStream, NULL, NULL, NULL)); + if (inSize != _zlibDecoderSpec->GetInputProcessedSize()) return S_FALSE; - if (outBuf) - { - *outBufWasWritten = true; - *outBufWasWrittenSize = (UInt32)destLen; - } - else - _dynOutStreamSpec->UpdateSize(destLen); } else if (method == kMethod_LZMA) { @@ -1153,14 +1153,44 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool } else { - if (!_zlibDecoder) + if (_inputBuffer.GetCapacity() < inSize) { - _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); - _zlibDecoder = _zlibDecoderSpec; + _inputBuffer.Free(); + _inputBuffer.SetCapacity(inSize); } - RINOK(_zlibDecoder->Code(_limitedInStream, outStream, NULL, NULL, NULL)); - if (inSize != _zlibDecoderSpec->GetInputProcessedSize()) + RINOK(ReadStream_FALSE(_stream, _inputBuffer, inSize)); + + Byte *dest = outBuf; + if (!outBuf) + { + dest = _dynOutStreamSpec->GetBufPtrForWriting(outSizeMax); + if (!dest) + return E_OUTOFMEMORY; + } + SizeT destLen = outSizeMax, srcLen = inSize; + if (method == kMethod_LZO) + { + RINOK(LzoDecode(dest, &destLen, _inputBuffer, &srcLen)); + } + else + { + ECoderStatus status; + XzUnpacker_Init(&_xz); + SRes res = XzUnpacker_Code(&_xz, dest, &destLen, _inputBuffer, &srcLen, LZMA_FINISH_END, &status); + if (res != 0) + return SResToHRESULT(res); + if (status != CODER_STATUS_NEEDS_MORE_INPUT || !XzUnpacker_IsStreamWasFinished(&_xz)) + return S_FALSE; + } + if (inSize != srcLen) return S_FALSE; + if (outBuf) + { + *outBufWasWritten = true; + *outBufWasWrittenSize = (UInt32)destLen; + } + else + _dynOutStreamSpec->UpdateSize(destLen); } return S_OK; } @@ -1418,6 +1448,7 @@ HRESULT CHandler::Open2(IInStream *inStream) case kMethod_ZLIB: case kMethod_LZMA: case kMethod_LZO: + case kMethod_XZ: break; default: return E_NOTIMPL; @@ -2072,15 +2103,18 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (inStream) { HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress); - if (hres != S_OK && hres != S_FALSE) + if (hres == S_OK) { - RINOK(hres); + if (copyCoderSpec->TotalSize == unpackSize) + res = NExtract::NOperationResult::kOK; + } + else if (hres == E_NOTIMPL) + { + res = NExtract::NOperationResult::kUnSupportedMethod; } - if (copyCoderSpec->TotalSize == unpackSize && hres == S_OK) - res = NExtract::NOperationResult::kOK; - else + else if(hres != S_FALSE) { - res = res; + RINOK(hres); } } } diff --git a/CPP/7zip/Archive/SwfHandler.cpp b/CPP/7zip/Archive/SwfHandler.cpp index dfc0326d..d7d9537e 100755 --- a/CPP/7zip/Archive/SwfHandler.cpp +++ b/CPP/7zip/Archive/SwfHandler.cpp @@ -21,8 +21,7 @@ #include "../Compress/ZlibEncoder.h" #include "Common/DummyOutStream.h" - -#include "DeflateProps.h" +#include "Common/HandlerOut.h" using namespace NWindows; @@ -69,7 +68,7 @@ class CHandler: CMyComPtr<ISequentialInStream> _seqStream; CMyComPtr<IInStream> _stream; - CDeflateProps _method; + CSingleMethodProps _props; public: MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties) @@ -206,7 +205,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } static HRESULT UpdateArchive(ISequentialOutStream *outStream, - UInt64 size, CDeflateProps &deflateProps, + UInt64 size, const CSingleMethodProps &props, IArchiveUpdateCallback *updateCallback) { UInt64 complexity = 0; @@ -234,7 +233,7 @@ static HRESULT UpdateArchive(ISequentialOutStream *outStream, NCompress::NZlib::CEncoder *encoderSpec = new NCompress::NZlib::CEncoder; CMyComPtr<ICompressCoder> encoder = encoderSpec; encoderSpec->Create(); - RINOK(deflateProps.SetCoderProperties(encoderSpec->DeflateEncoderSpec)); + RINOK(props.SetCoderProps(encoderSpec->DeflateEncoderSpec, NULL)); RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, progress)); if (encoderSpec->GetInputProcessedSize() + kHeaderSize != size) return E_INVALIDARG; @@ -284,7 +283,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return E_INVALIDARG; size = prop.uhVal.QuadPart; } - return UpdateArchive(outStream, size, _method, updateCallback); + return UpdateArchive(outStream, size, _props, updateCallback); } if (indexInArchive != 0) @@ -304,7 +303,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) { - return _method.SetProperties(names, values, numProps); + return _props.SetProperties(names, values, numProps); } static IInArchive *CreateArc() { return new CHandler; } diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp index 4db0cae8..251afdb7 100755 --- a/CPP/7zip/Archive/Tar/TarHandler.cpp +++ b/CPP/7zip/Archive/Tar/TarHandler.cpp @@ -64,6 +64,8 @@ HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx & { item.HeaderPos = _phySize; RINOK(ReadItem(stream, filled, item, _errorMessage)); + if (filled && item.IsSparse()) + _isSparse = true; _phySize += item.HeaderSize; _headersSize += item.HeaderSize; return S_OK; @@ -87,7 +89,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) break; _items.Add(item); - RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &_phySize)); + RINOK(stream->Seek(item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize)); if (_phySize > endPos) { _errorMessage = kUnexpectedEnd; @@ -162,6 +164,7 @@ STDMETHODIMP CHandler::Close() _headersSize = 0; _curIndex = 0; _latestIsRead = false; + _isSparse = false; _items.Clear(); _seqStream.Release(); _stream.Release(); @@ -186,7 +189,7 @@ HRESULT CHandler::SkipTo(UInt32 index) { if (_latestIsRead) { - UInt64 packSize = _latestItem.GetPackSize(); + UInt64 packSize = _latestItem.GetPackSizeAligned(); RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL)); _phySize += copyCoderSpec->TotalSize; if (copyCoderSpec->TotalSize != packSize) @@ -241,13 +244,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break; case kpidIsDir: prop = item->IsDir(); break; case kpidSize: prop = item->GetUnpackSize(); break; - case kpidPackSize: prop = item->GetPackSize(); break; + case kpidPackSize: prop = item->GetPackSizeAligned(); break; case kpidMTime: if (item->MTime != 0) { FILETIME ft; - NTime::UnixTimeToFileTime(item->MTime, ft); - prop = ft; + if (NTime::UnixTime64ToFileTime(item->MTime, ft)) + prop = ft; } break; case kpidPosixAttrib: prop = item->Mode; break; @@ -319,7 +322,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); UInt64 unpackSize = item->GetUnpackSize(); totalSize += unpackSize; - totalPackSize += item->GetPackSize(); + totalPackSize += item->GetPackSizeAligned(); if (item->IsDir()) { RINOK(extractCallback->PrepareOperation(askMode)); @@ -340,18 +343,26 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, realOutStream.Release(); outStreamSpec->Init(skipMode ? 0 : unpackSize, true); - if (item->IsLink()) - { - RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length())); - } + Int32 opRes = NExtract::NOperationResult::kOK; + if (item->IsSparse()) + opRes = NExtract::NOperationResult::kUnSupportedMethod; else { - if (!seqMode) + if (item->IsLink()) + { + RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length())); + } + else { - RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL)); + if (!seqMode) + { + RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL)); + } + streamSpec->Init(item->GetPackSizeAligned()); + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); } - streamSpec->Init(item->GetPackSize()); - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + if (outStreamSpec->GetRem() != 0) + opRes = NExtract::NOperationResult::kDataError; } if (seqMode) { @@ -359,9 +370,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, _curIndex++; } outStreamSpec->ReleaseStream(); - RINOK(extractCallback->SetOperationResult(outStreamSpec->GetRem() == 0 ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError)); + RINOK(extractCallback->SetOperationResult(opRes)); } return S_OK; COM_TRY_END @@ -371,6 +380,8 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) { COM_TRY_BEGIN const CItemEx &item = _items[index]; + if (item.IsSparse()) + return E_NOTIMPL; if (item.IsLink()) { CBufInStream *streamSpec = new CBufInStream; @@ -379,7 +390,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) *stream = streamTemp.Detach(); return S_OK; } - return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream); + return CreateLimitedInStream(_stream, item.GetDataPosition(), item.PackSize, stream); COM_TRY_END } diff --git a/CPP/7zip/Archive/Tar/TarHandler.h b/CPP/7zip/Archive/Tar/TarHandler.h index b1967061..9251edf6 100755 --- a/CPP/7zip/Archive/Tar/TarHandler.h +++ b/CPP/7zip/Archive/Tar/TarHandler.h @@ -32,6 +32,7 @@ class CHandler: UInt64 _headersSize; bool _phySizeDefined; AString _errorMessage; + bool _isSparse; NCompress::CCopyCoder *copyCoderSpec; CMyComPtr<ICompressCoder> copyCoder; diff --git a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp index ffdf2b13..b0ec63d1 100755 --- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp +++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp @@ -37,7 +37,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt IArchiveUpdateCallback *callback) { COM_TRY_BEGIN - if ((_stream && !_errorMessage.IsEmpty()) || _seqStream) + if ((_stream && (!_errorMessage.IsEmpty() || _isSparse)) || _seqStream) return E_NOTIMPL; CObjectVector<CUpdateItem> updateItems; for (UInt32 i = 0; i < numItems; i++) @@ -81,11 +81,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt NCOM::CPropVariant prop; RINOK(callback->GetProperty(i, kpidMTime, &prop)); if (prop.vt == VT_EMPTY) - ui.Time = 0; + ui.MTime = 0; else if (prop.vt != VT_FILETIME) return E_INVALIDARG; - else if (!NTime::FileTimeToUnixTime(prop.filetime, ui.Time)) - ui.Time = 0; + else + ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime); } { NCOM::CPropVariant prop; diff --git a/CPP/7zip/Archive/Tar/TarHeader.h b/CPP/7zip/Archive/Tar/TarHeader.h index 0b78bdc2..a212ae03 100755 --- a/CPP/7zip/Archive/Tar/TarHeader.h +++ b/CPP/7zip/Archive/Tar/TarHeader.h @@ -84,6 +84,7 @@ namespace NFileHeader Each file name is terminated by a null + an additional null after the last file name. */ + const char kSparse = 'S'; } // Further link types may be defined later. diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp index 5ceaa509..b6e5e0f5 100755 --- a/CPP/7zip/Archive/Tar/TarIn.cpp +++ b/CPP/7zip/Archive/Tar/TarIn.cpp @@ -63,6 +63,31 @@ static void ReadString(const char *s, int size, AString &result) result = temp; } +static bool ParseInt64(const char *p, Int64 &val) +{ + UInt32 h = GetBe32(p); + val = GetBe64(p + 4); + if (h == (UInt32)1 << 31) + return ((val >> 63) & 1) == 0; + if (h == (UInt32)(Int32)-1) + return ((val >> 63) & 1) != 0; + UInt64 uv; + bool res = OctalToNumber(p, 12, uv); + val = uv; + return res; +} + +static bool ParseSize(const char *p, UInt64 &val) +{ + if (GetBe32(p) == (UInt32)1 << 31) + { + // GNU extension + val = GetBe64(p + 4); + return ((val >> 63) & 1) == 0; + } + return OctalToNumber(p, 12, val); +} + static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error) { char buf[NFileHeader::kRecordSize]; @@ -105,17 +130,10 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; p += 8; if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; p += 8; - if (GetBe32(p) == (UInt32)1 << 31) - { - // GNU extension - item.Size = GetBe64(p + 4); - } - else - { - RIF(OctalToNumber(p, 12, item.Size)); - } + RIF(ParseSize(p, item.PackSize)); + item.Size = item.PackSize; p += 12; - RIF(OctalToNumber32(p, 12, item.MTime)); p += 12; + RIF(ParseInt64(p, item.MTime)); p += 12; UInt32 checkSum; RIF(OctalToNumber32(p, 8, checkSum)); @@ -141,7 +159,36 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE item.Name = prefix + AString('/') + item.Name; if (item.LinkFlag == NFileHeader::NLinkFlag::kLink) + { + item.PackSize = 0; item.Size = 0; + } + else if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse) + { + if (buf[482] != 0) + return S_FALSE; + RIF(ParseSize(buf + 483, item.Size)); + p = buf + 386; + UInt64 min = 0; + for (int i = 0; i < 4; i++, p += 24) + { + if (GetBe32(p) == 0) + break; + CSparseBlock sb; + RIF(ParseSize(p, sb.Offset)); + RIF(ParseSize(p + 12, sb.Size)); + item.SparseBlocks.Add(sb); + if (sb.Offset < min || sb.Offset > item.Size) + return S_FALSE; + if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0) + return S_FALSE; + min = sb.Offset + sb.Size; + if (min < sb.Offset) + return S_FALSE; + } + if (min > item.Size) + return S_FALSE; + } UInt32 checkSumReal = 0; for (int i = 0; i < NFileHeader::kRecordSize; i++) @@ -178,26 +225,39 @@ HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AStri if (item.Name.Compare(NFileHeader::kLongLink) != 0 && item.Name.Compare(NFileHeader::kLongLink2) != 0) return S_FALSE; - if (item.Size > (1 << 14)) + if (item.PackSize > (1 << 14)) return S_FALSE; - int packSize = (int)item.GetPackSize(); + int packSize = (int)item.GetPackSizeAligned(); char *buf = name->GetBuffer(packSize); RINOK(ReadStream_FALSE(stream, buf, packSize)); item.HeaderSize += packSize; - buf[(size_t)item.Size] = '\0'; + buf[(size_t)item.PackSize] = '\0'; name->ReleaseBuffer(); continue; } - if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X') + switch (item.LinkFlag) { - // pax Extended Header + case 'g': + case 'x': + case 'X': + { + // pax Extended Header + break; + } + case NFileHeader::NLinkFlag::kDumpDir: + { + break; + // GNU Extensions to the Archive Format + } + case NFileHeader::NLinkFlag::kSparse: + { + break; + // GNU Extensions to the Archive Format + } + default: + if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0)) + return S_FALSE; } - else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir) - { - // GNU Extensions to the Archive Format - } - else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0)) - return S_FALSE; if (flagL) item.Name = nameL; if (flagK) item.LinkName = nameK; return S_OK; diff --git a/CPP/7zip/Archive/Tar/TarItem.h b/CPP/7zip/Archive/Tar/TarItem.h index 859e66dd..3584a7ce 100755 --- a/CPP/7zip/Archive/Tar/TarItem.h +++ b/CPP/7zip/Archive/Tar/TarItem.h @@ -10,15 +10,22 @@ namespace NArchive { namespace NTar { +struct CSparseBlock +{ + UInt64 Offset; + UInt64 Size; +}; + struct CItem { AString Name; + UInt64 PackSize; UInt64 Size; + Int64 MTime; UInt32 Mode; UInt32 UID; UInt32 GID; - UInt32 MTime; UInt32 DeviceMajor; UInt32 DeviceMinor; @@ -31,7 +38,10 @@ struct CItem bool DeviceMajorDefined; bool DeviceMinorDefined; + CRecordVector<CSparseBlock> SparseBlocks; + bool IsLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymbolicLink && (Size == 0); } + bool IsSparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; } UInt64 GetUnpackSize() const { return IsLink() ? LinkName.Length() : Size; } bool IsDir() const @@ -56,15 +66,16 @@ struct CItem return true; } - UInt64 GetPackSize() const { return (Size + 0x1FF) & (~((UInt64)0x1FF)); } + UInt64 GetPackSizeAligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); } }; struct CItemEx: public CItem { UInt64 HeaderPos; unsigned HeaderSize; + UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; } - UInt64 GetFullSize() const { return HeaderSize + Size; } + UInt64 GetFullSize() const { return HeaderSize + PackSize; } }; }} diff --git a/CPP/7zip/Archive/Tar/TarOut.cpp b/CPP/7zip/Archive/Tar/TarOut.cpp index e542a3b2..6e699e28 100755 --- a/CPP/7zip/Archive/Tar/TarOut.cpp +++ b/CPP/7zip/Archive/Tar/TarOut.cpp @@ -47,7 +47,7 @@ static bool MakeOctalString8(char *s, UInt32 value) if (tempString.Length() >= kMaxSize) return false; int numSpaces = kMaxSize - (tempString.Length() + 1); - for(int i = 0; i < numSpaces; i++) + for (int i = 0; i < numSpaces; i++) s[i] = ' '; MyStringCopy(s + numSpaces, (const char *)tempString); return true; @@ -55,7 +55,7 @@ static bool MakeOctalString8(char *s, UInt32 value) static void MakeOctalString12(char *s, UInt64 value) { - AString tempString = MakeOctalString(value); + AString tempString = MakeOctalString(value); const int kMaxSize = 12; if (tempString.Length() > kMaxSize) { @@ -67,11 +67,23 @@ static void MakeOctalString12(char *s, UInt64 value) return; } int numSpaces = kMaxSize - tempString.Length(); - for(int i = 0; i < numSpaces; i++) + for (int i = 0; i < numSpaces; i++) s[i] = ' '; memmove(s + numSpaces, (const char *)tempString, tempString.Length()); } +static void MakeOctalString12_From_Int64(char *s, Int64 value) +{ + if (value >= 0) + { + MakeOctalString12(s, value); + return; + } + s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF; + for (int i = 0; i < 8; i++, value <<= 8) + s[4 + i] = (char)(value >> 56); +} + static bool CopyString(char *dest, const AString &src, int maxSize) { if (src.Length() >= maxSize) @@ -100,8 +112,8 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item) RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID)); cur += 8; RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID)); cur += 8; - MakeOctalString12(cur, item.Size); cur += 12; - MakeOctalString12(cur, item.MTime); cur += 12; + MakeOctalString12(cur, item.PackSize); cur += 12; + MakeOctalString12_From_Int64(cur, item.MTime); cur += 12; memmove(cur, NFileHeader::kCheckSumBlanks, 8); cur += 8; @@ -130,7 +142,7 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item) UInt32 checkSumReal = 0; - for(i = 0; i < NFileHeader::kRecordSize; i++) + for (i = 0; i < NFileHeader::kRecordSize; i++) checkSumReal += Byte(record[i]); RETURN_IF_NOT_TRUE(MakeOctalString8(record + 148, checkSumReal)); @@ -146,7 +158,7 @@ HRESULT COutArchive::WriteHeader(const CItem &item) CItem modifiedItem = item; int nameStreamSize = nameSize + 1; - modifiedItem.Size = nameStreamSize; + modifiedItem.PackSize = nameStreamSize; modifiedItem.LinkFlag = 'L'; modifiedItem.Name = NFileHeader::kLongLink; modifiedItem.LinkName.Empty(); diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp index c1633218..fb123169 100755 --- a/CPP/7zip/Archive/Tar/TarUpdate.cpp +++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp @@ -48,7 +48,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, complexity = 0; - for(i = 0; i < updateItems.Size(); i++) + for (i = 0; i < updateItems.Size(); i++) { lps->InSize = lps->OutSize = complexity; RINOK(lps->SetCur()); @@ -64,14 +64,14 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, if (ui.IsDir) { item.LinkFlag = NFileHeader::NLinkFlag::kDirectory; - item.Size = 0; + item.PackSize = 0; } else { item.LinkFlag = NFileHeader::NLinkFlag::kNormal; - item.Size = ui.Size; + item.PackSize = ui.Size; } - item.MTime = ui.Time; + item.MTime = ui.MTime; item.DeviceMajorDefined = false; item.DeviceMinorDefined = false; item.UID = 0; @@ -83,12 +83,12 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, if (ui.NewData) { - item.Size = ui.Size; - if (item.Size == (UInt64)(Int64)-1) + item.PackSize = ui.Size; + if (ui.Size == (UInt64)(Int64)-1) return E_INVALIDARG; } else - item.Size = inputItems[ui.IndexInArchive].Size; + item.PackSize = inputItems[ui.IndexInArchive].PackSize; if (ui.NewData) { @@ -101,9 +101,9 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, if (!ui.IsDir) { RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress)); - if (copyCoderSpec->TotalSize != item.Size) + if (copyCoderSpec->TotalSize != item.PackSize) return E_FAIL; - RINOK(outArchive.FillDataResidual(item.Size)); + RINOK(outArchive.FillDataResidual(item.PackSize)); } } complexity += ui.Size; @@ -117,7 +117,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, { RINOK(outArchive.WriteHeader(item)); RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL)); - size = existItem.Size; + size = existItem.PackSize; } else { @@ -129,10 +129,12 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); if (copyCoderSpec->TotalSize != size) return E_FAIL; - RINOK(outArchive.FillDataResidual(existItem.Size)); + RINOK(outArchive.FillDataResidual(existItem.PackSize)); complexity += size; } } + lps->InSize = lps->OutSize = complexity; + RINOK(lps->SetCur()); return outArchive.WriteFinishHeader(); } diff --git a/CPP/7zip/Archive/Tar/TarUpdate.h b/CPP/7zip/Archive/Tar/TarUpdate.h index fb217d19..3f889739 100755 --- a/CPP/7zip/Archive/Tar/TarUpdate.h +++ b/CPP/7zip/Archive/Tar/TarUpdate.h @@ -13,15 +13,15 @@ struct CUpdateItem { int IndexInArchive; int IndexInClient; - UInt32 Time; - UInt32 Mode; + Int64 MTime; UInt64 Size; - AString Name; - AString User; - AString Group; + UInt32 Mode; bool NewData; bool NewProps; bool IsDir; + AString Name; + AString User; + AString Group; }; HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp index 60d5fc2a..d2a2884f 100755 --- a/CPP/7zip/Archive/Udf/UdfIn.cpp +++ b/CPP/7zip/Archive/Udf/UdfIn.cpp @@ -574,34 +574,33 @@ HRESULT CInArchive::Open2() { Clear(); + // Some UDFs contain additional pad zeros (2 KB). + // Seek to STREAM_SEEK_END for direct DVD reading can return 8 KB more, so we check last 16 KB. + // And when we read last block, result read size can be smaller than required size. + UInt64 fileSize; RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize)); - - // Some UDFs contain additional 2 KB of zeros, so we also check 12, corrected to 11. - const int kSecLogSizeMax = 12; - Byte buf[1 << kSecLogSizeMax]; - Byte kSizesLog[] = { 11, 8, 12 }; - - for (int i = 0;; i++) + const size_t kBufSize = 1 << 14; + Byte buf[kBufSize]; + size_t readSize = (fileSize < kBufSize) ? (size_t)fileSize : kBufSize; + RINOK(_stream->Seek(fileSize - readSize, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream(_stream, buf, &readSize)); + size_t i = readSize; + for (;;) { - if (i == sizeof(kSizesLog) / sizeof(kSizesLog[0])) - return S_FALSE; - SecLogSize = kSizesLog[i]; - Int32 bufSize = 1 << SecLogSize; - if (bufSize > fileSize) + const size_t kSecSizeMin = 1 << 8; + if (i < kSecSizeMin) return S_FALSE; - RINOK(_stream->Seek(-bufSize, STREAM_SEEK_END, NULL)); - RINOK(ReadStream_FALSE(_stream, buf, bufSize)); + i -= kSecSizeMin; + SecLogSize = (readSize - i < ((size_t)1 << 11)) ? 8 : 11; CTag tag; - if (tag.Parse(buf, bufSize) == S_OK) + if (tag.Parse(buf + i, (1 << SecLogSize)) == S_OK) if (tag.Id == DESC_TYPE_AnchorVolPtr) break; } - if (SecLogSize == 12) - SecLogSize = 11; CExtent extentVDS; - extentVDS.Parse(buf + 16); + extentVDS.Parse(buf + i + 16); for (UInt32 location = extentVDS.Pos; ; location++) { diff --git a/CPP/7zip/Archive/UefiHandler.cpp b/CPP/7zip/Archive/UefiHandler.cpp new file mode 100755 index 00000000..88739d8f --- /dev/null +++ b/CPP/7zip/Archive/UefiHandler.cpp @@ -0,0 +1,1935 @@ +// UefiHandler.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +// #include <stdio.h> + +#ifdef SHOW_DEBUG_INFO +#include <stdio.h> +#endif + +#include "../../../C/7zCrc.h" +#include "../../../C/Alloc.h" +#include "../../../C/CpuArch.h" +#include "../../../C/LzmaDec.h" + +#include "Common/Buffer.h" +#include "Common/ComTry.h" +#include "Common/IntToString.h" +#include "Common/StringConvert.h" + +#include "Windows/PropVariant.h" +#include "Windows/PropVariantUtils.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#include "./Common/FindSignature.h" + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) +#define Get24(p) (Get32(p) & 0xFFFFFF) + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +namespace NArchive { +namespace NUefi { + +static const UInt32 kBufTotalSizeMax = (1 << 29); +static const UInt32 kNumFilesMax = (1 << 18); +static const int kLevelMax = 64; + +static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } +static void SzFree(void *p, void *address) { p = p; MyFree(address); } +static ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +static const UInt32 kFvHeaderSize = 0x38; +static const UInt32 kGuidSize = 16; +static const UInt32 kCapsuleSigSize = kGuidSize; +#define CAPSULE_SIGNATURE \ + { 0xBD,0x86,0x66,0x3B,0x76,0x0D,0x30,0x40,0xB7,0x0E,0xB5,0x51,0x9E,0x2F,0xC5,0xA0 } +static const Byte kCapsuleSig[kCapsuleSigSize] = CAPSULE_SIGNATURE; + +static const UInt32 kFfsGuidOffset = 16; +#define FFS_SIGNATURE \ + { 0xD9,0x54,0x93,0x7A,0x68,0x04,0x4A,0x44,0x81,0xCE,0x0B,0xF6,0x17,0xD8,0x90,0xDF } +static const Byte k_FFS_Guid[kGuidSize] = FFS_SIGNATURE; + +static const Byte k_MacFS_Guid[kGuidSize] = + { 0xAD,0xEE,0xAD,0x04,0xFF,0x61,0x31,0x4D,0xB6,0xBA,0x64,0xF8,0xBF,0x90,0x1F,0x5A }; + +static const UInt32 kFvSignature = 0x4856465F; + +static const Byte kGuids[][kGuidSize] = +{ + { 0xB0,0xCD,0x1B,0xFC,0x31,0x7D,0xAA,0x49,0x93,0x6A,0xA4,0x60,0x0D,0x9D,0xD0,0x83 }, + { 0x2E,0x06,0xA0,0x1B,0x79,0xC7,0x82,0x45,0x85,0x66,0x33,0x6A,0xE8,0xF7,0x8F,0x09 }, + { 0x25,0x4E,0x37,0x7E,0x01,0x8E,0xEE,0x4F,0x87,0xf2,0x39,0x0C,0x23,0xC6,0x06,0xCD }, + { 0x97,0xE5,0x1B,0x16,0xC5,0xE9,0xDB,0x49,0xAE,0x50,0xC4,0x62,0xAB,0x54,0xEE,0xDA }, + { 0xDB,0x7F,0xAD,0x77,0x2A,0xDF,0x02,0x43,0x88,0x98,0xC7,0x2E,0x4C,0xDB,0xD0,0xF4 }, + { 0xAB,0x71,0xCF,0xF5,0x4B,0xB0,0x7E,0x4B,0x98,0x8A,0xD8,0xA0,0xD4,0x98,0xE6,0x92 }, + { 0x91,0x45,0x53,0x7A,0xCE,0x37,0x81,0x48,0xB3,0xC9,0x71,0x38,0x14,0xF4,0x5D,0x6B }, + { 0x84,0xE6,0x7A,0x36,0x5D,0x33,0x71,0x46,0xA1,0x6D,0x89,0x9D,0xBF,0xEA,0x6B,0x88 }, + { 0x98,0x07,0x40,0x24,0x07,0x38,0x42,0x4A,0xB4,0x13,0xA1,0xEC,0xEE,0x20,0x5D,0xD8 }, + { 0xEE,0xA2,0x3F,0x28,0x2C,0x53,0x4D,0x48,0x93,0x83,0x9F,0x93,0xB3,0x6F,0x0B,0x7E }, + { 0x9B,0xD5,0xB8,0x98,0xBA,0xE8,0xEE,0x48,0x98,0xDD,0xC2,0x95,0x39,0x2F,0x1E,0xDB }, + { 0x09,0x6D,0xE3,0xC3,0x94,0x82,0x97,0x4B,0xA8,0x57,0xD5,0x28,0x8F,0xE3,0x3E,0x28 }, + { 0x18,0x88,0x53,0x4A,0xE0,0x5A,0xB2,0x4E,0xB2,0xEB,0x48,0x8B,0x23,0x65,0x70,0x22 } +}; + + +static const char *kGuidNames[] = +{ + "CRC", + "VolumeTopFile", + "ACPI", + "ACPI2", + "Main", + "Intel32", + "Intel64", + "Intel32c", + "Intel64c", + "MacVolume", + "MacUpdate.txt", + "MacName", + "Insyde" +}; + +enum +{ + kGuidIndex_CRC = 0 +}; + +struct CSigExtPair +{ + const char *ext; + unsigned sigSize; + Byte sig[16]; +}; + +static const CSigExtPair g_Sigs[] = +{ + { "bmp", 2, { 'B','M' } }, + { "riff", 4, { 'R','I','F','F' } }, + { "pe", 2, { 'M','Z'} }, + { "gif", 6, { 'G','I','F','8','9', 'a' } }, + { "png", 8, { 0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A } }, + { "jpg", 10, { 0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46 } }, + { "rom", 2, { 0x55,0xAA } } +}; + +enum +{ + kSig_BMP, + kSig_RIFF, + kSig_PE +}; + +static const char *FindExt(const Byte *p, size_t size) +{ + unsigned i; + for (i = 0; i < ARRAY_SIZE(g_Sigs); i++) + { + const CSigExtPair &pair = g_Sigs[i]; + if (size >= pair.sigSize) + if (memcmp(p, pair.sig, pair.sigSize) == 0) + break; + } + if (i == ARRAY_SIZE(g_Sigs)) + return NULL; + switch (i) + { + case kSig_BMP: + if (GetUi32(p + 2) > size || GetUi32(p + 0xA) > size) + return NULL; + break; + case kSig_RIFF: + if (GetUi32(p + 8) == 0x45564157 || GetUi32(p + 0xC) == 0x20746D66 ) + return "wav"; + break; + case kSig_PE: + { + if (size < 512) + return NULL; + UInt32 peOffset = GetUi32(p + 0x3C); + if (peOffset >= 0x1000 || peOffset + 512 > size || (peOffset & 7) != 0) + return NULL; + if (GetUi32(p + peOffset) != 0x00004550) + return NULL; + break; + } + } + return g_Sigs[i].ext; +} + +static bool AreGuidsEq(const Byte *p1, const Byte *p2) +{ + return memcmp(p1, p2, kGuidSize) == 0; +} + +static int FindGuid(const Byte *p) +{ + for (int i = 0; i < ARRAY_SIZE(kGuids); i++) + if (AreGuidsEq(p, kGuids[i])) + return i; + return -1; +} + +static bool IsFfs(const Byte *p) +{ + return (Get32(p + 0x28) == kFvSignature && AreGuidsEq(p + kFfsGuidOffset, k_FFS_Guid)); +} + +#define FVB_ERASE_POLARITY (1 << 11) + +/* +static const CUInt32PCharPair g_FV_Attribs[] = +{ + { 0, "ReadDisabledCap" }, + { 1, "ReadEnabledCap" }, + { 2, "ReadEnabled" }, + { 3, "WriteDisabledCap" }, + { 4, "WriteEnabledCap" }, + { 5, "WriteEnabled" }, + { 6, "LockCap" }, + { 7, "Locked" }, + + { 9, "StickyWrite" }, + { 10, "MemoryMapped" }, + { 11, "ErasePolarity" }, + + { 12, "ReadLockCap" }, + { 13, "WriteLockCap" }, + { 14, "WriteLockCap" } +}; +*/ + +enum +{ + FV_FILETYPE_ALL, + FV_FILETYPE_RAW, + FV_FILETYPE_FREEFORM, + FV_FILETYPE_SECURITY_CORE, + FV_FILETYPE_PEI_CORE, + FV_FILETYPE_DXE_CORE, + FV_FILETYPE_PEIM, + FV_FILETYPE_DRIVER, + FV_FILETYPE_COMBINED_PEIM_DRIVER, + FV_FILETYPE_APPLICATION, + // The value 0x0A is reserved and should not be used + FV_FILETYPE_FIRMWARE_VOLUME_IMAGE = 0x0B, + // types 0xF0 - 0xFF are FFS file types + FV_FILETYPE_FFS_PAD = 0xF0 +}; + +static const char *g_FileTypes[] = +{ + "ALL", + "RAW", + "FREEFORM", + "SECURITY_CORE", + "PEI_CORE", + "DXE_CORE", + "PEIM", + "DRIVER", + "COMBINED_PEIM_DRIVER", + "APPLICATION", + "0xA", + "VOLUME" +}; + +// typedef Byte FFS_FILE_ATTRIBUTES; +// FFS File Attributes +#define FFS_ATTRIB_TAIL_PRESENT 0x01 +// #define FFS_ATTRIB_RECOVERY 0x02 +// #define FFS_ATTRIB_HEADER_EXTENSION 0x04 +// #define FFS_ATTRIB_DATA_ALIGNMENT 0x38 +#define FFS_ATTRIB_CHECKSUM 0x40 + +static const CUInt32PCharPair g_FFS_FILE_ATTRIBUTES[] = +{ + { 0, "" /* "TAIL" */ }, + { 1, "RECOVERY" }, + // { 2, "HEADER_EXTENSION" }, // reserved for future + { 6, "" /* "CHECKSUM" */ } +}; + +// static const Byte g_Allignment[8] = { 3, 4, 7, 9, 10, 12, 15, 16 }; + +// typedef Byte FFS_FILE_STATE; + +// Look also FVB_ERASE_POLARITY. +// Lower-order State bits are superceded by higher-order State bits. + +// #define FILE_HEADER_CONSTRUCTION 0x01 +// #define FILE_HEADER_VALID 0x02 +#define FILE_DATA_VALID 0x04 +// #define FILE_MARKED_FOR_UPDATE 0x08 +// #define FILE_DELETED 0x10 +// #define FILE_HEADER_INVALID 0x20 + +// SECTION_TYPE + +#define SECTION_ALL 0x00 + +#define SECTION_COMPRESSION 0x01 +#define SECTION_GUID_DEFINED 0x02 + +// Leaf section Type values +#define SECTION_PE32 0x10 +#define SECTION_PIC 0x11 +#define SECTION_TE 0x12 +#define SECTION_DXE_DEPEX 0x13 +#define SECTION_VERSION 0x14 +#define SECTION_USER_INTERFACE 0x15 +#define SECTION_COMPATIBILITY16 0x16 +#define SECTION_FIRMWARE_VOLUME_IMAGE 0x17 +#define SECTION_FREEFORM_SUBTYPE_GUID 0x18 +#define SECTION_RAW 0x19 +#define SECTION_PEI_DEPEX 0x1B + + +// #define GUIDED_SECTION_PROCESSING_REQUIRED 0x01 +// #define GUIDED_SECTION_AUTH_STATUS_VALID 0x02 + +static const CUInt32PCharPair g_GUIDED_SECTION_ATTRIBUTES[] = +{ + { 0, "PROCESSING_REQUIRED" }, + { 1, "AUTH" } +}; + +static const CUInt32PCharPair g_SECTION_TYPE[] = +{ + { 0x01, "COMPRESSION" }, + { 0x02, "GUID" }, + { 0x10, "efi" }, + { 0x11, "PIC" }, + { 0x12, "te" }, + { 0x13, "DXE_DEPEX" }, + { 0x14, "VERSION" }, + { 0x15, "USER_INTERFACE" }, + { 0x16, "COMPATIBILITY16" }, + { 0x17, "VOLUME" }, + { 0x18, "FREEFORM_SUBTYPE_GUID" }, + { 0x19, "raw" }, + { 0x1B, "PEI_DEPEX" } +}; + +#define COMPRESSION_TYPE_NONE 0 +#define COMPRESSION_TYPE_LZH 1 +#define COMPRESSION_TYPE_LZMA 2 + +static const char *g_Methods[] = +{ + "COPY", + "LZH", + "LZMA" +}; + +static AString UInt32ToString(UInt32 val) +{ + char sz[16]; + ConvertUInt32ToString(val, sz); + return sz; +} + +static void ConvertByteToHex(unsigned value, char *s) +{ + for (int i = 0; i < 2; i++) + { + unsigned t = value & 0xF; + value >>= 4; + s[1 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); + } +} + +static AString GuidToString(const Byte *p, bool full) +{ + char s[16 * 2 + 8]; + int i; + for (i = 0; i < 4; i++) + ConvertByteToHex(p[3 - i], s + i * 2); + s[8] = 0; + + if (full) + { + s[8] = '-'; + for (i = 4; i < kGuidSize; i++) + ConvertByteToHex(p[i], s + 1 + i * 2); + s[32 + 1] = 0; + } + return s; +} + +static const char *kExpressionCommands[] = +{ + "BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR" +}; + +static bool ParseDepedencyExpression(const Byte *p, UInt32 size, AString &res) +{ + res.Empty(); + for (UInt32 i = 0; i < size;) + { + unsigned command = p[i++]; + if (command > ARRAY_SIZE(kExpressionCommands)) + return false; + res += kExpressionCommands[command]; + if (command < 3) + { + if (i + kGuidSize > size) + return false; + res += " "; + res += GuidToString(p + i, false); + i += kGuidSize; + } + res += "; "; + } + return true; +} + +static bool ParseUtf16zString(const Byte *p, UInt32 size, UString &res) +{ + if ((size & 1) != 0) + return false; + res.Empty(); + UInt32 i; + for (i = 0; i < size; i += 2) + { + wchar_t c = Get16(p + i); + if (c == 0) + break; + res += c; + } + return (i == size - 2); +} + +static bool ParseUtf16zString2(const Byte *p, UInt32 size, AString &res) +{ + UString s; + if (!ParseUtf16zString(p, size, s)) + return false; + res = UnicodeStringToMultiByte(s); + return true; +} + +#define FLAGS_TO_STRING(pairs, value) FlagsToString(pairs, ARRAY_SIZE(pairs), value) +#define TYPE_TO_STRING(table, value) TypeToString(table, ARRAY_SIZE(table), value) +#define TYPE_PAIR_TO_STRING(table, value) TypePairToString(table, ARRAY_SIZE(table), value) + +static const UInt32 kFileHeaderSize = 24; + +static void AddSpaceAndString(AString &res, const AString &newString) +{ + if (!res.IsEmpty() && !newString.IsEmpty()) + res += ' '; + res += newString; +} + +class CFfsFileHeader +{ + Byte CheckHeader; + Byte CheckFile; + Byte Attrib; + Byte State; + + UInt16 GetTailReference() const { return CheckHeader | ((UInt16)CheckFile << 8); } + UInt32 GetTailSize() const { return IsThereTail() ? 2 : 0; } + bool IsThereFileChecksum() const { return (Attrib & FFS_ATTRIB_CHECKSUM) != 0; } + bool IsThereTail() const { return (Attrib & FFS_ATTRIB_TAIL_PRESENT) != 0; } +public: + Byte GuidName[kGuidSize]; + Byte Type; + UInt32 Size; + + bool Parse(const Byte *p) + { + int i; + for (i = 0; i < kFileHeaderSize; i++) + if (p[i] != 0xFF) + break; + if (i == kFileHeaderSize) + return false; + memcpy(GuidName, p, kGuidSize); + CheckHeader = p[0x10]; + CheckFile = p[0x11]; + Type = p[0x12]; + Attrib = p[0x13]; + Size = Get24(p + 0x14); + State = p[0x17]; + return true; + } + + UInt32 GetDataSize() const { return Size - kFileHeaderSize - GetTailSize(); } + + bool Check(const Byte *p, UInt32 size) + { + if (Size > size) + return false; + UInt32 tailSize = GetTailSize(); + if (Size < kFileHeaderSize + tailSize) + return false; + + { + unsigned checkSum = 0; + for (UInt32 i = 0; i < kFileHeaderSize; i++) + checkSum += p[i]; + checkSum -= p[0x17]; + checkSum -= p[0x11]; + if ((Byte)checkSum != 0) + return false; + } + + if (IsThereFileChecksum()) + { + unsigned checkSum = 0; + UInt32 checkSize = Size - tailSize; + for (UInt32 i = 0; i < checkSize; i++) + checkSum += p[i]; + checkSum -= p[0x17]; + if ((Byte)checkSum != 0) + return false; + } + + if (IsThereTail()) + if (GetTailReference() != (UInt16)~Get16(p + Size - 2)) + return false; + + int polarity = 0; + int i; + for (i = 5; i >= 0; i--) + if (((State >> i) & 1) == polarity) + { + // AddSpaceAndString(s, g_FFS_FILE_STATE_Flags[i]); + if ((1 << i) != FILE_DATA_VALID) + return false; + break; + } + if (i < 0) + return false; + + return true; + } + + AString GetCharacts() const + { + AString s; + if (Type == FV_FILETYPE_FFS_PAD) + s += "PAD"; + else + s += TYPE_TO_STRING(g_FileTypes, Type); + AddSpaceAndString(s, FLAGS_TO_STRING(g_FFS_FILE_ATTRIBUTES, Attrib & 0xC7)); + /* + int align = (Attrib >> 3) & 7; + if (align != 0) + { + s += " Align:"; + s += UInt32ToString((UInt32)1 << g_Allignment[align]); + } + */ + return s; + } +}; + +#define GET_32(offs, dest) dest = Get32(p + (offs)); +#define GET_64(offs, dest) dest = Get64(p + (offs)); + +struct CCapsuleHeader +{ + UInt32 HeaderSize; + UInt32 Flags; + UInt32 CapsuleImageSize; + UInt32 SequenceNumber; + // Guid InstanceId; + UInt32 OffsetToSplitInformation; + UInt32 OffsetToCapsuleBody; + UInt32 OffsetToOemDefinedHeader; + UInt32 OffsetToAuthorInformation; + UInt32 OffsetToRevisionInformation; + UInt32 OffsetToShortDescription; + UInt32 OffsetToLongDescription; + UInt32 OffsetToApplicableDevices; + + void Clear() { memset(this, 0, sizeof(this)); } + + void Parse(const Byte *p) + { + GET_32(0x10, HeaderSize); + GET_32(0x14, Flags); + GET_32(0x18, CapsuleImageSize); + GET_32(0x1C, SequenceNumber); + GET_32(0x30, OffsetToSplitInformation); + GET_32(0x34, OffsetToCapsuleBody); + GET_32(0x38, OffsetToOemDefinedHeader); + GET_32(0x3C, OffsetToAuthorInformation); + GET_32(0x40, OffsetToRevisionInformation); + GET_32(0x44, OffsetToShortDescription); + GET_32(0x48, OffsetToLongDescription); + GET_32(0x4C, OffsetToApplicableDevices); + } +}; + +struct CItem +{ + AString Name; + AString Characts; + int Parent; + int Method; + int NameIndex; + int NumChilds; + bool IsDir; + bool Skip; + bool ThereAreSubDirs; + bool ThereIsUniqueName; + bool KeepName; + + int BufIndex; + UInt32 Offset; + UInt32 Size; + + CItem(): Parent(-1), Method(-1), NameIndex(-1), NumChilds(0), + IsDir(false), Skip(false), ThereAreSubDirs(false), ThereIsUniqueName(false), KeepName(true) {} + void SetGuid(const Byte *guidName, bool full = false); + AString GetName(int numChildsInParent) const; +}; + +void CItem::SetGuid(const Byte *guidName, bool full) +{ + ThereIsUniqueName = true; + int index = FindGuid(guidName); + if (index >= 0) + Name = kGuidNames[index]; + else + Name = GuidToString(guidName, full); +} + +AString CItem::GetName(int numChildsInParent) const +{ + if (numChildsInParent <= 1 || NameIndex < 0) + return Name; + char sz[32]; + char sz2[32]; + ConvertUInt32ToString(NameIndex, sz); + ConvertUInt32ToString(numChildsInParent - 1, sz2); + int numZeros = (int)strlen(sz2) - (int)strlen(sz); + AString res; + for (int i = 0; i < numZeros; i++) + res += '0'; + return res + (AString)sz + '.' + Name; +} + +struct CItem2 +{ + AString Name; + AString Characts; + int MainIndex; + int Parent; + + CItem2(): Parent(-1) {} +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CObjectVector<CItem> _items; + CObjectVector<CItem2> _items2; + CObjectVector<CByteBuffer> _bufs; + UString _comment; + UInt32 _methodsMask; + bool _capsuleMode; + + UInt32 _totalBufsSize; + CCapsuleHeader _h; + + void AddCommentString(const wchar_t *name, UInt32 pos); + int AddItem(const CItem &item); + int AddFileItemWithIndex(CItem &item); + int AddDirItem(CItem &item); + int AddBuf(UInt32 size); + + HRESULT ParseSections(int bufIndex, UInt32 pos, UInt32 size, int parent, int method, int level); + HRESULT ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, int parent, int method, int level); + HRESULT OpenCapsule(IInStream *stream); + HRESULT OpenFv(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback); + HRESULT Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback); +public: + CHandler(bool capsuleMode): _capsuleMode(capsuleMode) {} + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +static const STATPROPSTG kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidIsDir, VT_BOOL}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidCharacts, VT_BSTR} +}; + +static const STATPROPSTG kArcProps[] = +{ + { NULL, kpidComment, VT_BSTR}, + { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidPhySize, VT_UI8}, + { NULL, kpidCharacts, VT_BSTR} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem2 &item2 = _items2[index]; + const CItem &item = _items[item2.MainIndex]; + switch(propID) + { + case kpidPath: + { + AString path = item2.Name; + int cur = item2.Parent; + while (cur >= 0) + { + const CItem2 &item2 = _items2[cur]; + path = item2.Name + CHAR_PATH_SEPARATOR + path; + cur = item2.Parent; + } + prop = path; + break; + } + case kpidIsDir: prop = item.IsDir; break; + case kpidMethod: if (item.Method >= 0) prop = g_Methods[item.Method]; break; + case kpidCharacts: if (!item2.Characts.IsEmpty()) prop = item2.Characts; break; + case kpidSize: if (!item.IsDir) prop = (UInt64)item.Size; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +void CHandler::AddCommentString(const wchar_t *name, UInt32 pos) +{ + UString s; + const Byte *buf = _bufs[0]; + if (pos < _h.HeaderSize) + return; + for (UInt32 i = pos;; i += 2) + { + if (s.Length() > (1 << 16) || i >= _h.OffsetToCapsuleBody) + return; + wchar_t c = Get16(buf + i); + if (c == 0) + { + i += 2; + if (i >= _h.OffsetToCapsuleBody) + return; + c = Get16(buf + i); + if (c == 0) + break; + s += L'\n'; + } + s += c; + } + if (s.IsEmpty()) + return; + _comment += L'\n'; + _comment += name; + _comment += L": "; + _comment += s; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch(propID) + { + case kpidMethod: + { + AString s; + for (int i = 0; i < 32; i++) + if ((_methodsMask & ((UInt32)1 << i)) != 0) + AddSpaceAndString(s, g_Methods[i]); + if (!s.IsEmpty()) + prop = s; + break; + } + case kpidComment: if (!_comment.IsEmpty()) prop = _comment; break; + case kpidPhySize: prop = (UInt64)_h.CapsuleImageSize; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +#ifdef SHOW_DEBUG_INFO +static void PrintLevel(int level) +{ + PRF(printf("\n")); + for (int i = 0; i < level; i++) + PRF(printf(" ")); +} +static void MyPrint(UInt32 posBase, UInt32 size, int level, const char *name) +{ + PrintLevel(level); + PRF(printf("%s, pos = %6x, size = %6d", name, posBase, size)); +} +#else +#define PrintLevel(level) +#define MyPrint(posBase, size, level, name) +#endif + +static const unsigned kNumBigValueBits = 8 * 4; +static const unsigned kNumValueBytes = 3; +static const unsigned kNumValueBits = 8 * kNumValueBytes; +static const UInt32 kMask = (1 << kNumValueBits) - 1; + +class CBitmMemDecoder +{ + unsigned _bitPos; + UInt32 _value; + const Byte *_buf; + size_t _pos; + size_t _size; + size_t _extra; +public: + void Init(const Byte *buf, size_t size) + { + _buf = buf; + _size = size; + _pos = 0; + _extra = 0; + _bitPos = kNumBigValueBits; + Normalize(); + } + + bool IsFullFinished() const { return (_extra * 8) == (kNumBigValueBits - _bitPos); } + + void Normalize() + { + for (; _bitPos >= 8; _bitPos -= 8) + { + Byte b; + if (_pos < _size) + b = _buf[_pos++]; + else + { + b = 0; + _extra++; + } + _value = (_value << 8) | b; + } + } + + UInt32 GetValue(unsigned numBits) const + { + return ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - numBits); + } + + void MovePos(unsigned numBits) + { + _bitPos += numBits; + Normalize(); + } + + UInt32 ReadBitsFast(unsigned numBits) + { + UInt32 res = GetValue(numBits); + MovePos(numBits); + return res; + } + + UInt32 ReadBits(unsigned numBits); + UInt32 ReadAlignBits() { return ReadBits((32 - _bitPos) & 7); } +}; + +UInt32 CBitmMemDecoder::ReadBits(unsigned numBits) +{ + UInt32 res = GetValue(numBits); + MovePos(numBits); + return res; +} + +namespace NHuffman { + +static const int kNumTableBits = 9; +static const int kNumBitsMax = 16; + +class CDecoder +{ + UInt32 m_Limits[kNumBitsMax + 1]; + UInt32 m_Positions[kNumBitsMax + 1]; + Byte m_Lengths[1 << kNumTableBits]; + Int32 m_MainSymbol; + +public: + UInt32 *m_Symbols; + UInt32 m_NumSymbols; + + void SetSingleSymbolMode(UInt32 symbol) { m_MainSymbol = symbol; } + bool SetCodeLengths(const Byte *codeLengths); + UInt32 DecodeSymbol(CBitmMemDecoder *bitStream) + { + if (m_MainSymbol != -1) + return (UInt32)m_MainSymbol; + int numBits; + UInt32 value = bitStream->GetValue(kNumBitsMax); + if (value < m_Limits[kNumTableBits]) + numBits = m_Lengths[value >> (kNumBitsMax - kNumTableBits)]; + else + for (numBits = kNumTableBits + 1; value >= m_Limits[numBits]; numBits++); + bitStream->MovePos(numBits); + return m_Symbols[m_Positions[numBits] + ((value - m_Limits[numBits - 1]) >> (kNumBitsMax - numBits))]; + } +}; + +bool CDecoder::SetCodeLengths(const Byte *codeLengths) +{ + m_MainSymbol = -1; + int lenCounts[kNumBitsMax + 1]; + UInt32 tmpPositions[kNumBitsMax + 1]; + int i; + for (i = 1; i <= kNumBitsMax; i++) + lenCounts[i] = 0; + UInt32 symbol; + for (symbol = 0; symbol < m_NumSymbols; symbol++) + { + int len = codeLengths[symbol]; + if (len > kNumBitsMax) + return false; + lenCounts[len]++; + m_Symbols[symbol] = 0xFFFFFFFF; + } + lenCounts[0] = 0; + m_Positions[0] = m_Limits[0] = 0; + UInt32 startPos = 0; + UInt32 index = 0; + const UInt32 kMaxValue = (1 << kNumBitsMax); + for (i = 1; i <= kNumBitsMax; i++) + { + startPos += lenCounts[i] << (kNumBitsMax - i); + if (startPos > kMaxValue) + return false; + m_Limits[i] = (i == kNumBitsMax) ? kMaxValue : startPos; + m_Positions[i] = m_Positions[i - 1] + lenCounts[i - 1]; + tmpPositions[i] = m_Positions[i]; + if (i <= kNumTableBits) + { + UInt32 limit = (m_Limits[i] >> (kNumBitsMax - kNumTableBits)); + for (; index < limit; index++) + m_Lengths[index] = (Byte)i; + } + } + if (startPos != kMaxValue) + return false; + for (symbol = 0; symbol < m_NumSymbols; symbol++) + { + int len = codeLengths[symbol]; + if (len != 0) + m_Symbols[tmpPositions[len]++] = symbol; + } + return true; +} + +} + +static const int kMaxHuffmanLen = 16; +static const int kExtraSize = kMaxHuffmanLen + 3; +static const int kMinMatchLen = 3; +static const int kMaxMatchLen = 256; +static const int kNumAlphaSymsMax = 256 + kMaxMatchLen - kMinMatchLen + 1; +static const int kNumDistSymsMax = 24 + 2; // it's limited by bit decoder. + +#define HUFF_START_CODE(huff, numSymsMax, numSymBits) \ + UInt32 numSyms = bitDec.ReadBits(numSymBits); \ + Byte lens[numSymsMax]; memset(lens, 0, sizeof(lens)); \ + if (numSyms > (numSymsMax)) return S_FALSE; \ + huff.m_NumSymbols = numSyms; \ + if (numSyms == 0) { \ + numSyms = bitDec.ReadBits(numSymBits); \ + if (numSyms >= (numSymsMax)) return S_FALSE; \ + huff.SetSingleSymbolMode(numSyms); } \ + +static HRESULT LzhDecode(Byte *dest, UInt32 destSize, const Byte *src, UInt32 srcSize) +{ + if (srcSize < 8) + return S_FALSE; + { + UInt32 packSize = Get32(src); + UInt32 unpackSize = Get32(src + 4); + src += 8; + srcSize -= 8; + if (destSize != unpackSize || srcSize != packSize) + return S_FALSE; + } + + CBitmMemDecoder bitDec; + bitDec.Init(src, srcSize); + + UInt32 pos = 0; + for (;;) + { + UInt32 blockSize = bitDec.ReadBits(16); + UInt32 symbols[kExtraSize + kNumAlphaSymsMax + kNumDistSymsMax]; + + NHuffman::CDecoder extraHuff; + extraHuff.m_Symbols = symbols; + { + HUFF_START_CODE(extraHuff, kExtraSize, 5) + else + { + for (UInt32 i = 0; i < numSyms; i++) + { + if (i == 3) + { + UInt32 numZeros = bitDec.ReadBits(2); + if (i + numZeros > numSyms) + return S_FALSE; + for (UInt32 j = 0; j < numZeros; j++, i++) + lens[i] = (Byte)0; + if (i == numSyms) + break; + } + + UInt32 len = bitDec.ReadBits(3); + if (len == 7) + { + for(;; len++) + { + if (len > kMaxHuffmanLen) + return S_FALSE; + if (bitDec.ReadBits(1) == 0) + break; + } + } + lens[i] = (Byte)len; + } + if (!extraHuff.SetCodeLengths(lens)) + return S_FALSE; + } + } + + NHuffman::CDecoder symHuff; + symHuff.m_Symbols = symbols + kExtraSize; + { + HUFF_START_CODE(symHuff, kNumAlphaSymsMax, 9) + else + { + for (UInt32 i = 0; i < numSyms;) + { + UInt32 c = extraHuff.DecodeSymbol(&bitDec); + if (c > 2) + lens[i++] = (Byte)c - 2; + else + { + UInt32 numZeros; + if (c == 0) + numZeros = 1; + else if (c == 1) + numZeros = bitDec.ReadBits(4) + 3; + else + numZeros = bitDec.ReadBits(9) + 20; + if (i + numZeros > numSyms) + return S_FALSE; + for (UInt32 j = 0; j < numZeros; j++, i++) + lens[i] = (Byte)0; + } + } + if (!symHuff.SetCodeLengths(lens)) + return S_FALSE; + } + } + + NHuffman::CDecoder distHuff; + distHuff.m_Symbols = symbols + kExtraSize + kNumAlphaSymsMax; + { + const UInt32 version = 1; + const UInt32 numDistBits = version + 4; + HUFF_START_CODE(distHuff, kNumDistSymsMax, numDistBits) + else + { + for (UInt32 i = 0; i < numSyms; i++) + { + UInt32 len = bitDec.ReadBits(3); + if (len == 7) + { + for(;; len++) + { + if (len > kMaxHuffmanLen) + return S_FALSE; + if (bitDec.ReadBits(1) == 0) + break; + } + } + lens[i] = (Byte)len; + } + if (!distHuff.SetCodeLengths(lens)) + return S_FALSE; + } + } + + while (blockSize) + { + blockSize--; + UInt32 c = symHuff.DecodeSymbol(&bitDec); + if (c < 256) + { + if (destSize == 0) + return S_FALSE; + *dest++ = (Byte)c; + destSize--; + pos++; + continue; + } + c = c - 256 + kMinMatchLen; + if (destSize < c) + return S_FALSE; + UInt32 dist = distHuff.DecodeSymbol(&bitDec); + if (dist > 1) + dist = ((UInt32)1 << (dist - 1)) + bitDec.ReadBits(dist - 1); + dist++; + if (dist > pos) + return S_FALSE; + pos += c; + destSize -= c; + do + { + *dest = dest[0 - (Int32)dist]; + dest++; + } + while (--c); + } + + // PRF(printf("\ndestSize = %6d", destSize)); + if (destSize == 0) + { + if (bitDec.ReadAlignBits() != 0) + return S_FALSE; + if (bitDec.ReadBits(8) != 0) + return S_FALSE; + if (!bitDec.IsFullFinished()) + return S_FALSE; + break; + } + } + return S_OK; +} + +int CHandler::AddItem(const CItem &item) +{ + if (_items.Size() >= kNumFilesMax) + throw 2; + return _items.Add(item); +} + +int CHandler::AddFileItemWithIndex(CItem &item) +{ + int nameIndex = _items.Size(); + if (item.Parent >= 0) + nameIndex = _items[item.Parent].NumChilds++; + item.NameIndex = nameIndex; + return AddItem(item); +} + +int CHandler::AddDirItem(CItem &item) +{ + if (item.Parent >= 0) + _items[item.Parent].ThereAreSubDirs = true; + item.IsDir = true; + item.Size = 0; + return AddItem(item); +} + +int CHandler::AddBuf(UInt32 size) +{ + if (size > kBufTotalSizeMax - _totalBufsSize) + throw 1; + _totalBufsSize += size; + int index = _bufs.Add(CByteBuffer()); + _bufs[index].SetCapacity(size); + return index; +} + +HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int parent, int method, int level) +{ + if (level > kLevelMax) + return S_FALSE; + MyPrint(posBase, size, level, "Sections"); + level++; + const Byte *bufData = _bufs[bufIndex]; + UInt32 pos = 0; + for (;;) + { + if (size == pos) + return S_OK; + PrintLevel(level); + PRF(printf("%s, pos = %6x", "Sect", pos)); + pos = (pos + 3) & ~(UInt32)3; + if (pos > size) + return S_FALSE; + UInt32 rem = size - pos; + if (rem == 0) + return S_OK; + if (rem < 4) + return S_FALSE; + const Byte *p = bufData + posBase + pos; + UInt32 sectSize = Get24(p); + if (sectSize > rem || sectSize < 4) + return S_FALSE; + + Byte type = p[3]; + PrintLevel(level); + PRF(printf("%s, type = %2x, pos = %6x, size = %6d", "Sect", type, pos, sectSize)); + CItem item; + item.Method = method; + item.BufIndex = bufIndex; + item.Parent = parent; + item.Offset = posBase + pos + 4; + UInt32 sectDataSize = sectSize - 4; + item.Size = sectDataSize; + item.Name = TYPE_PAIR_TO_STRING(g_SECTION_TYPE, type); + + if (type == SECTION_COMPRESSION) + { + if (sectSize < 4 + 5) + return S_FALSE; + UInt32 uncompressedSize = Get32(p + 4); + Byte compressionType = p[8]; + + UInt32 newSectSize = sectSize - 9; + UInt32 newOffset = posBase + pos + 9; + const Byte *pStart = p + 9; + + item.KeepName = false; + if (compressionType > 2) + { + // AddFileItemWithIndex(item); + return S_FALSE; + } + else + { + item.Name = g_Methods[compressionType]; + // int parent = AddDirItem(item); + if (compressionType == COMPRESSION_TYPE_NONE) + { + RINOK(ParseSections(bufIndex, newOffset, newSectSize, parent, method, level)); + } + else if (compressionType == COMPRESSION_TYPE_LZH) + { + int newBufIndex = AddBuf(uncompressedSize); + CByteBuffer &buf = _bufs[newBufIndex]; + RINOK(LzhDecode(buf, uncompressedSize, pStart, newSectSize)); + RINOK(ParseSections(newBufIndex, 0, uncompressedSize, parent, compressionType, level)); + } + else + { + if (newSectSize < 4 + 5 + 8) + return S_FALSE; + unsigned addSize = 4; + if (pStart[0] == 0x5d && pStart[1] == 0 && pStart[2] == 0 && pStart[3] == 0x80 && pStart[4] == 0) + { + addSize = 0; + // some archives have such header + } + else + { + // normal BIOS contains uncompressed size here + // UInt32 uncompressedSize2 = Get24(pStart); + // Byte firstSectType = p[9 + 3]; + // firstSectType can be 0 in some archives + } + pStart += addSize; + UInt64 lzmaUncompressedSize = Get64(pStart + 5); + if (lzmaUncompressedSize > (1 << 30)) + return S_FALSE; + if (lzmaUncompressedSize < uncompressedSize) + return S_FALSE; + SizeT destLen = (SizeT)lzmaUncompressedSize; + int newBufIndex = AddBuf((UInt32)lzmaUncompressedSize); + CByteBuffer &buf = _bufs[newBufIndex]; + ELzmaStatus status; + SizeT srcLen = newSectSize - (addSize + 5 + 8); + SizeT srcLen2 = srcLen; + SRes res = LzmaDecode(buf, &destLen, pStart + 13, &srcLen, + pStart, 5, LZMA_FINISH_END, &status, &g_Alloc); + if (res != 0) + return S_FALSE; + if (srcLen != srcLen2 || destLen != lzmaUncompressedSize || status != LZMA_STATUS_FINISHED_WITH_MARK) + return S_FALSE; + RINOK(ParseSections(newBufIndex, 0, (UInt32)lzmaUncompressedSize, parent, compressionType, level)); + } + _methodsMask |= (1 << compressionType); + } + } + else if (type == SECTION_GUID_DEFINED) + { + const UInt32 kHeaderSize = 4 + kGuidSize + 4; + if (sectSize < kHeaderSize) + return S_FALSE; + item.SetGuid(p + 4); + UInt32 dataOffset = Get16(p + 4 + kGuidSize); + UInt32 attrib = Get16(p + 4 + kGuidSize + 2); + if (dataOffset > sectSize || dataOffset < kHeaderSize) + return S_FALSE; + UInt32 newSectSize = sectSize - dataOffset; + item.Size = newSectSize; + UInt32 newOffset = posBase + pos + dataOffset; + item.Offset = newOffset; + UInt32 propsSize = dataOffset - kHeaderSize; + bool needDir = true; + AddSpaceAndString(item.Characts, FLAGS_TO_STRING(g_GUIDED_SECTION_ATTRIBUTES, attrib)); + if (AreGuidsEq(p + 0x4, kGuids[kGuidIndex_CRC]) && propsSize == 4) + { + needDir = false; + item.KeepName = false; + if (CrcCalc(bufData + newOffset, newSectSize) != Get32(p + kHeaderSize)) + return S_FALSE; + } + else + { + if (propsSize != 0) + { + CItem item2 = item; + item2.Name += ".prop"; + item2.Size = propsSize; + item2.Offset = posBase + pos + kHeaderSize; + AddItem(item2); + } + } + int newParent = parent; + if (needDir) + newParent = AddDirItem(item); + RINOK(ParseSections(bufIndex, newOffset, newSectSize, newParent, method, level)); + } + else if (type == SECTION_FIRMWARE_VOLUME_IMAGE) + { + item.KeepName = false; + int newParent = AddDirItem(item); + RINOK(ParseVolume(bufIndex, posBase + pos + 4, sectSize - 4, newParent, method, level)); + } + else + { + bool needAdd = true; + switch(type) + { + case SECTION_RAW: + { + const UInt32 kInsydeOffset = 12; + if (sectDataSize >= kFvHeaderSize + kInsydeOffset) + { + if (IsFfs(p + 4 + kInsydeOffset) && + sectDataSize - kInsydeOffset == Get64(p + 4 + kInsydeOffset + 0x20)) + { + needAdd = false; + item.Name = "vol"; + int newParent = AddDirItem(item); + RINOK(ParseVolume(bufIndex, posBase + pos + 4 + kInsydeOffset, sectDataSize - kInsydeOffset, newParent, method, level)); + } + + if (needAdd) + { + const char *ext = FindExt(p + 4, sectDataSize); + if (ext) + item.Name = ext; + } + } + break; + } + case SECTION_DXE_DEPEX: + case SECTION_PEI_DEPEX: + { + AString s; + if (ParseDepedencyExpression(p + 4, sectDataSize, s)) + { + if (s.Length() < (1 << 9)) + { + s = '[' + s + ']'; + AddSpaceAndString(_items[item.Parent].Characts, s); + needAdd = false; + } + else + { + item.BufIndex = AddBuf(s.Length()); + CByteBuffer &buf0 = _bufs[item.BufIndex]; + memcpy(buf0, s, s.Length()); + item.Offset = 0; + item.Size = s.Length(); + } + } + break; + } + case SECTION_VERSION: + { + if (sectDataSize > 2) + { + AString s; + if (ParseUtf16zString2(p + 6, sectDataSize - 2, s)) + { + AddSpaceAndString(_items[item.Parent].Characts, (AString)"ver:" + UInt32ToString(Get16(p + 4)) + ' ' + s); + needAdd = false; + } + } + break; + } + case SECTION_USER_INTERFACE: + { + AString s; + if (ParseUtf16zString2(p + 4, sectDataSize, s)) + { + _items[parent].Name = s; + needAdd = false; + } + break; + } + case SECTION_FREEFORM_SUBTYPE_GUID: + { + if (sectDataSize >= kGuidSize) + { + item.SetGuid(p + 4); + item.Size = sectDataSize - kGuidSize; + item.Offset = posBase + pos + 4 + kGuidSize; + } + break; + } + } + + if (needAdd) + AddFileItemWithIndex(item); + } + pos += sectSize; + } +} + +static UInt32 Count_FF_Bytes(const Byte *p, UInt32 size) +{ + UInt32 i; + for (i = 0; i < size && p[i] == 0xFF; i++); + return i; +} + +static bool Is_FF_Stream(const Byte *p, UInt32 size) +{ + return (Count_FF_Bytes(p, size) == size); +} + +HRESULT CHandler::ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, int parent, int method, int level) +{ + if (level > kLevelMax) + return S_FALSE; + MyPrint(posBase, size, level, "Volume"); + level++; + if (size < kFvHeaderSize) + return S_FALSE; + const Byte *p = _bufs[bufIndex] + posBase; + // first 16 bytes must be zeros, but they are not zeros sometimes. + if (!AreGuidsEq(p + kFfsGuidOffset, k_FFS_Guid) && + !AreGuidsEq(p + kFfsGuidOffset, k_MacFS_Guid)) + { + CItem item; + item.Method = method; + item.BufIndex = bufIndex; + item.Parent = parent; + item.Offset = posBase; + item.Size = size; + item.SetGuid(p + kFfsGuidOffset); + item.Name += " [VOLUME]"; + AddItem(item); + return S_OK; + } + + if (Get32(p + 0x28) != kFvSignature) + return S_FALSE; + UInt32 attribs = Get32(p + 0x2C); + if ((attribs & FVB_ERASE_POLARITY) == 0) + return S_FALSE; + // if (parent >= 0) AddSpaceAndString(_items[parent].Characts, FLAGS_TO_STRING(g_FV_Attribs, attribs)); + UInt64 fvLen = Get64(p + 0x20); + UInt32 headerLen = Get16(p + 0x30); + if (headerLen > size || headerLen < kFvHeaderSize || (headerLen & 0x7) != 0 || + fvLen > size || fvLen < headerLen) + return S_FALSE; + + { + UInt32 checkCalc = 0; + for (UInt32 i = 0; i < headerLen; i += 2) + checkCalc += Get16(p + i); + if ((checkCalc & 0xFFFF) != 0) + return S_FALSE; + } + + // 3 reserved bytes are not zeros sometimes. + // UInt16 ExtHeaderOffset; // in new SPECIFICATION? + // Byte revision = p[0x37]; + + UInt32 pos = kFvHeaderSize; + for (;;) + { + if (pos >= headerLen) + return S_FALSE; + UInt32 numBlocks = Get32(p + pos); + UInt32 length = Get32(p + pos + 4); + pos += 8; + if (numBlocks == 0 && length == 0) + break; + } + if (pos != headerLen) + return S_FALSE; + + CRecordVector<UInt32> guidsVector; + + for (;;) + { + UInt32 rem = (UInt32)fvLen - pos; + if (rem < kFileHeaderSize) + break; + pos = (pos + 7) & ~7; + rem = (UInt32)fvLen - pos; + if (rem < kFileHeaderSize) + break; + + CItem item; + item.Method = method; + item.BufIndex = bufIndex; + item.Parent = parent; + + const Byte *pFile = p + pos; + CFfsFileHeader fh; + if (!fh.Parse(pFile)) + { + UInt32 num_FF_bytes = Count_FF_Bytes(pFile, rem); + if (num_FF_bytes != rem) + { + item.Name = "[junk]"; + item.Offset = posBase + pos + num_FF_bytes; + item.Size = rem - num_FF_bytes; + AddItem(item); + } + break; + } + PrintLevel(level); PRF(printf("%s, pos = %6x, size = %6d", "FILE", posBase + pos, fh.Size)); + if (!fh.Check(pFile, rem)) + return S_FALSE; + + UInt32 offset = posBase + pos + kFileHeaderSize; + UInt32 sectSize = fh.GetDataSize(); + item.Offset = offset; + item.Size = sectSize; + + pos += fh.Size; + + if (fh.Type == FV_FILETYPE_FFS_PAD) + if (Is_FF_Stream(pFile + kFileHeaderSize, sectSize)) + continue; + + UInt32 guid32 = Get32(fh.GuidName); + bool full = true; + if (guidsVector.FindInSorted(guid32) < 0) + { + guidsVector.AddToUniqueSorted(guid32); + full = false; + } + item.SetGuid(fh.GuidName, full); + + item.Characts = fh.GetCharacts(); + PrintLevel(level); + PRF(printf("%s", item.Characts)); + + if (fh.Type == FV_FILETYPE_FFS_PAD || + fh.Type == FV_FILETYPE_RAW) + { + bool isVolume = false; + if (fh.Type == FV_FILETYPE_RAW) + { + if (sectSize >= kFvHeaderSize) + if (IsFfs(pFile + kFileHeaderSize)) + isVolume = true; + } + if (isVolume) + { + int newParent = AddDirItem(item); + RINOK(ParseVolume(bufIndex, offset, sectSize, newParent, method, level)); + } + else + AddItem(item); + } + else + { + int newParent = AddDirItem(item); + RINOK(ParseSections(bufIndex, offset, sectSize, newParent, method, level)); + } + } + return S_OK; +} + +HRESULT CHandler::OpenCapsule(IInStream *stream) +{ + const UInt32 kHeaderSize = 80; + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)); + _h.Parse(buf); + if (_h.HeaderSize != kHeaderSize || + _h.CapsuleImageSize < kHeaderSize || + _h.OffsetToCapsuleBody < kHeaderSize || + _h.OffsetToCapsuleBody > _h.CapsuleImageSize) + return S_FALSE; + + if (_h.SequenceNumber != 0 || + _h.OffsetToSplitInformation != 0 ) + return E_NOTIMPL; + + int bufIndex = AddBuf(_h.CapsuleImageSize); + CByteBuffer &buf0 = _bufs[bufIndex]; + memcpy(buf0, buf, kHeaderSize); + ReadStream_FALSE(stream, buf0 + kHeaderSize, _h.CapsuleImageSize - kHeaderSize); + + AddCommentString(L"Author", _h.OffsetToAuthorInformation); + AddCommentString(L"Revision", _h.OffsetToRevisionInformation); + AddCommentString(L"Short Description", _h.OffsetToShortDescription); + AddCommentString(L"Long Description", _h.OffsetToLongDescription); + + return ParseVolume(bufIndex, _h.OffsetToCapsuleBody, _h.CapsuleImageSize - _h.OffsetToCapsuleBody, -1, -1, 0); +} + +HRESULT CHandler::OpenFv(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) +{ + UInt64 fileSize; + RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); + if (fileSize > (1 << 27)) + return S_FALSE; + + UInt32 volIndex = 0; + UInt32 pos = 0, prevEnd = 0; + if (callback) + { + RINOK(callback->SetTotal(NULL, &fileSize)); + } + + for (;;) + { + UInt64 limit = 0; + UInt64 *limitPtr = NULL; + if (maxCheckStartPosition) + { + UInt32 directSize = pos - prevEnd; + if (directSize >= *maxCheckStartPosition) + break; + limit = *maxCheckStartPosition - directSize; + limitPtr = &limit; + } + + UInt64 resPos; + RINOK(stream->Seek(pos + kFfsGuidOffset, STREAM_SEEK_SET, NULL)); + if (FindSignatureInStream(stream, k_FFS_Guid, kGuidSize, limitPtr, resPos) == S_FALSE) + break; + + pos += (UInt32)resPos; + UInt64 fvSize; + { + UInt32 rem = (UInt32)fileSize - pos; + if (rem < kFvHeaderSize) + break; + RINOK(stream->Seek(pos, STREAM_SEEK_SET, NULL)); + Byte buf[kFvHeaderSize]; + RINOK(ReadStream_FALSE(stream, buf, kFvHeaderSize)); + fvSize = Get64(buf + 0x20); + if (!IsFfs(buf) || fvSize > rem) + { + pos++; + continue; + } + } + + RINOK(stream->Seek(prevEnd, STREAM_SEEK_SET, NULL)); + + if (pos != prevEnd) + { + CItem item; + item.Offset = 0; + item.Size = pos - prevEnd; + item.BufIndex = AddBuf(item.Size); + CByteBuffer &buf0 = _bufs[item.BufIndex]; + RINOK(ReadStream_FALSE(stream, buf0, item.Size)); + item.Name = UInt32ToString(volIndex++); + AddItem(item); + } + + prevEnd = pos; + RINOK(stream->Seek(pos, STREAM_SEEK_SET, NULL)); + UInt32 fvSize32 = (UInt32)fvSize; + CItem item; + item.BufIndex = AddBuf(fvSize32); + CByteBuffer &buf0 = _bufs[item.BufIndex]; + item.Name = UInt32ToString(volIndex++); + int parent = AddDirItem(item); + ReadStream_FALSE(stream, buf0, fvSize32); + RINOK(ParseVolume(item.BufIndex, 0, fvSize32, parent, -1, 0)); + pos += fvSize32; + prevEnd = pos; + + if (callback) + { + UInt64 pos64 = pos; + RINOK(callback->SetCompleted(NULL, &pos64)); + } + } + if (_items.Size() == 0) + return S_FALSE; + + if (pos <= fileSize) + { + pos = (UInt32)fileSize; + if (prevEnd < pos) + { + CItem item; + item.Offset = 0; + item.Size = pos - prevEnd; + item.BufIndex = AddBuf(item.Size); + CByteBuffer &buf0 = _bufs[item.BufIndex]; + RINOK(stream->Seek(prevEnd, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, buf0, item.Size)); + item.Name = UInt32ToString(volIndex++); + AddItem(item); + } + } + _h.CapsuleImageSize = pos; + return S_OK; +} + +HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) +{ + if (_capsuleMode) + { + RINOK(OpenCapsule(stream)); + } + else + { + RINOK(OpenFv(stream, maxCheckStartPosition, callback)); + } + + CIntVector numChilds; + numChilds.Reserve(_items.Size()); + int i; + for (i = 0; i < _items.Size(); i++) + { + numChilds.Add(0); + int parent = _items[i].Parent; + if (parent >= 0) + numChilds[parent]++; + } + + for (i = 0; i < _items.Size(); i++) + { + CItem &item = _items[i]; + int parent = item.Parent; + if (parent >= 0) + { + CItem &parentItem = _items[parent]; + if (numChilds[parent] == 1) + if (!item.ThereIsUniqueName || !parentItem.ThereIsUniqueName || !parentItem.ThereAreSubDirs) + parentItem.Skip = true; + } + } + + CIntVector mainToReduced; + for (i = 0; i < _items.Size(); i++) + { + mainToReduced.Add(_items2.Size()); + const CItem &item = _items[i]; + if (item.Skip) + continue; + AString name; + int numItems = -1; + int parent = item.Parent; + if (parent >= 0) + numItems = numChilds[parent]; + AString name2 = item.GetName(numItems); + AString characts2 = item.Characts; + if (item.KeepName) + name = name2; + while (parent >= 0) + { + const CItem &item3 = _items[parent]; + if (!item3.Skip) + break; + if (item3.KeepName) + { + AString name3 = item3.GetName(-1); + if (name.IsEmpty()) + name = name3; + else + name = name3 + '.' + name; + } + AddSpaceAndString(characts2, item3.Characts); + parent = item3.Parent; + } + if (name.IsEmpty()) + name = name2; + + CItem2 item2; + item2.MainIndex = i; + item2.Name = name; + item2.Characts = characts2; + if (parent >= 0) + item2.Parent = mainToReduced[parent]; + _items2.Add(item2); + /* + CItem2 item2; + item2.MainIndex = i; + item2.Name = item.Name; + item2.Parent = item.Parent; + _items2.Add(item2); + */ + } + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + Close(); + try + { + if (Open2(inStream, maxCheckStartPosition, callback) != S_OK) + return S_FALSE; + } + catch(...) { return S_FALSE; } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _totalBufsSize = 0; + _methodsMask = 0; + _items.Clear(); + _items2.Clear(); + _bufs.Clear(); + _comment.Empty(); + _h.Clear(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items2.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)-1); + if (allFilesMode) + numItems = _items2.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _items[_items2[allFilesMode ? i : indices[i]].MainIndex].Size; + extractCallback->SetTotal(totalSize); + + UInt64 currentTotalSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + CMyComPtr<ISequentialOutStream> realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[_items2[index].MainIndex]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + currentTotalSize += item.Size; + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + if (testMode || item.IsDir) + { + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + int res = NExtract::NOperationResult::kDataError; + CMyComPtr<ISequentialInStream> inStream; + GetStream(index, &inStream); + if (inStream) + { + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize == item.Size) + res = NExtract::NOperationResult::kOK; + } + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(res)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + const CItem &item = _items[_items2[index].MainIndex]; + if (item.IsDir) + return S_FALSE; + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr<IInStream> streamTemp = streamSpec; + const CByteBuffer &buf = _bufs[item.BufIndex]; + /* + if (item.Offset + item.Size > buf.GetCapacity()) + return S_FALSE; + */ + streamSpec->Init(buf + item.Offset, item.Size, (IInArchive *)this); + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + + +namespace UEFIc +{ + static IInArchive *CreateArc() { return new CHandler(true); } + static CArcInfo g_ArcInfo = + { L"UEFIc", L"scap", 0, 0xD0, CAPSULE_SIGNATURE, kCapsuleSigSize, false, CreateArc, 0 }; + REGISTER_ARC(UEFIc) +} + +namespace UEFIs +{ + static IInArchive *CreateArc() { return new CHandler(false); } + static CArcInfo g_ArcInfo = + { L"UEFIs", L"", 0, 0xD1, FFS_SIGNATURE, kGuidSize, false, CreateArc, 0 }; + REGISTER_ARC(UEFIs) +} + +}} diff --git a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp index 50b879e7..85f0771c 100755 --- a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp +++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp @@ -465,7 +465,8 @@ static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream, RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } } - + lps->InSize = lps->OutSize = complexity; + RINOK(lps->SetCur()); CUpdateItem ri; FILETIME ft; diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp index 64b7a586..8383488b 100755 --- a/CPP/7zip/Archive/XzHandler.cpp +++ b/CPP/7zip/Archive/XzHandler.cpp @@ -8,6 +8,7 @@ #include "../../Common/ComTry.h" #include "../../Common/IntToString.h" +#include "../../Common/StringConvert.h" #include "../ICoder.h" @@ -40,13 +41,15 @@ namespace NXz { struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit; +static const wchar_t *k_LZMA2_Name = L"LZMA2"; + class CHandler: public IInArchive, public IArchiveOpenSeq, #ifndef EXTRACT_ONLY public IOutArchive, public ISetProperties, - public COutHandler, + public CMultiMethodProps, #endif public CMyUnknownImp { @@ -62,12 +65,12 @@ class CHandler: CMyComPtr<IInStream> _stream; CMyComPtr<ISequentialInStream> _seqStream; - UInt32 _crcSize; + UInt32 _filterId; void Init() { - _crcSize = 4; - COutHandler::Init(); + _filterId = 0; + CMultiMethodProps::Init(); } HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback); @@ -98,14 +101,14 @@ CHandler::CHandler() Init(); } -STATPROPSTG kProps[] = +static STATPROPSTG const kProps[] = { { NULL, kpidSize, VT_UI8}, { NULL, kpidPackSize, VT_UI8}, { NULL, kpidMethod, VT_BSTR} }; -STATPROPSTG kArcProps[] = +static STATPROPSTG const kArcProps[] = { { NULL, kpidMethod, VT_BSTR}, { NULL, kpidNumBlocks, VT_UI4} @@ -160,11 +163,11 @@ struct CMethodNamePair const char *Name; }; -static CMethodNamePair g_NamePairs[] = +static const CMethodNamePair g_NamePairs[] = { { XZ_ID_Subblock, "SB" }, { XZ_ID_Delta, "Delta" }, - { XZ_ID_X86, "x86" }, + { XZ_ID_X86, "BCJ" }, { XZ_ID_PPC, "PPC" }, { XZ_ID_IA64, "IA64" }, { XZ_ID_ARM, "ARM" }, @@ -439,7 +442,10 @@ struct CXzUnpackerCPP Byte *InBuf; Byte *OutBuf; CXzUnpacker p; - CXzUnpackerCPP(): InBuf(0), OutBuf(0) {} + CXzUnpackerCPP(): InBuf(0), OutBuf(0) + { + XzUnpacker_Construct(&p, &g_Alloc); + } ~CXzUnpackerCPP() { XzUnpacker_Free(&p); @@ -483,7 +489,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CCompressProgressWrap progressWrap(progress); - SRes res; + SRes res = S_OK; const UInt32 kInBufSize = 1 << 15; const UInt32 kOutBufSize = 1 << 21; @@ -492,8 +498,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt32 inSize = 0; UInt32 outPos = 0; CXzUnpackerCPP xzu; - res = XzUnpacker_Create(&xzu.p, &g_Alloc); - if (res == SZ_OK) + XzUnpacker_Init(&xzu.p); { xzu.InBuf = (Byte *)MyAlloc(kInBufSize); xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize); @@ -534,6 +539,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } outPos = 0; } + RINOK(lps->SetCur()); if (finished) { _packSize = lps->InSize; @@ -553,7 +559,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } break; } - RINOK(lps->SetCur()); } Int32 opRes; @@ -573,8 +578,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, return SResToHRESULT(res); } realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(opRes)); - return S_OK; + return extractCallback->SetOperationResult(opRes); COM_TRY_END } @@ -619,8 +623,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (IntToBool(newData)) { + UInt64 size; { - UInt64 size; NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(0, kpidSize, &prop)); if (prop.vt != VT_UI8) @@ -632,22 +636,26 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt CLzma2EncProps lzma2Props; Lzma2EncProps_Init(&lzma2Props); - lzma2Props.lzmaProps.level = _level; + lzma2Props.lzmaProps.level = GetLevel(); CMyComPtr<ISequentialInStream> fileInStream; RINOK(updateCallback->GetStream(0, &fileInStream)); CSeqInStreamWrap seqInStream(fileInStream); + { + NCOM::CPropVariant prop = (UInt64)size; + RINOK(NCompress::NLzma2::SetLzma2Prop(NCoderPropID::kReduceSize, prop, lzma2Props)); + } + for (int i = 0; i < _methods.Size(); i++) { COneMethodInfo &m = _methods[i]; - SetCompressionMethod2(m + SetGlobalLevelAndThreads(m #ifndef _7ZIP_ST , _numThreads #endif ); - if (m.IsLzma()) { for (int j = 0; j < m.Props.Size(); j++) { @@ -666,7 +674,40 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt lps->Init(updateCallback, true); CCompressProgressWrap progressWrap(progress); - SRes res = Xz_Encode(&seqOutStream.p, &seqInStream.p, &lzma2Props, False, &progressWrap.p); + CXzProps xzProps; + CXzFilterProps filter; + XzProps_Init(&xzProps); + XzFilterProps_Init(&filter); + xzProps.lzma2Props = &lzma2Props; + xzProps.filterProps = (_filterId != 0 ? &filter : NULL); + switch (_crcSize) + { + case 0: xzProps.checkId = XZ_CHECK_NO; break; + case 4: xzProps.checkId = XZ_CHECK_CRC32; break; + case 8: xzProps.checkId = XZ_CHECK_CRC64; break; + case 32: xzProps.checkId = XZ_CHECK_SHA256; break; + default: return E_INVALIDARG; + } + filter.id = _filterId; + if (_filterId == XZ_ID_Delta) + { + bool deltaDefined = false; + for (int j = 0; j < _filterMethod.Props.Size(); j++) + { + const CProp &prop = _filterMethod.Props[j]; + if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4) + { + UInt32 delta = (UInt32)prop.Value.ulVal; + if (delta < 1 || delta > 256) + return E_INVALIDARG; + filter.delta = delta; + deltaDefined = true; + } + } + if (!deltaDefined) + return E_INVALIDARG; + } + SRes res = Xz_Encode(&seqOutStream.p, &seqInStream.p, &xzProps, &progressWrap.p); if (res == SZ_OK) return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); return SResToHRESULT(res); @@ -678,14 +719,46 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return NCompress::CopyStream(_stream, outStream, 0); } +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) { COM_TRY_BEGIN - BeforeSetProperty(); + Init(); for (int i = 0; i < numProps; i++) { RINOK(SetProperty(names[i], values[i])); } + + if (!_filterMethod.MethodName.IsEmpty()) + { + int k; + for (k = 0; k < ARRAY_SIZE(g_NamePairs); k++) + { + const CMethodNamePair &pair = g_NamePairs[k]; + UString m = GetUnicodeString(pair.Name); + if (_filterMethod.MethodName.CompareNoCase(m) == 0) + { + _filterId = pair.Id; + break; + } + } + if (k == ARRAY_SIZE(g_NamePairs)) + return E_INVALIDARG; + } + + int numEmptyMethods = GetNumEmptyMethods(); + _methods.Delete(0, numEmptyMethods); + if (_methods.Size() > 1) + return E_INVALIDARG; + if (_methods.Size() == 1) + { + UString &methodName = _methods[0].MethodName; + if (methodName.IsEmpty()) + methodName = k_LZMA2_Name; + else if (methodName.CompareNoCase(k_LZMA2_Name) != 0) + return E_INVALIDARG; + } return S_OK; COM_TRY_END } diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp index 4c5fd38d..da42f3bd 100755 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp @@ -33,6 +33,7 @@ static const UInt32 kLzmaHeaderSize = 4 + kLzmaPropsSize; class CLzmaEncoder: public ICompressCoder, + public ICompressSetCoderProperties, public CMyUnknownImp { NCompress::NLzma::CEncoder *EncoderSpec; @@ -41,12 +42,12 @@ class CLzmaEncoder: public: STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - HRESULT SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); + STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); - MY_UNKNOWN_IMP + MY_UNKNOWN_IMP1(ICompressSetCoderProperties) }; -HRESULT CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) +STDMETHODIMP CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) { if (!Encoder) { @@ -67,7 +68,7 @@ HRESULT CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIAN return S_OK; } -HRESULT CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, +STDMETHODIMP CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) { RINOK(WriteStream(outStream, Header, kLzmaHeaderSize)); @@ -210,52 +211,12 @@ HRESULT CAddCommon::Compress( _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_LZMA; CLzmaEncoder *_lzmaEncoder = new CLzmaEncoder(); _compressEncoder = _lzmaEncoder; - NWindows::NCOM::CPropVariant props[] = - { - #ifndef _7ZIP_ST - _options.NumThreads, - #endif - _options.Algo, - _options.DicSize, - _options.NumFastBytes, - const_cast<BSTR>((const wchar_t *)_options.MatchFinder), - _options.NumMatchFinderCycles - }; - PROPID propIDs[] = - { - #ifndef _7ZIP_ST - NCoderPropID::kNumThreads, - #endif - NCoderPropID::kAlgorithm, - NCoderPropID::kDictionarySize, - NCoderPropID::kNumFastBytes, - NCoderPropID::kMatchFinder, - NCoderPropID::kMatchFinderCycles - }; - int numProps = sizeof(propIDs) / sizeof(propIDs[0]); - if (!_options.NumMatchFinderCyclesDefined) - numProps--; - RINOK(_lzmaEncoder->SetCoderProperties(propIDs, props, numProps)); } else if (method == NFileHeader::NCompressionMethod::kPPMd) { _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_PPMd; NCompress::NPpmdZip::CEncoder *encoder = new NCompress::NPpmdZip::CEncoder(); _compressEncoder = encoder; - NWindows::NCOM::CPropVariant props[] = - { - _options.Algo, - _options.MemSize, - _options.Order - - }; - PROPID propIDs[] = - { - NCoderPropID::kAlgorithm, - NCoderPropID::kUsedMemorySize, - NCoderPropID::kOrder - }; - RINOK(encoder->SetCoderProperties(propIDs, props, sizeof(propIDs) / sizeof(propIDs[0]))); } else { @@ -282,56 +243,20 @@ HRESULT CAddCommon::Compress( if (method == NFileHeader::NCompressionMethod::kDeflated || method == NFileHeader::NCompressionMethod::kDeflated64) { - NWindows::NCOM::CPropVariant props[] = - { - _options.Algo, - _options.NumPasses, - _options.NumFastBytes, - _options.NumMatchFinderCycles - }; - PROPID propIDs[] = - { - NCoderPropID::kAlgorithm, - NCoderPropID::kNumPasses, - NCoderPropID::kNumFastBytes, - NCoderPropID::kMatchFinderCycles - }; - int numProps = sizeof(propIDs) / sizeof(propIDs[0]); - if (!_options.NumMatchFinderCyclesDefined) - numProps--; - CMyComPtr<ICompressSetCoderProperties> setCoderProperties; - _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties); - if (setCoderProperties) - { - RINOK(setCoderProperties->SetCoderProperties(propIDs, props, numProps)); - } } else if (method == NFileHeader::NCompressionMethod::kBZip2) { - NWindows::NCOM::CPropVariant props[] = - { - _options.DicSize, - _options.NumPasses - #ifndef _7ZIP_ST - , _options.NumThreads - #endif - }; - PROPID propIDs[] = - { - NCoderPropID::kDictionarySize, - NCoderPropID::kNumPasses - #ifndef _7ZIP_ST - , NCoderPropID::kNumThreads - #endif - }; - CMyComPtr<ICompressSetCoderProperties> setCoderProperties; - _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties); - if (setCoderProperties) + } + } + { + CMyComPtr<ICompressSetCoderProperties> setCoderProps; + _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProps); + if (setCoderProps) { - RINOK(setCoderProperties->SetCoderProperties(propIDs, props, sizeof(propIDs) / sizeof(propIDs[0]))); + RINOK(_options.MethodInfo.SetCoderProps(setCoderProps, + _options._dataSizeReduceDefined ? &_options._dataSizeReduce : NULL)); } } - } } CMyComPtr<ISequentialOutStream> outStreamNew; if (_options.PasswordIsDefined) diff --git a/CPP/7zip/Archive/Zip/ZipCompressionMode.h b/CPP/7zip/Archive/Zip/ZipCompressionMode.h index 7ef7cfb2..5be33166 100755 --- a/CPP/7zip/Archive/Zip/ZipCompressionMode.h +++ b/CPP/7zip/Archive/Zip/ZipCompressionMode.h @@ -5,36 +5,54 @@ #include "Common/MyString.h" +#ifndef _7ZIP_ST +#include "../../../Windows/System.h" +#endif + +#include "../Common/HandlerOut.h" + namespace NArchive { namespace NZip { -struct CCompressionMethodMode +struct CBaseProps { - CRecordVector<Byte> MethodSequence; - UString MatchFinder; - UInt32 Algo; - UInt32 NumPasses; - UInt32 NumFastBytes; - bool NumMatchFinderCyclesDefined; - UInt32 NumMatchFinderCycles; - UInt32 DicSize; - UInt32 MemSize; - UInt32 Order; + CMethodProps MethodInfo; + Int32 Level; #ifndef _7ZIP_ST UInt32 NumThreads; + bool NumThreadsWasChanged; #endif - bool PasswordIsDefined; - AString Password; bool IsAesMode; Byte AesKeyMode; + + void Init() + { + MethodInfo.Clear(); + Level = -1; + #ifndef _7ZIP_ST + NumThreads = NWindows::NSystem::GetNumberOfProcessors();; + NumThreadsWasChanged = false; + #endif + IsAesMode = false; + AesKeyMode = 3; + } +}; + +struct CCompressionMethodMode: public CBaseProps +{ + CRecordVector<Byte> MethodSequence; + bool PasswordIsDefined; + AString Password; + + UInt64 _dataSizeReduce; + bool _dataSizeReduceDefined; - CCompressionMethodMode(): - NumMatchFinderCyclesDefined(false), - PasswordIsDefined(false), - IsAesMode(false), - AesKeyMode(3) - {} + CCompressionMethodMode(): PasswordIsDefined(false) + { + _dataSizeReduceDefined = false; + _dataSizeReduce = 0; + } }; }} diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp index bd156322..2281ed5b 100755 --- a/CPP/7zip/Archive/Zip/ZipHandler.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp @@ -107,7 +107,7 @@ static struct CStrongCryptoPair { NStrongCryptoFlags::kRC4, "RC4" } }; -static STATPROPSTG kProps[] = +static const STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidIsDir, VT_BOOL}, @@ -117,6 +117,7 @@ static STATPROPSTG kProps[] = { NULL, kpidCTime, VT_FILETIME}, { NULL, kpidATime, VT_FILETIME}, { NULL, kpidAttrib, VT_UI4}, + // { NULL, kpidPosixAttrib, VT_UI4}, { NULL, kpidEncrypted, VT_BOOL}, { NULL, kpidComment, VT_BSTR}, { NULL, kpidCRC, VT_UI4}, @@ -125,7 +126,7 @@ static STATPROPSTG kProps[] = { NULL, kpidUnpackVer, VT_UI4} }; -static STATPROPSTG kArcProps[] = +static const STATPROPSTG kArcProps[] = { { NULL, kpidBit64, VT_BOOL}, { NULL, kpidComment, VT_BSTR}, @@ -135,7 +136,7 @@ static STATPROPSTG kArcProps[] = CHandler::CHandler() { - InitMethodProperties(); + InitMethodProps(); } static AString BytesToString(const CByteBuffer &data) @@ -165,6 +166,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidComment: prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break; case kpidPhySize: prop = m_Archive.ArcInfo.GetPhySize(); break; case kpidOffset: if (m_Archive.ArcInfo.StartPosition != 0) prop = m_Archive.ArcInfo.StartPosition; break; + case kpidError: if (!m_Archive.IsOkHeaders) prop = "Incorrect headers"; break; } prop.Detach(value); COM_TRY_END @@ -194,7 +196,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val UInt32 unixTime; if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft)) prop = (UInt32)NFileTimeType::kWindows; - else if (item.CentralExtra.GetUnixTime(NFileHeader::NUnixTime::kMTime, unixTime)) + else if (item.CentralExtra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) prop = (UInt32)NFileTimeType::kUnix; else prop = (UInt32)NFileTimeType::kDOS; @@ -220,7 +222,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (!item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc)) { UInt32 unixTime; - if (item.CentralExtra.GetUnixTime(NFileHeader::NUnixTime::kMTime, unixTime)) + if (item.CentralExtra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) NTime::UnixTimeToFileTime(unixTime, utc); else { @@ -233,7 +235,14 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = utc; break; } - case kpidAttrib: prop = item.GetWinAttributes(); break; + case kpidAttrib: prop = item.GetWinAttrib(); break; + case kpidPosixAttrib: + { + UInt32 attrib; + if (item.GetPosixAttrib(attrib)) + prop = attrib; + break; + } case kpidEncrypted: prop = item.IsEncrypted(); break; case kpidComment: prop = item.GetUnicodeString(BytesToString(item.Comment)); break; case kpidCRC: if (item.IsThereCrc()) prop = item.FileCRC; break; @@ -435,7 +444,10 @@ public: ISequentialOutStream *realOutStream, IArchiveExtractCallback *extractCallback, ICompressProgressInfo *compressProgress, - UInt32 numThreads, Int32 &res); + #ifndef _7ZIP_ST + UInt32 numThreads, + #endif + Int32 &res); }; HRESULT CZipDecoder::Decode( @@ -444,7 +456,10 @@ HRESULT CZipDecoder::Decode( ISequentialOutStream *realOutStream, IArchiveExtractCallback *extractCallback, ICompressProgressInfo *compressProgress, - UInt32 numThreads, Int32 &res) + #ifndef _7ZIP_ST + UInt32 numThreads, + #endif + Int32 &res) { res = NExtract::NOperationResult::kDataError; CInStreamReleaser inStreamReleaser; @@ -805,15 +820,22 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->PrepareOperation(askMode)); Int32 res; - RINOK(myDecoder.Decode( + HRESULT hres = myDecoder.Decode( EXTERNAL_CODECS_VARS m_Archive, item, realOutStream, extractCallback, - progress, _numThreads, res)); + progress, + #ifndef _7ZIP_ST + _props.NumThreads, + #endif + res); + RINOK(hres); realOutStream.Release(); RINOK(extractCallback->SetOperationResult(res)) } - return S_OK; + lps->InSize = currentTotalPacked; + lps->OutSize = currentTotalUnPacked; + return lps->SetCur(); COM_TRY_END } diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h index fdb60aaf..33cf6fdc 100755 --- a/CPP/7zip/Archive/Zip/ZipHandler.h +++ b/CPP/7zip/Archive/Zip/ZipHandler.h @@ -12,10 +12,6 @@ #include "ZipIn.h" #include "ZipCompressionMode.h" -#ifndef _7ZIP_ST -#include "../../../Windows/System.h" -#endif - namespace NArchive { namespace NZip { @@ -46,53 +42,24 @@ private: CObjectVector<CItemEx> m_Items; CInArchive m_Archive; - int m_Level; - int m_MainMethod; - UInt32 m_DicSize; - UInt32 m_Algo; - UInt32 m_NumPasses; - UInt32 m_NumFastBytes; - UInt32 m_NumMatchFinderCycles; - UInt32 m_MemSize; - UInt32 m_Order; - - bool m_NumMatchFinderCyclesDefined; + CBaseProps _props; + int m_MainMethod; bool m_ForceAesMode; - bool m_IsAesMode; - Byte m_AesKeyMode; - bool m_WriteNtfsTimeExtra; bool m_ForceLocal; bool m_ForceUtf8; - #ifndef _7ZIP_ST - UInt32 _numThreads; - #endif - DECL_EXTERNAL_CODECS_VARS - void InitMethodProperties() + void InitMethodProps() { - m_Level = -1; + _props.Init(); m_MainMethod = -1; - m_Algo = - m_DicSize = - m_NumPasses = - m_NumFastBytes = - m_Order = - m_MemSize = - m_NumMatchFinderCycles = 0xFFFFFFFF; - m_NumMatchFinderCyclesDefined = false; m_ForceAesMode = false; - m_IsAesMode = false; - m_AesKeyMode = 3; // aes-256 m_WriteNtfsTimeExtra = true; m_ForceLocal = false; m_ForceUtf8 = false; - #ifndef _7ZIP_ST - _numThreads = NWindows::NSystem::GetNumberOfProcessors();; - #endif } }; diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp index a5e0f59d..427b0c31 100755 --- a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp @@ -28,37 +28,6 @@ using namespace NTime; namespace NArchive { namespace NZip { -static const UInt32 kLzAlgoX1 = 0; -static const UInt32 kLzAlgoX5 = 1; - -static const UInt32 kDeflateNumPassesX1 = 1; -static const UInt32 kDeflateNumPassesX7 = 3; -static const UInt32 kDeflateNumPassesX9 = 10; - -static const UInt32 kDeflateNumFastBytesX1 = 32; -static const UInt32 kDeflateNumFastBytesX7 = 64; -static const UInt32 kDeflateNumFastBytesX9 = 128; - -static const wchar_t *kLzmaMatchFinderX1 = L"HC4"; -static const wchar_t *kLzmaMatchFinderX5 = L"BT4"; - -static const UInt32 kLzmaNumFastBytesX1 = 32; -static const UInt32 kLzmaNumFastBytesX7 = 64; - -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 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; - STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) { *timeType = NFileTimeType::kDOS; @@ -99,6 +68,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt COM_TRY_BEGIN2 CObjectVector<CUpdateItem> updateItems; bool thereAreAesUpdates = false; + UInt64 largestSize = 0; + bool largestSizeDefined = false; for (UInt32 i = 0; i < numItems; i++) { CUpdateItem ui; @@ -178,7 +149,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt const wchar_t kSlash = L'/'; if (!name.IsEmpty()) { - if (name[name.Length() - 1] == kSlash) + if (name.Back() == kSlash) { if (!ui.IsDir) return E_INVALIDARG; @@ -235,6 +206,9 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (prop.vt != VT_UI8) return E_INVALIDARG; size = prop.uhVal.QuadPart; + if (largestSize < size) + largestSize = size; + largestSizeDefined = true; } ui.Size = size; } @@ -247,6 +221,9 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt udateCallBack2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword); } CCompressionMethodMode options; + (CBaseProps &)options = _props; + options._dataSizeReduce = largestSize; + options._dataSizeReduceDefined = largestSizeDefined; if (getTextPassword) { @@ -256,8 +233,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt options.PasswordIsDefined = IntToBool(passwordIsDefined); if (options.PasswordIsDefined) { - options.IsAesMode = (m_ForceAesMode ? m_IsAesMode : thereAreAesUpdates); - options.AesKeyMode = m_AesKeyMode; + if (!m_ForceAesMode) + options.IsAesMode = thereAreAesUpdates; if (!IsAsciiString((const wchar_t *)password)) return E_INVALIDARG; @@ -272,13 +249,9 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt else options.PasswordIsDefined = false; - int level = m_Level; - if (level < 0) - level = 5; - Byte mainMethod; if (m_MainMethod < 0) - mainMethod = (Byte)(((level == 0) ? + mainMethod = (Byte)(((_props.Level == 0) ? NFileHeader::NCompressionMethod::kStored : NFileHeader::NCompressionMethod::kDeflated)); else @@ -286,83 +259,6 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt options.MethodSequence.Add(mainMethod); if (mainMethod != NFileHeader::NCompressionMethod::kStored) options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStored); - bool isDeflate = (mainMethod == NFileHeader::NCompressionMethod::kDeflated) || - (mainMethod == NFileHeader::NCompressionMethod::kDeflated64); - bool isLZMA = (mainMethod == NFileHeader::NCompressionMethod::kLZMA); - bool isLz = (isLZMA || isDeflate); - options.NumPasses = m_NumPasses; - options.DicSize = m_DicSize; - options.NumFastBytes = m_NumFastBytes; - options.NumMatchFinderCycles = m_NumMatchFinderCycles; - options.NumMatchFinderCyclesDefined = m_NumMatchFinderCyclesDefined; - options.Algo = m_Algo; - options.MemSize = m_MemSize; - options.Order = m_Order; - #ifndef _7ZIP_ST - options.NumThreads = _numThreads; - #endif - if (isLz) - { - if (isDeflate) - { - if (options.NumPasses == 0xFFFFFFFF) - options.NumPasses = (level >= 9 ? kDeflateNumPassesX9 : - (level >= 7 ? kDeflateNumPassesX7 : - kDeflateNumPassesX1)); - if (options.NumFastBytes == 0xFFFFFFFF) - options.NumFastBytes = (level >= 9 ? kDeflateNumFastBytesX9 : - (level >= 7 ? kDeflateNumFastBytesX7 : - kDeflateNumFastBytesX1)); - } - else if (isLZMA) - { - if (options.DicSize == 0xFFFFFFFF) - options.DicSize = - (level >= 9 ? kLzmaDicSizeX9 : - (level >= 7 ? kLzmaDicSizeX7 : - (level >= 5 ? kLzmaDicSizeX5 : - (level >= 3 ? kLzmaDicSizeX3 : - kLzmaDicSizeX1)))); - - if (options.NumFastBytes == 0xFFFFFFFF) - options.NumFastBytes = (level >= 7 ? kLzmaNumFastBytesX7 : - kLzmaNumFastBytesX1); - - options.MatchFinder = - (level >= 5 ? kLzmaMatchFinderX5 : - kLzmaMatchFinderX1); - } - - if (options.Algo == 0xFFFFFFFF) - options.Algo = (level >= 5 ? kLzAlgoX5 : - kLzAlgoX1); - } - if (mainMethod == NFileHeader::NCompressionMethod::kBZip2) - { - if (options.NumPasses == 0xFFFFFFFF) - options.NumPasses = (level >= 9 ? kBZip2NumPassesX9 : - (level >= 7 ? kBZip2NumPassesX7 : - kBZip2NumPassesX1)); - if (options.DicSize == 0xFFFFFFFF) - options.DicSize = (level >= 5 ? kBZip2DicSizeX5 : - (level >= 3 ? kBZip2DicSizeX3 : - kBZip2DicSizeX1)); - } - if (mainMethod == NFileHeader::NCompressionMethod::kPPMd) - { - int level2 = level; - if (level2 < 1) level2 = 1; - if (level2 > 9) level2 = 9; - - if (options.MemSize == 0xFFFFFFFF) - options.MemSize = (1 << (19 + (level2 > 8 ? 8 : level2))); - - if (options.Order == 0xFFFFFFFF) - options.Order = 3 + level2; - - if (options.Algo == 0xFFFFFFFF) - options.Algo = (level2 >= 7 ? 1 : 0); - } return Update( EXTERNAL_CODECS_VARS @@ -371,16 +267,34 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt COM_TRY_END2 } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) +struct CMethodIndexToName +{ + unsigned Method; + const wchar_t *Name; +}; + +static const CMethodIndexToName k_SupportedMethods[] = { + { NFileHeader::NCompressionMethod::kStored, L"COPY" }, + { NFileHeader::NCompressionMethod::kDeflated, L"DEFLATE" }, + { NFileHeader::NCompressionMethod::kDeflated64, L"DEFLATE64" }, + { NFileHeader::NCompressionMethod::kBZip2, L"BZIP2" }, + { NFileHeader::NCompressionMethod::kLZMA, L"LZMA" }, + { NFileHeader::NCompressionMethod::kPPMd, L"PPMD" } +}; + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) +{ + InitMethodProps(); #ifndef _7ZIP_ST - const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); - _numThreads = numProcessors; + const UInt32 numProcessors = _props.NumThreads; #endif - InitMethodProperties(); - for (int i = 0; i < numProperties; i++) + + for (int i = 0; i < numProps; i++) { - UString name = UString(names[i]); + UString name = names[i]; name.MakeUpper(); if (name.IsEmpty()) return E_INVALIDARG; @@ -390,140 +304,112 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v if (name[0] == L'X') { UInt32 level = 9; - RINOK(ParsePropValue(name.Mid(1), prop, level)); - m_Level = level; - continue; + RINOK(ParsePropToUInt32(name.Mid(1), prop, level)); + _props.Level = level; + _props.MethodInfo.AddLevelProp(level); } else if (name == L"M") { if (prop.vt == VT_BSTR) { - UString m = prop.bstrVal; + UString m = prop.bstrVal, m2; m.MakeUpper(); - if (m == L"COPY") m_MainMethod = NFileHeader::NCompressionMethod::kStored; - else if (m == L"DEFLATE") m_MainMethod = NFileHeader::NCompressionMethod::kDeflated; - else if (m == L"DEFLATE64") m_MainMethod = NFileHeader::NCompressionMethod::kDeflated64; - else if (m == L"BZIP2") m_MainMethod = NFileHeader::NCompressionMethod::kBZip2; - else if (m == L"LZMA") m_MainMethod = NFileHeader::NCompressionMethod::kLZMA; - else if (m == L"PPMD") m_MainMethod = NFileHeader::NCompressionMethod::kPPMd; - else return E_INVALIDARG; + int colonPos = m.Find(L':'); + if (colonPos >= 0) + { + m2 = m.Mid(colonPos + 1); + m = m.Left(colonPos); + } + int k; + for (k = 0; k < ARRAY_SIZE(k_SupportedMethods); k++) + { + const CMethodIndexToName &pair = k_SupportedMethods[k]; + if (m == pair.Name) + { + if (!m2.IsEmpty()) + { + RINOK(_props.MethodInfo.ParseParamsFromString(m2)); + } + m_MainMethod = pair.Method; + break; + } + } + if (k == ARRAY_SIZE(k_SupportedMethods)) + return E_INVALIDARG; } else if (prop.vt == VT_UI4) { - switch(prop.ulVal) + int k; + for (k = 0; k < ARRAY_SIZE(k_SupportedMethods); k++) { - case NFileHeader::NCompressionMethod::kStored: - case NFileHeader::NCompressionMethod::kDeflated: - case NFileHeader::NCompressionMethod::kDeflated64: - case NFileHeader::NCompressionMethod::kBZip2: - case NFileHeader::NCompressionMethod::kLZMA: - m_MainMethod = (Byte)prop.ulVal; + unsigned method = k_SupportedMethods[k].Method; + if (prop.ulVal == method) + { + m_MainMethod = method; break; - default: - return E_INVALIDARG; + } } + if (k == ARRAY_SIZE(k_SupportedMethods)) + return E_INVALIDARG; } else return E_INVALIDARG; } else if (name.Left(2) == L"EM") { - if (prop.vt == VT_BSTR) + if (prop.vt != VT_BSTR) + return E_INVALIDARG; { - UString valueString = prop.bstrVal; - valueString.MakeUpper(); - if (valueString.Left(3) == L"AES") + UString m = prop.bstrVal; + m.MakeUpper(); + if (m.Left(3) == L"AES") { - valueString = valueString.Mid(3); - if (valueString == L"128") - m_AesKeyMode = 1; - else if (valueString == L"192") - m_AesKeyMode = 2; - else if (valueString == L"256" || valueString.IsEmpty()) - m_AesKeyMode = 3; + m = m.Mid(3); + if (m == L"128") + _props.AesKeyMode = 1; + else if (m == L"192") + _props.AesKeyMode = 2; + else if (m == L"256" || m.IsEmpty()) + _props.AesKeyMode = 3; else return E_INVALIDARG; - m_IsAesMode = true; + _props.IsAesMode = true; m_ForceAesMode = true; } - else if (valueString == L"ZIPCRYPTO") + else if (m == L"ZIPCRYPTO") { - m_IsAesMode = false; + _props.IsAesMode = false; m_ForceAesMode = true; } else return E_INVALIDARG; } - else - return E_INVALIDARG; - } - else if (name[0] == L'D') - { - UInt32 dicSize = kBZip2DicSizeX5; - RINOK(ParsePropDictionaryValue(name.Mid(1), prop, dicSize)); - m_DicSize = dicSize; - } - else if (name.Left(3) == L"MEM") - { - UInt32 memSize = 1 << 24; - RINOK(ParsePropDictionaryValue(name.Mid(3), prop, memSize)); - m_MemSize = memSize; - } - else if (name[0] == L'O') - { - UInt32 order = 8; - RINOK(ParsePropValue(name.Mid(1), prop, order)); - m_Order = order; - } - else if (name.Left(4) == L"PASS") - { - UInt32 num = kDeflateNumPassesX9; - RINOK(ParsePropValue(name.Mid(4), prop, num)); - m_NumPasses = num; - } - else if (name.Left(2) == L"FB") - { - UInt32 num = kDeflateNumFastBytesX9; - RINOK(ParsePropValue(name.Mid(2), prop, num)); - m_NumFastBytes = num; - } - else if (name.Left(2) == L"MC") - { - UInt32 num = 0xFFFFFFFF; - RINOK(ParsePropValue(name.Mid(2), prop, num)); - m_NumMatchFinderCycles = num; - m_NumMatchFinderCyclesDefined = true; } else if (name.Left(2) == L"MT") { #ifndef _7ZIP_ST - RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _numThreads)); + RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _props.NumThreads)); + _props.NumThreadsWasChanged = true; #endif } - else if (name.Left(1) == L"A") - { - UInt32 num = kLzAlgoX5; - RINOK(ParsePropValue(name.Mid(1), prop, num)); - m_Algo = num; - } else if (name.CompareNoCase(L"TC") == 0) { - RINOK(SetBoolProperty(m_WriteNtfsTimeExtra, prop)); + RINOK(PROPVARIANT_to_bool(prop, m_WriteNtfsTimeExtra)); } else if (name.CompareNoCase(L"CL") == 0) { - RINOK(SetBoolProperty(m_ForceLocal, prop)); + RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal)); if (m_ForceLocal) m_ForceUtf8 = false; } else if (name.CompareNoCase(L"CU") == 0) { - RINOK(SetBoolProperty(m_ForceUtf8, prop)); + RINOK(PROPVARIANT_to_bool(prop, m_ForceUtf8)); if (m_ForceUtf8) m_ForceLocal = false; } else - return E_INVALIDARG; + return _props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop); } return S_OK; } diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index b36b61be..e930488f 100755 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -756,6 +756,7 @@ void CEcd64::Parse(const Byte *p) HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress) { + IsOkHeaders = true; // m_Signature must be kLocalFileHeaderSignature or // kEndOfCentralDirSignature // m_Position points to next byte after signature @@ -852,6 +853,8 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *pr if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported); + if (numCdItems != items.Size()) + IsOkHeaders = false; if ((UInt16)ecd64.numEntriesInCDOnThisDisk != ((UInt16)numCdItems) || (UInt16)ecd64.numEntriesInCD != ((UInt16)numCdItems) || (UInt32)ecd64.cdSize != (UInt32)cdSize || @@ -861,7 +864,6 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *pr _inBufMode = false; _inBuffer.Free(); - IsOkHeaders = (numCdItems == items.Size()); ArcInfo.FinishPosition = m_Position; return S_OK; } diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp index 139b0129..ad89f558 100755 --- a/CPP/7zip/Archive/Zip/ZipItem.cpp +++ b/CPP/7zip/Archive/Zip/ZipItem.cpp @@ -51,7 +51,7 @@ bool CExtraSubBlock::ExtractNtfsTime(int index, FILETIME &ft) const return false; } -bool CExtraSubBlock::ExtractUnixTime(int index, UInt32 &res) const +bool CExtraSubBlock::ExtractUnixTime(bool isCentral, int index, UInt32 &res) const { res = 0; UInt32 size = (UInt32)Data.GetCapacity(); @@ -60,6 +60,15 @@ bool CExtraSubBlock::ExtractUnixTime(int index, UInt32 &res) const const Byte *p = (const Byte *)Data; Byte flags = *p++; size--; + if (isCentral) + { + if (index != NFileHeader::NUnixTime::kMTime || + (flags & (1 << NFileHeader::NUnixTime::kMTime)) == 0 || + size < 4) + return false; + res = GetUi32(p); + return true; + } for (int i = 0; i < 3; i++) if ((flags & (1 << i)) != 0) { @@ -88,7 +97,7 @@ bool CItem::IsDir() const if (!FromCentral) return false; WORD highAttributes = WORD((ExternalAttributes >> 16 ) & 0xFFFF); - switch(MadeByVersion.HostOS) + switch (MadeByVersion.HostOS) { case NFileHeader::NHostOS::kAMIGA: switch (highAttributes & NFileHeader::NAmigaAttribute::kIFMT) @@ -109,44 +118,41 @@ bool CItem::IsDir() const case NFileHeader::NHostOS::kAcorn: case NFileHeader::NHostOS::kMVS: return false; // change it throw kUnknownAttributes; + case NFileHeader::NHostOS::kUnix: + return (highAttributes & NFileHeader::NUnixAttribute::kIFDIR) != 0; default: - /* - switch (highAttributes & NFileHeader::NUnixAttribute::kIFMT) - { - case NFileHeader::NUnixAttribute::kIFDIR: - return true; - default: - return false; - } - */ return false; } } -UInt32 CLocalItem::GetWinAttributes() const -{ - DWORD winAttributes = 0; - if (IsDir()) - winAttributes |= FILE_ATTRIBUTE_DIRECTORY; - return winAttributes; -} - -UInt32 CItem::GetWinAttributes() const +UInt32 CItem::GetWinAttrib() const { - DWORD winAttributes = 0; - switch(MadeByVersion.HostOS) + DWORD winAttrib = 0; + switch (MadeByVersion.HostOS) { case NFileHeader::NHostOS::kFAT: case NFileHeader::NHostOS::kNTFS: if (FromCentral) - winAttributes = ExternalAttributes; + winAttrib = ExternalAttributes; break; - default: - winAttributes = 0; // must be converted from unix value; } - if (IsDir()) // test it; - winAttributes |= FILE_ATTRIBUTE_DIRECTORY; - return winAttributes; + if (IsDir()) // test it; + winAttrib |= FILE_ATTRIBUTE_DIRECTORY; + return winAttrib; +} + +bool CItem::GetPosixAttrib(UInt32 &attrib) const +{ + // some archivers can store PosixAttrib in high 16 bits even with HostOS=FAT. + if (FromCentral && MadeByVersion.HostOS == NFileHeader::NHostOS::kUnix) + { + attrib = ExternalAttributes >> 16; + return (attrib != 0); + } + attrib = 0; + if (IsDir()) + attrib = NFileHeader::NUnixAttribute::kIFDIR; + return false; } void CLocalItem::SetFlagBits(int startBitNumber, int numBits, int value) diff --git a/CPP/7zip/Archive/Zip/ZipItem.h b/CPP/7zip/Archive/Zip/ZipItem.h index 31f2de73..5efd433a 100755 --- a/CPP/7zip/Archive/Zip/ZipItem.h +++ b/CPP/7zip/Archive/Zip/ZipItem.h @@ -3,7 +3,6 @@ #ifndef __ARCHIVE_ZIP_ITEM_H #define __ARCHIVE_ZIP_ITEM_H -#include "Common/Types.h" #include "Common/MyString.h" #include "Common/Buffer.h" #include "Common/UTFConvert.h" @@ -28,7 +27,7 @@ struct CExtraSubBlock UInt16 ID; CByteBuffer Data; bool ExtractNtfsTime(int index, FILETIME &ft) const; - bool ExtractUnixTime(int index, UInt32 &res) const; + bool ExtractUnixTime(bool isCentral, int index, UInt32 &res) const; }; struct CWzAesExtraField @@ -152,13 +151,13 @@ struct CExtraBlock return false; } - bool GetUnixTime(int index, UInt32 &res) const + bool GetUnixTime(bool isCentral, int index, UInt32 &res) const { for (int i = 0; i < SubBlocks.Size(); i++) { const CExtraSubBlock &sb = SubBlocks[i]; if (sb.ID == NFileHeader::NExtraID::kUnixTime) - return sb.ExtractUnixTime(index, res); + return sb.ExtractUnixTime(isCentral, index, res); } return false; } @@ -205,7 +204,6 @@ public: bool IsDir() const; bool IgnoreItem() const { return false; } - UInt32 GetWinAttributes() const; bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; } @@ -252,7 +250,8 @@ public: bool NtfsTimeIsDefined; bool IsDir() const; - UInt32 GetWinAttributes() const; + UInt32 GetWinAttrib() const; + bool GetPosixAttrib(UInt32 &attrib) const; bool IsThereCrc() const { @@ -277,5 +276,3 @@ public: }} #endif - - diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index d4fdee3d..490d9e26 100755 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -473,6 +473,9 @@ static HRESULT Update2St( items.Add(item); lps->ProgressOffset += NFileHeader::kLocalBlockSize; } + lps->InSize = unpackSizeTotal; + lps->OutSize = packSizeTotal; + RINOK(lps->SetCur()); archive.WriteCentralDir(items, comment); return S_OK; } @@ -493,7 +496,7 @@ static HRESULT Update2( UInt64 numBytesToCompress = 0; int i; - for(i = 0; i < updateItems.Size(); i++) + for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; if (ui.NewData) @@ -527,6 +530,10 @@ static HRESULT Update2( complexity = 0; + CCompressionMethodMode options2; + if (options != 0) + options2 = *options; + #ifndef _7ZIP_ST const size_t kNumMaxThreads = (1 << 10); @@ -537,53 +544,58 @@ static HRESULT Update2( const size_t kMemPerThread = (1 << 25); const size_t kBlockSize = 1 << 16; - CCompressionMethodMode options2; - if (options != 0) - options2 = *options; - bool mtMode = ((options != 0) && (numThreads > 1)); if (numFilesToCompress <= 1) mtMode = false; - if (mtMode) + if (!mtMode) + { + if (numThreads < 2) + if (options2.MethodInfo.FindProp(NCoderPropID::kNumThreads) < 0 && + options2.NumThreadsWasChanged) + options2.MethodInfo.AddNumThreadsProp(1); + } + else { Byte method = options->MethodSequence.Front(); if (method == NFileHeader::NCompressionMethod::kStored && !options->PasswordIsDefined) - mtMode = false; + numThreads = 1; if (method == NFileHeader::NCompressionMethod::kBZip2) { - UInt64 averageSize = numBytesToCompress / numFilesToCompress; - UInt32 blockSize = options->DicSize; - if (blockSize == 0) - blockSize = 1; - UInt64 averageNumberOfBlocks = averageSize / blockSize; - UInt32 numBZip2Threads = 32; - if (averageNumberOfBlocks < numBZip2Threads) - numBZip2Threads = (UInt32)averageNumberOfBlocks; - if (numBZip2Threads < 1) - numBZip2Threads = 1; - numThreads = numThreads / numBZip2Threads; - options2.NumThreads = numBZip2Threads; - if (numThreads <= 1) - mtMode = false; + bool fixedNumber; + UInt32 numBZip2Threads = options2.MethodInfo.Get_BZip2_NumThreads(fixedNumber); + if (!fixedNumber) + { + UInt64 averageSize = numBytesToCompress / numFilesToCompress; + UInt32 blockSize = options2.MethodInfo.Get_BZip2_BlockSize(); + UInt64 averageNumberOfBlocks = averageSize / blockSize + 1; + numBZip2Threads = 32; + if (averageNumberOfBlocks < numBZip2Threads) + numBZip2Threads = (UInt32)averageNumberOfBlocks; + options2.MethodInfo.AddNumThreadsProp(numBZip2Threads); + } + numThreads /= numBZip2Threads; } if (method == NFileHeader::NCompressionMethod::kLZMA) { - UInt32 numLZMAThreads = (options->Algo > 0 ? 2 : 1); + bool fixedNumber; + // we suppose that default LZMA is 2 thread. So we don't change it + UInt32 numLZMAThreads = options2.MethodInfo.Get_Lzma_NumThreads(fixedNumber); numThreads /= numLZMAThreads; - options2.NumThreads = numLZMAThreads; - if (numThreads <= 1) - mtMode = false; } + if (numThreads > numFilesToCompress) + numThreads = (UInt32)numFilesToCompress; + if (numThreads <= 1) + mtMode = false; } if (!mtMode) #endif return Update2St( EXTERNAL_CODECS_LOC_VARS - archive, inArchive,inStream, - inputItems, updateItems, options, comment, updateCallback); + archive, inArchive, inStream, + inputItems, updateItems, &options2, comment, updateCallback); #ifndef _7ZIP_ST @@ -606,7 +618,7 @@ static HRESULT Update2( { RINOK(memManager.AllocateSpaceAlways((size_t)numThreads * (kMemPerThread / kBlockSize))); - for(i = 0; i < updateItems.Size(); i++) + for (i = 0; i < updateItems.Size(); i++) refs.Refs.Add(CMemBlocks2()); UInt32 i; @@ -796,6 +808,7 @@ static HRESULT Update2( mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); itemIndex++; } + RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL)); archive.WriteCentralDir(items, comment); return S_OK; #endif |