diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2021-11-29 06:03:01 +0300 |
---|---|---|
committer | fn ⌃ ⌥ <70830482+FnControlOption@users.noreply.github.com> | 2021-11-29 06:03:01 +0300 |
commit | 1194dc935382931bbfdd4e49004bd755e6165df1 (patch) | |
tree | 60354d8832278528f74c48ca3b5e446175747409 /CPP/7zip | |
parent | d789d4137d8a7c16696c5bc1b13f24bb887eb7ea (diff) |
21.0421.04
Diffstat (limited to 'CPP/7zip')
121 files changed, 5698 insertions, 871 deletions
diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.h b/CPP/7zip/Archive/7z/7zCompressionMode.h index 44c90226..9e846345 100644 --- a/CPP/7zip/Archive/7z/7zCompressionMode.h +++ b/CPP/7zip/Archive/7z/7zCompressionMode.h @@ -14,8 +14,10 @@ struct CMethodFull: public CMethodProps CMethodId Id; UInt32 NumStreams; int CodecIndex; + UInt32 NumThreads; + bool Set_NumThreads; - CMethodFull(): CodecIndex(-1) {} + CMethodFull(): CodecIndex(-1), NumThreads(1), Set_NumThreads(false) {} bool IsSimpleCoder() const { return NumStreams == 1; } }; @@ -53,8 +55,12 @@ struct CCompressionMethodMode #ifndef _7ZIP_ST UInt32 NumThreads; + bool NumThreads_WasForced; bool MultiThreadMixer; #endif + + UInt64 MemoryUsageLimit; + bool MemoryUsageLimit_WasSet; bool PasswordIsDefined; UString Password; // _Wipe @@ -65,8 +71,11 @@ struct CCompressionMethodMode , Filter_was_Inserted(false) #ifndef _7ZIP_ST , NumThreads(1) + , NumThreads_WasForced(false) , MultiThreadMixer(true) #endif + , MemoryUsageLimit((UInt64)1 << 30) + , MemoryUsageLimit_WasSet(false) , PasswordIsDefined(false) {} diff --git a/CPP/7zip/Archive/7z/7zEncode.cpp b/CPP/7zip/Archive/7z/7zEncode.cpp index 49963241..83b0f18f 100644 --- a/CPP/7zip/Archive/7z/7zEncode.cpp +++ b/CPP/7zip/Archive/7z/7zEncode.cpp @@ -175,12 +175,16 @@ HRESULT CEncoder::CreateMixerCoder( CMyComPtr<IUnknown> encoderCommon = cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2; #ifndef _7ZIP_ST + if (methodFull.Set_NumThreads) { CMyComPtr<ICompressSetCoderMt> setCoderMt; encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); if (setCoderMt) { - RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads)); + RINOK(setCoderMt->SetNumberOfThreads( + /* _options.NumThreads */ + methodFull.NumThreads + )); } } #endif diff --git a/CPP/7zip/Archive/7z/7zExtract.cpp b/CPP/7zip/Archive/7z/7zExtract.cpp index 95eba9af..8ca815d4 100644 --- a/CPP/7zip/Archive/7z/7zExtract.cpp +++ b/CPP/7zip/Archive/7z/7zExtract.cpp @@ -374,7 +374,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, _7Z_DECODER_CRYPRO_VARS #if !defined(_7ZIP_ST) - , true, _numThreads, _memUsage + , true, _numThreads, _memUsage_Decompress #endif ); diff --git a/CPP/7zip/Archive/7z/7zHandler.h b/CPP/7zip/Archive/7z/7zHandler.h index cad1ae61..cbc2d028 100644 --- a/CPP/7zip/Archive/7z/7zHandler.h +++ b/CPP/7zip/Archive/7z/7zHandler.h @@ -158,12 +158,7 @@ private: HRESULT PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m); HRESULT SetHeaderMethod(CCompressionMethodMode &headerMethod); - HRESULT SetMainMethod(CCompressionMethodMode &method - #ifndef _7ZIP_ST - , UInt32 numThreads - #endif - ); - + HRESULT SetMainMethod(CCompressionMethodMode &method); #endif diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp index 8bb87341..923ad105 100644 --- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp +++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp @@ -69,15 +69,12 @@ HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod) return PropsMethod_To_FullMethod(methodFull, m); } -HRESULT CHandler::SetMainMethod( - CCompressionMethodMode &methodMode - #ifndef _7ZIP_ST - , UInt32 numThreads - #endif - ) + +HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode) { methodMode.Bonds = _bonds; + // we create local copy of _methods. So we can modify it. CObjectVector<COneMethodInfo> methods = _methods; { @@ -120,19 +117,25 @@ HRESULT CHandler::SetMainMethod( COneMethodInfo &oneMethodInfo = methods[i]; SetGlobalLevelTo(oneMethodInfo); + #ifndef _7ZIP_ST - CMultiMethodProps::SetMethodThreadsTo(oneMethodInfo, numThreads); + const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0); + if (!numThreads_WasSpecifiedInMethod) + { + // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already + CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, methodMode.NumThreads); + } #endif CMethodFull &methodFull = methodMode.Methods.AddNew(); RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo)); + methodFull.Set_NumThreads = true; + methodFull.NumThreads = methodMode.NumThreads; + if (methodFull.Id != k_Copy) needSolid = true; - if (_numSolidBytesDefined) - continue; - UInt64 dicSize; switch (methodFull.Id) { @@ -145,9 +148,13 @@ HRESULT CHandler::SetMainMethod( default: continue; } + UInt64 numSolidBytes; + if (methodFull.Id == k_LZMA2) { // he we calculate default chunk Size for LZMA2 as defined in LZMA2 encoder code + /* lzma2 code use dictionary upo to fake 4 GiB to calculate ChunkSize. + So we do same */ UInt64 cs = (UInt64)dicSize << 2; const UInt32 kMinSize = (UInt32)1 << 20; const UInt32 kMaxSize = (UInt32)1 << 28; @@ -157,20 +164,78 @@ HRESULT CHandler::SetMainMethod( cs += (kMinSize - 1); cs &= ~(UInt64)(kMinSize - 1); // we want to use at least 64 chunks (threads) per one solid block. - _numSolidBytes = cs << 6; + + // here we don't use chunckSize property + numSolidBytes = cs << 6; + + // here we get real chunckSize + cs = oneMethodInfo.Get_Xz_BlockSize(); + if (dicSize > cs) + dicSize = cs; + const UInt64 kSolidBytes_Lzma2_Max = ((UInt64)1 << 34); - if (_numSolidBytes > kSolidBytes_Lzma2_Max) - _numSolidBytes = kSolidBytes_Lzma2_Max; + if (numSolidBytes > kSolidBytes_Lzma2_Max) + numSolidBytes = kSolidBytes_Lzma2_Max; + + methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder + + #ifndef _7ZIP_ST + if (!numThreads_WasSpecifiedInMethod + && !methodMode.NumThreads_WasForced + && methodMode.MemoryUsageLimit_WasSet + ) + { + const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads(); + const UInt32 numBlockThreads_Original = methodMode.NumThreads / lzmaThreads; + + if (numBlockThreads_Original > 1) + { + /* + const UInt32 kNumThreads_Max = 1024; + if (numBlockThreads > kNumMaxThreads) + numBlockThreads = kNumMaxThreads; + */ + + UInt32 numBlockThreads = numBlockThreads_Original; + const UInt64 lzmaMemUsage = oneMethodInfo.Get_Lzma_MemUsage(false); // solid + + for (; numBlockThreads > 1; numBlockThreads--) + { + UInt64 size = numBlockThreads * (lzmaMemUsage + cs); + UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1; + if (cs < ((UInt32)1 << 26)) numPackChunks++; + if (cs < ((UInt32)1 << 24)) numPackChunks++; + if (cs < ((UInt32)1 << 22)) numPackChunks++; + size += numPackChunks * cs; + // printf("\nnumBlockThreads = %d, size = %d\n", (unsigned)(numBlockThreads), (unsigned)(size >> 20)); + if (size <= methodMode.MemoryUsageLimit) + break; + } + + if (numBlockThreads == 0) + numBlockThreads = 1; + if (numBlockThreads != numBlockThreads_Original) + { + const UInt32 numThreads_New = numBlockThreads * lzmaThreads; + CMultiMethodProps::SetMethodThreadsTo_Replace(methodFull, numThreads_New); + } + } + } + #endif } else { - _numSolidBytes = (UInt64)dicSize << 7; - if (_numSolidBytes > kSolidBytes_Max) - _numSolidBytes = kSolidBytes_Max; + numSolidBytes = (UInt64)dicSize << 7; + if (numSolidBytes > kSolidBytes_Max) + numSolidBytes = kSolidBytes_Max; } - if (_numSolidBytes < kSolidBytes_Min) - _numSolidBytes = kSolidBytes_Min; + if (_numSolidBytesDefined) + continue; + + if (numSolidBytes < kSolidBytes_Min) + numSolidBytes = kSolidBytes_Min; + _numSolidBytes = numSolidBytes; _numSolidBytesDefined = true; } @@ -182,9 +247,13 @@ HRESULT CHandler::SetMainMethod( _numSolidBytes = 0; } _numSolidBytesDefined = true; + + return S_OK; } + + static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, unsigned index, PROPID propID, UInt64 &ft, bool &ftDefined) { // ft = 0; @@ -576,22 +645,28 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt CCompressionMethodMode methodMode, headerMethod; - HRESULT res = SetMainMethod(methodMode - #ifndef _7ZIP_ST - , _numThreads - #endif - ); - RINOK(res); + methodMode.MemoryUsageLimit = _memUsage_Compress; + methodMode.MemoryUsageLimit_WasSet = _memUsage_WasSet; - RINOK(SetHeaderMethod(headerMethod)); - #ifndef _7ZIP_ST - methodMode.NumThreads = _numThreads; - methodMode.MultiThreadMixer = _useMultiThreadMixer; - headerMethod.NumThreads = 1; - headerMethod.MultiThreadMixer = _useMultiThreadMixer; + { + UInt32 numThreads = _numThreads; + const UInt32 kNumThreads_Max = 1024; + if (numThreads > kNumThreads_Max) + numThreads = kNumThreads_Max; + methodMode.NumThreads = numThreads; + methodMode.NumThreads_WasForced = _numThreads_WasForced; + methodMode.MultiThreadMixer = _useMultiThreadMixer; + // headerMethod.NumThreads = 1; + headerMethod.MultiThreadMixer = _useMultiThreadMixer; + } #endif + HRESULT res = SetMainMethod(methodMode); + RINOK(res); + + RINOK(SetHeaderMethod(headerMethod)); + CMyComPtr<ICryptoGetTextPassword2> getPassword2; updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2); diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp index 972a766a..bd673fcc 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.cpp +++ b/CPP/7zip/Archive/Common/HandlerOut.cpp @@ -70,15 +70,22 @@ bool CCommonMethodProps::SetCommonProperty(const UString &name, const PROPVARIAN if (name.IsPrefixedBy_Ascii_NoCase("mt")) { #ifndef _7ZIP_ST - hres = ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads); + _numThreads = _numProcessors; + _numThreads_WasForced = false; + hres = ParseMtProp2(name.Ptr(2), value, _numThreads, _numThreads_WasForced); + // "mt" means "_numThreads_WasForced = false" here #endif return true; } if (name.IsPrefixedBy_Ascii_NoCase("memuse")) { - if (!ParseSizeString(name.Ptr(6), value, _memAvail, _memUsage)) + UInt64 v; + if (!ParseSizeString(name.Ptr(6), value, _memAvail, v)) hres = E_INVALIDARG; + _memUsage_Decompress = v; + _memUsage_Compress = v; + _memUsage_WasSet = true; return true; } @@ -88,12 +95,24 @@ bool CCommonMethodProps::SetCommonProperty(const UString &name, const PROPVARIAN #ifndef EXTRACT_ONLY -static void SetMethodProp32(COneMethodInfo &m, PROPID propID, UInt32 value) +static void SetMethodProp32(CMethodProps &m, PROPID propID, UInt32 value) { if (m.FindProp(propID) < 0) m.AddProp32(propID, value); } +static void SetMethodProp32_Replace(CMethodProps &m, PROPID propID, UInt32 value) +{ + const int i = m.FindProp(propID); + if (i >= 0) + { + NWindows::NCOM::CPropVariant &val = m.Props[(unsigned)i].Value; + val = (UInt32)value; + return; + } + m.AddProp32(propID, value); +} + void CMultiMethodProps::SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const { UInt32 level = _level; @@ -102,10 +121,15 @@ void CMultiMethodProps::SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const } #ifndef _7ZIP_ST -void CMultiMethodProps::SetMethodThreadsTo(COneMethodInfo &oneMethodInfo, UInt32 numThreads) +void CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(CMethodProps &oneMethodInfo, UInt32 numThreads) { SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); } + +void CMultiMethodProps::SetMethodThreadsTo_Replace(CMethodProps &oneMethodInfo, UInt32 numThreads) +{ + SetMethodProp32_Replace(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); +} #endif void CMultiMethodProps::InitMulti() diff --git a/CPP/7zip/Archive/Common/HandlerOut.h b/CPP/7zip/Archive/Common/HandlerOut.h index bbb4336e..619def42 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.h +++ b/CPP/7zip/Archive/Common/HandlerOut.h @@ -18,15 +18,26 @@ protected: { #ifndef _7ZIP_ST _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors(); + _numThreads_WasForced = false; #endif UInt64 memAvail = (UInt64)(sizeof(size_t)) << 28; _memAvail = memAvail; - _memUsage = memAvail; - if (NWindows::NSystem::GetRamSize(memAvail)) + _memUsage_Compress = memAvail; + _memUsage_Decompress = memAvail; + _memUsage_WasSet = NWindows::NSystem::GetRamSize(memAvail); + if (_memUsage_WasSet) { _memAvail = memAvail; - _memUsage = memAvail / 32 * 17; + unsigned bits = sizeof(size_t) * 8; + if (bits == 32) + { + const UInt32 limit2 = (UInt32)7 << 28; + if (memAvail > limit2) + memAvail = limit2; + } + _memUsage_Compress = memAvail / 32 * 28; + _memUsage_Decompress = memAvail / 32 * 17; } } @@ -34,9 +45,12 @@ public: #ifndef _7ZIP_ST UInt32 _numThreads; UInt32 _numProcessors; + bool _numThreads_WasForced; #endif - UInt64 _memUsage; + bool _memUsage_WasSet; + UInt64 _memUsage_Compress; + UInt64 _memUsage_Decompress; UInt64 _memAvail; bool SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres); @@ -63,7 +77,8 @@ public: void SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const; #ifndef _7ZIP_ST - static void SetMethodThreadsTo(COneMethodInfo &oneMethodInfo, UInt32 numThreads); + static void SetMethodThreadsTo_IfNotFinded(CMethodProps &props, UInt32 numThreads); + static void SetMethodThreadsTo_Replace(CMethodProps &props, UInt32 numThreads); #endif diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp index 57313280..b70a291f 100644 --- a/CPP/7zip/Archive/HfsHandler.cpp +++ b/CPP/7zip/Archive/HfsHandler.cpp @@ -1513,6 +1513,9 @@ STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE; return S_OK; } + #else + UNUSED_VAR(index); + UNUSED_VAR(propID); #endif return S_OK; } diff --git a/CPP/7zip/Archive/IArchive.h b/CPP/7zip/Archive/IArchive.h index 8290c735..6df76d26 100644 --- a/CPP/7zip/Archive/IArchive.h +++ b/CPP/7zip/Archive/IArchive.h @@ -59,6 +59,7 @@ namespace NArcInfoFlags const UInt32 kSymLinks = 1 << 10; // the handler supports symbolic links const UInt32 kHardLinks = 1 << 11; // the handler supports hard links const UInt32 kByExtOnlyOpen = 1 << 12; // call handler only if file extension matches + const UInt32 kHashHandler = 1 << 13; // the handler contains the hashes (checksums) } namespace NArchive @@ -91,7 +92,8 @@ namespace NArchive { kExtract = 0, kTest, - kSkip + kSkip, + kReadExternal }; } @@ -458,7 +460,8 @@ namespace NUpdateNotifyOp kRepack, kSkip, kDelete, - kHeader + kHeader, + kHashRead // kNumDefined }; @@ -481,6 +484,14 @@ ARCHIVE_INTERFACE(IArchiveUpdateCallbackFile, 0x83) }; +#define INTERFACE_IArchiveGetDiskProperty(x) \ + STDMETHOD(GetDiskProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \ + +ARCHIVE_INTERFACE(IArchiveGetDiskProperty, 0x84) +{ + INTERFACE_IArchiveGetDiskProperty(PURE); +}; + /* UpdateItems() ------------- diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp index bc00e3fc..c1073092 100644 --- a/CPP/7zip/Archive/Tar/TarHandler.cpp +++ b/CPP/7zip/Archive/Tar/TarHandler.cpp @@ -763,6 +763,9 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR _forceCodePage = true; _curCodePage = _specifiedCodePage = cp; } + else if (name.IsPrefixedBy_Ascii_NoCase("mt")) + { + } else return E_INVALIDARG; } diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp index 520ceeea..04d9228f 100644 --- a/CPP/7zip/Archive/Udf/UdfIn.cpp +++ b/CPP/7zip/Archive/Udf/UdfIn.cpp @@ -109,7 +109,7 @@ static UString ParseDString(const Byte *data, unsigned size) } } else - return UString("[unknow]"); + return UString("[unknown]"); *p = 0; res.ReleaseBuf_SetLen((unsigned)(p - (const wchar_t *)res)); } diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp index 2553c175..b25d51c2 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.cpp +++ b/CPP/7zip/Archive/Wim/WimHandler.cpp @@ -877,8 +877,10 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal curStream = inStream; else { - UString fullName = seqName.GetNextName(i); - HRESULT result = openVolumeCallback->GetStream(fullName, &curStream); + if (!openVolumeCallback) + continue; + const UString fullName = seqName.GetNextName(i); + const HRESULT result = openVolumeCallback->GetStream(fullName, &curStream); if (result == S_FALSE) continue; if (result != S_OK) diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp index 35dd607a..b5a1972d 100644 --- a/CPP/7zip/Archive/XarHandler.cpp +++ b/CPP/7zip/Archive/XarHandler.cpp @@ -151,7 +151,8 @@ IMP_IInArchive_ArcProps #define PARSE_NUM(_num_, _dest_) \ { const char *end; _dest_ = ConvertStringToUInt32(p, &end); \ - if ((unsigned)(end - p) != _num_) return 0; p += _num_ + 1; } + if ((unsigned)(end - p) != _num_) return 0; \ + p += _num_ + 1; } static bool ParseUInt64(const CXmlItem &item, const char *name, UInt64 &res) { diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp index 2803f6a8..f1afab66 100644 --- a/CPP/7zip/Archive/XzHandler.cpp +++ b/CPP/7zip/Archive/XzHandler.cpp @@ -117,7 +117,7 @@ class CHandler: #ifndef _7ZIP_ST decoder._numThreads = _numThreads; #endif - decoder._memUsage = _memUsage; + decoder._memUsage = _memUsage_Decompress; HRESULT hres = decoder.Decode(seqInStream, outStream, NULL, // *outSizeLimit @@ -1129,14 +1129,14 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (IntToBool(newData)) { - UInt64 size; + UInt64 dataSize; { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(0, kpidSize, &prop)); if (prop.vt != VT_UI8) return E_INVALIDARG; - size = prop.uhVal.QuadPart; - RINOK(updateCallback->SetTotal(size)); + dataSize = prop.uhVal.QuadPart; + RINOK(updateCallback->SetTotal(dataSize)); } NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder; @@ -1147,17 +1147,79 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt lzma2Props.lzmaProps.level = GetLevel(); - xzProps.reduceSize = size; + xzProps.reduceSize = dataSize; /* { - NCOM::CPropVariant prop = (UInt64)size; + NCOM::CPropVariant prop = (UInt64)dataSize; RINOK(encoderSpec->SetCoderProp(NCoderPropID::kReduceSize, prop)); } */ #ifndef _7ZIP_ST - xzProps.numTotalThreads = (int)_numThreads; - #endif + + UInt32 numThreads = _numThreads; + + const UInt32 kNumThreads_Max = 1024; + if (numThreads > kNumThreads_Max) + numThreads = kNumThreads_Max; + + if (!_numThreads_WasForced + && _numThreads >= 1 + && _memUsage_WasSet) + { + COneMethodInfo oneMethodInfo; + if (!_methods.IsEmpty()) + oneMethodInfo = _methods[0]; + + SetGlobalLevelTo(oneMethodInfo); + + const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0); + if (!numThreads_WasSpecifiedInMethod) + { + // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already + CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, numThreads); + } + + UInt64 cs = _numSolidBytes; + if (cs != XZ_PROPS__BLOCK_SIZE__AUTO) + oneMethodInfo.AddProp_BlockSize2(cs); + cs = oneMethodInfo.Get_Xz_BlockSize(); + + if (cs != XZ_PROPS__BLOCK_SIZE__AUTO && + cs != XZ_PROPS__BLOCK_SIZE__SOLID) + { + const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads(); + const UInt32 numBlockThreads_Original = numThreads / lzmaThreads; + + if (numBlockThreads_Original > 1) + { + UInt32 numBlockThreads = numBlockThreads_Original; + { + const UInt64 lzmaMemUsage = oneMethodInfo.Get_Lzma_MemUsage(false); + for (; numBlockThreads > 1; numBlockThreads--) + { + UInt64 size = numBlockThreads * (lzmaMemUsage + cs); + UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1; + if (cs < ((UInt32)1 << 26)) numPackChunks++; + if (cs < ((UInt32)1 << 24)) numPackChunks++; + if (cs < ((UInt32)1 << 22)) numPackChunks++; + size += numPackChunks * cs; + // printf("\nnumBlockThreads = %d, size = %d\n", (unsigned)(numBlockThreads), (unsigned)(size >> 20)); + if (size <= _memUsage_Compress) + break; + } + } + if (numBlockThreads == 0) + numBlockThreads = 1; + if (numBlockThreads != numBlockThreads_Original) + numThreads = numBlockThreads * lzmaThreads; + } + } + } + xzProps.numTotalThreads = (int)numThreads; + + #endif // _7ZIP_ST + xzProps.blockSize = _numSolidBytes; if (_numSolidBytes == XZ_PROPS__BLOCK_SIZE__SOLID) diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp index 72a77cb7..d8168bbe 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp @@ -1665,7 +1665,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, m_Archive, item, realOutStream, extractCallback, progress, #ifndef _7ZIP_ST - _props._numThreads, _props._memUsage, + _props._numThreads, _props._memUsage_Decompress, #endif res); diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index 880ff218..076d6bb5 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -989,7 +989,8 @@ bool CInArchive::ReadFileName(unsigned size, AString &s) bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlock &extra, - UInt64 &unpackSize, UInt64 &packSize, UInt64 &localOffset, UInt32 &disk) + UInt64 &unpackSize, UInt64 &packSize, + CItem *cdItem) { extra.Clear(); @@ -1017,18 +1018,40 @@ bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlo { extra.IsZip64 = true; bool isOK = true; + + if (!cdItem + && size == 16 + && !ZIP64_IS_32_MAX(unpackSize) + && !ZIP64_IS_32_MAX(packSize)) + { + /* Win10 Explorer's "Send to Zip" for big (3500 MiB) files + creates Zip64 Extra in local file header. + But if both uncompressed and compressed sizes are smaller than 4 GiB, + Win10 doesn't store 0xFFFFFFFF in 32-bit fields as expected by zip specification. + 21.04: we ignore these minor errors in Win10 zip archives. */ + if (ReadUInt64() != unpackSize) + isOK = false; + if (ReadUInt64() != packSize) + isOK = false; + size = 0; + } + else + { + if (ZIP64_IS_32_MAX(unpackSize)) + { if (size < 8) isOK = false; else { size -= 8; unpackSize = ReadUInt64(); }} - if (ZIP64_IS_32_MAX(unpackSize)) - { if (size < 8) isOK = false; else { size -= 8; unpackSize = ReadUInt64(); }} - - if (isOK && ZIP64_IS_32_MAX(packSize)) - { if (size < 8) isOK = false; else { size -= 8; packSize = ReadUInt64(); }} - - if (isOK && ZIP64_IS_32_MAX(localOffset)) - { if (size < 8) isOK = false; else { size -= 8; localOffset = ReadUInt64(); }} + if (isOK && ZIP64_IS_32_MAX(packSize)) + { if (size < 8) isOK = false; else { size -= 8; packSize = ReadUInt64(); }} - if (isOK && ZIP64_IS_16_MAX(disk)) - { if (size < 4) isOK = false; else { size -= 4; disk = ReadUInt32(); }} + if (cdItem) + { + if (isOK && ZIP64_IS_32_MAX(cdItem->LocalHeaderPos)) + { if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }} + + if (isOK && ZIP64_IS_16_MAX(cdItem->Disk)) + { if (size < 4) isOK = false; else { size -= 4; cdItem->Disk = ReadUInt32(); }} + } + } if (!isOK || size != 0) { @@ -1100,9 +1123,7 @@ bool CInArchive::ReadLocalItem(CItemEx &item) if (extraSize > 0) { - UInt64 localOffset = 0; - UInt32 disk = 0; - if (!ReadExtra(item, extraSize, item.LocalExtra, item.Size, item.PackSize, localOffset, disk)) + if (!ReadExtra(item, extraSize, item.LocalExtra, item.Size, item.PackSize, NULL)) { /* Most of archives are OK for Extra. But there are some rare cases that have error. And if error in first item, it can't open archive. @@ -1557,7 +1578,7 @@ HRESULT CInArchive::ReadCdItem(CItemEx &item) ReadFileName(nameSize, item.Name); if (extraSize > 0) - ReadExtra(item, extraSize, item.CentralExtra, item.Size, item.PackSize, item.LocalHeaderPos, item.Disk); + ReadExtra(item, extraSize, item.CentralExtra, item.Size, item.PackSize, &item); // May be these strings must be deleted /* diff --git a/CPP/7zip/Archive/Zip/ZipIn.h b/CPP/7zip/Archive/Zip/ZipIn.h index 31e524b6..1498afed 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.h +++ b/CPP/7zip/Archive/Zip/ZipIn.h @@ -312,7 +312,7 @@ class CInArchive bool ReadFileName(unsigned nameSize, AString &dest); bool ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlock &extra, - UInt64 &unpackSize, UInt64 &packSize, UInt64 &localOffset, UInt32 &disk); + UInt64 &unpackSize, UInt64 &packSize, CItem *cdItem); bool ReadLocalItem(CItemEx &item); HRESULT FindDescriptor(CItemEx &item, unsigned numFiles); HRESULT ReadCdItem(CItemEx &item); diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index 4468c7c5..26636c78 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -773,7 +773,7 @@ static HRESULT Update2( if (numThreads < 1) numThreads = 1; - const size_t kMemPerThread = (size_t)1 << 25; + const size_t kMemPerThread = (size_t)sizeof(size_t) << 23; const size_t kBlockSize = 1 << 16; bool mtMode = (numThreads > 1); @@ -791,6 +791,7 @@ static HRESULT Update2( if (onem.FindProp(NCoderPropID::kNumThreads) < 0) { + // fixme: we should check the number of threads for xz mehod also // fixed for 9.31. bzip2 default is just one thread. onem.AddProp_NumThreads(numThreads); } @@ -801,8 +802,8 @@ static HRESULT Update2( if (method == NFileHeader::NCompressionMethod::kStore && !options.PasswordIsDefined) numThreads = 1; - if (oneMethodMain) - { + if (oneMethodMain) + { if (method == NFileHeader::NCompressionMethod::kBZip2) { @@ -828,6 +829,7 @@ static HRESULT Update2( int numXzThreads = oneMethodMain->Get_Xz_NumThreads(numLzmaThreads); if (numXzThreads < 0) { + // numXzThreads is unknown const UInt64 averageSize = numBytesToCompress / numFilesToCompress; const UInt64 blockSize = oneMethodMain->Get_Xz_BlockSize(); UInt64 averageNumberOfBlocks = 1; @@ -844,18 +846,52 @@ static HRESULT Update2( } numThreads /= (unsigned)numXzThreads; } + else if ( + method == NFileHeader::NCompressionMethod::kDeflate + || method == NFileHeader::NCompressionMethod::kDeflate64 + || method == NFileHeader::NCompressionMethod::kPPMd) + { + if (numThreads > 1 + && options._memUsage_WasSet + && !options._numThreads_WasForced) + { + UInt64 methodMemUsage; + if (method == NFileHeader::NCompressionMethod::kPPMd) + methodMemUsage = oneMethodMain->Get_Ppmd_MemSize(); + else + methodMemUsage = (4 << 20); // for deflate + const UInt64 threadMemUsage = kMemPerThread + methodMemUsage; + const UInt64 numThreads64 = options._memUsage_Compress / threadMemUsage; + if (numThreads64 < numThreads) + numThreads = (UInt32)numThreads64; + } + } else if (method == NFileHeader::NCompressionMethod::kLZMA) { // we suppose that default LZMA is 2 thread. So we don't change it - UInt32 numLZMAThreads = oneMethodMain->Get_Lzma_NumThreads(); + const UInt32 numLZMAThreads = oneMethodMain->Get_Lzma_NumThreads(); numThreads /= numLZMAThreads; + + if (numThreads > 1 + && options._memUsage_WasSet + && !options._numThreads_WasForced) + { + const UInt64 methodMemUsage = oneMethodMain->Get_Lzma_MemUsage(true); + const UInt64 threadMemUsage = kMemPerThread + methodMemUsage; + const UInt64 numThreads64 = options._memUsage_Compress / threadMemUsage; + if (numThreads64 < numThreads) + numThreads = (UInt32)numThreads64; + } } - } + } // (oneMethodMain) if (numThreads > numFilesToCompress) numThreads = (UInt32)numFilesToCompress; if (numThreads <= 1) + { mtMode = false; + numThreads = 1; + } } // mtMode = true; // to test mtMode for seqMode diff --git a/CPP/7zip/Bundles/Alone/Alone.dsp b/CPP/7zip/Bundles/Alone/Alone.dsp index 7a1f79df..84d3cdf7 100644 --- a/CPP/7zip/Bundles/Alone/Alone.dsp +++ b/CPP/7zip/Bundles/Alone/Alone.dsp @@ -294,6 +294,14 @@ SOURCE=..\..\..\Common\DynamicBuffer.h # End Source File # Begin Source File +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + SOURCE=..\..\..\Common\IntToString.cpp # End Source File # Begin Source File diff --git a/CPP/7zip/Bundles/Alone/makefile b/CPP/7zip/Bundles/Alone/makefile index ca3392db..cc4b29ed 100644 --- a/CPP/7zip/Bundles/Alone/makefile +++ b/CPP/7zip/Bundles/Alone/makefile @@ -7,6 +7,7 @@ COMMON_OBJS = \ $O\CommandLineParser.obj \ $O\CRC.obj \ $O\CrcReg.obj \ + $O\DynLimBuf.obj \ $O\IntToString.obj \ $O\ListFileUtils.obj \ $O\LzFindPrepare.obj \ diff --git a/CPP/7zip/Bundles/Alone/makefile.gcc b/CPP/7zip/Bundles/Alone/makefile.gcc index 182e9a7c..38f8d593 100644 --- a/CPP/7zip/Bundles/Alone/makefile.gcc +++ b/CPP/7zip/Bundles/Alone/makefile.gcc @@ -108,6 +108,7 @@ COMMON_OBJS = \ $O/CommandLineParser.o \ $O/CRC.o \ $O/CrcReg.o \ + $O/DynLimBuf.o \ $O/IntToString.o \ $O/ListFileUtils.o \ $O/LzFindPrepare.o \ diff --git a/CPP/7zip/Bundles/Alone7z/Alone.dsp b/CPP/7zip/Bundles/Alone7z/Alone.dsp index a15a5bfa..76607fdd 100644 --- a/CPP/7zip/Bundles/Alone7z/Alone.dsp +++ b/CPP/7zip/Bundles/Alone7z/Alone.dsp @@ -290,6 +290,14 @@ SOURCE=..\..\..\Common\DynamicBuffer.h # End Source File # Begin Source File +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + SOURCE=..\..\..\Common\IntToString.cpp # End Source File # Begin Source File diff --git a/CPP/7zip/Bundles/Alone7z/makefile b/CPP/7zip/Bundles/Alone7z/makefile index 0a68e141..f87684c7 100644 --- a/CPP/7zip/Bundles/Alone7z/makefile +++ b/CPP/7zip/Bundles/Alone7z/makefile @@ -8,6 +8,7 @@ COMMON_OBJS = \ $O\CommandLineParser.obj \ $O\CRC.obj \ $O\CrcReg.obj \ + $O\DynLimBuf.obj \ $O\IntToString.obj \ $O\ListFileUtils.obj \ $O\LzFindPrepare.obj \ diff --git a/CPP/7zip/Bundles/Alone7z/makefile.gcc b/CPP/7zip/Bundles/Alone7z/makefile.gcc index c1d6ac50..8565452b 100644 --- a/CPP/7zip/Bundles/Alone7z/makefile.gcc +++ b/CPP/7zip/Bundles/Alone7z/makefile.gcc @@ -73,6 +73,7 @@ LOCAL_FLAGS = \ CONSOLE_OBJS = \ $O/BenchCon.o \ $O/ConsoleClose.o \ + $O/DynLimBuf.o \ $O/ExtractCallbackConsole.o \ $O/HashCon.o \ $O/List.o \ diff --git a/CPP/7zip/Bundles/Fm/FM.dsp b/CPP/7zip/Bundles/Fm/FM.dsp index 86d788f0..54efba98 100644 --- a/CPP/7zip/Bundles/Fm/FM.dsp +++ b/CPP/7zip/Bundles/Fm/FM.dsp @@ -1084,6 +1084,20 @@ SOURCE=..\..\..\..\C\MtDec.h # End Source File # Begin Source File +SOURCE=..\..\..\..\C\Sha1.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha1.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha1Opt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + SOURCE=..\..\..\..\C\Sha256.c !IF "$(CFG)" == "FM - Win32 Release" @@ -1133,6 +1147,16 @@ SOURCE=..\..\..\..\C\Threads.c SOURCE=..\..\..\..\C\Threads.h # End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzCrc64.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzCrc64Opt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File # End Group # Begin Group "Windows" @@ -1483,6 +1507,14 @@ SOURCE=..\..\..\Common\DynamicBuffer.h # End Source File # Begin Source File +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + SOURCE=..\..\..\Common\Exception.h # End Source File # Begin Source File @@ -1563,10 +1595,22 @@ SOURCE=..\..\..\Common\Random.h # End Source File # Begin Source File +SOURCE=..\..\..\Common\Sha1Prepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha1Reg.cpp +# End Source File +# Begin Source File + SOURCE=..\..\..\Common\Sha256Prepare.cpp # End Source File # Begin Source File +SOURCE=..\..\..\Common\Sha256Reg.cpp +# End Source File +# Begin Source File + SOURCE=..\..\..\Common\StringConvert.cpp # End Source File # Begin Source File @@ -1601,6 +1645,14 @@ SOURCE=..\..\..\Common\Wildcard.cpp SOURCE=..\..\..\Common\Wildcard.h # End Source File +# Begin Source File + +SOURCE=..\..\..\Common\XzCrc64Init.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\XzCrc64Reg.cpp +# End Source File # End Group # Begin Group "UI" diff --git a/CPP/7zip/Bundles/SFXWin/SFXWin.dsp b/CPP/7zip/Bundles/SFXWin/SFXWin.dsp index c80736de..8e1a70d2 100644 --- a/CPP/7zip/Bundles/SFXWin/SFXWin.dsp +++ b/CPP/7zip/Bundles/SFXWin/SFXWin.dsp @@ -537,6 +537,14 @@ SOURCE=..\..\..\Windows\Control\ListView.h # End Group # Begin Source File +SOURCE=..\..\..\Windows\Clipboard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Clipboard.h +# End Source File +# Begin Source File + SOURCE=..\..\..\Windows\CommonDialog.cpp # End Source File # Begin Source File @@ -593,6 +601,14 @@ SOURCE=..\..\..\Windows\FileName.h # End Source File # Begin Source File +SOURCE=..\..\..\Windows\MemoryGlobal.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryGlobal.h +# End Source File +# Begin Source File + SOURCE=..\..\..\Windows\PropVariant.cpp # End Source File # Begin Source File diff --git a/CPP/7zip/Bundles/SFXWin/makefile b/CPP/7zip/Bundles/SFXWin/makefile index 57d922fb..0ed36f8a 100644 --- a/CPP/7zip/Bundles/SFXWin/makefile +++ b/CPP/7zip/Bundles/SFXWin/makefile @@ -31,6 +31,7 @@ COMMON_OBJS = \ $O\Wildcard.obj \ WIN_OBJS = \ + $O\Clipboard.obj \ $O\CommonDialog.obj \ $O\DLL.obj \ $O\ErrorMsg.obj \ @@ -38,6 +39,7 @@ WIN_OBJS = \ $O\FileFind.obj \ $O\FileIO.obj \ $O\FileName.obj \ + $O\MemoryGlobal.obj \ $O\PropVariant.obj \ $O\PropVariantConv.obj \ $O\ResourceString.obj \ diff --git a/CPP/7zip/Common/CreateCoder.cpp b/CPP/7zip/Common/CreateCoder.cpp index e62bb0b4..872f17fc 100644 --- a/CPP/7zip/Common/CreateCoder.cpp +++ b/CPP/7zip/Common/CreateCoder.cpp @@ -118,6 +118,7 @@ HRESULT CExternalCodecs::Load() } RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned)); RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned)); + RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kIsFilter, info.IsFilter)); Codecs.Add(info); } diff --git a/CPP/7zip/Common/CreateCoder.h b/CPP/7zip/Common/CreateCoder.h index 20d0ef33..24e6b663 100644 --- a/CPP/7zip/Common/CreateCoder.h +++ b/CPP/7zip/Common/CreateCoder.h @@ -35,8 +35,9 @@ struct CCodecInfoEx UInt32 NumStreams; bool EncoderIsAssigned; bool DecoderIsAssigned; + bool IsFilter; // it's unused - CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false) {} + CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false), IsFilter(false) {} }; struct CHasherInfoEx diff --git a/CPP/7zip/Common/MethodProps.cpp b/CPP/7zip/Common/MethodProps.cpp index 3ab89ddb..a55c49f9 100644 --- a/CPP/7zip/Common/MethodProps.cpp +++ b/CPP/7zip/Common/MethodProps.cpp @@ -53,7 +53,7 @@ static unsigned ParseStringToUInt64(const UString &srcString, UInt64 &number) HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue) { // =VT_UI4 - // =VT_EMPTY + // =VT_EMPTY : it doesn't change (resValue), and returns S_OK // {stringUInt32}=VT_EMPTY if (prop.vt == VT_UI4) @@ -74,31 +74,92 @@ HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 & return S_OK; } -HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads) + + +HRESULT ParseMtProp2(const UString &name, const PROPVARIANT &prop, UInt32 &numThreads, bool &force) { + force = false; + UString s; if (name.IsEmpty()) { - switch (prop.vt) + if (prop.vt == VT_UI4) { - case VT_UI4: - numThreads = prop.ulVal; - break; - default: + numThreads = prop.ulVal; + force = true; + return S_OK; + } + bool val; + HRESULT res = PROPVARIANT_to_bool(prop, val); + if (res == S_OK) + { + if (!val) { - bool val; - RINOK(PROPVARIANT_to_bool(prop, val)); - numThreads = (val ? defaultNumThreads : 1); - break; + numThreads = 1; + force = true; } + // force = true; for debug + // "(VT_BOOL = VARIANT_TRUE)" set "force = false" and doesn't change numThreads + return S_OK; } - return S_OK; + if (prop.vt != VT_BSTR) + return res; + s.SetFromBstr(prop.bstrVal); + if (s.IsEmpty()) + return E_INVALIDARG; } - if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - return ParsePropToUInt32(name, prop, numThreads); + else + { + if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + s = name; + } + + s.MakeLower_Ascii(); + const wchar_t *start = s; + UInt32 v = numThreads; + + /* we force up, if threads number specified + only `d` will force it down */ + bool force_loc = true; + for (;;) + { + const wchar_t c = *start; + if (!c) + break; + if (c == 'd') + { + force_loc = false; // force down + start++; + continue; + } + if (c == 'u') + { + force_loc = true; // force up + start++; + continue; + } + bool isPercent = false; + if (c == 'p') + { + isPercent = true; + start++; + } + const wchar_t *end; + v = ConvertStringToUInt32(start, &end); + if (end == start) + return E_INVALIDARG; + if (isPercent) + v = numThreads * v / 100; + start = end; + } + + numThreads = v; + force = force_loc; + return S_OK; } + static HRESULT SetLogSizeProp(UInt64 number, NCOM::CPropVariant &destProp) { if (number >= 64) @@ -263,9 +324,9 @@ HRESULT CProps::SetCoderProps_DSReduce_Aff( int CMethodProps::FindProp(PROPID id) const { - for (int i = (int)Props.Size() - 1; i >= 0; i--) - if (Props[(unsigned)i].Id == id) - return i; + for (unsigned i = Props.Size(); i != 0;) + if (Props[--i].Id == id) + return (int)i; return -1; } @@ -511,6 +572,59 @@ HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const return S_OK; } + +static UInt64 GetMemoryUsage_LZMA(UInt32 dict, bool isBt, UInt32 numThreads) +{ + UInt32 hs = dict - 1; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + if (hs >= (1 << 24)) + hs >>= 1; + hs |= (1 << 16) - 1; + // if (numHashBytes >= 5) + if (!isBt) + hs |= (256 << 10) - 1; + hs++; + UInt64 size1 = (UInt64)hs * 4; + size1 += (UInt64)dict * 4; + if (isBt) + size1 += (UInt64)dict * 4; + size1 += (2 << 20); + + if (numThreads > 1 && isBt) + size1 += (2 << 20) + (4 << 20); + return size1; +} + +static const UInt32 kLzmaMaxDictSize = (UInt32)15 << 28; + +UInt64 CMethodProps::Get_Lzma_MemUsage(bool addSlidingWindowSize) const +{ + const UInt64 dicSize = Get_Lzma_DicSize(); + const bool isBt = Get_Lzma_MatchFinder_IsBt(); + const UInt32 dict32 = (dicSize >= kLzmaMaxDictSize ? kLzmaMaxDictSize : (UInt32)dicSize); + const UInt32 numThreads = Get_Lzma_NumThreads(); + UInt64 size = GetMemoryUsage_LZMA(dict32, isBt, numThreads); + + if (addSlidingWindowSize) + { + const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16); + UInt64 blockSize = (UInt64)dict32 + (1 << 16) + + (numThreads > 1 ? (1 << 20) : 0); + blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2)); + if (blockSize >= kBlockSizeMax) + blockSize = kBlockSizeMax; + size += blockSize; + } + return size; +} + + + + HRESULT COneMethodInfo::ParseMethodFromString(const UString &s) { MethodName.Empty(); diff --git a/CPP/7zip/Common/MethodProps.h b/CPP/7zip/Common/MethodProps.h index bd9283f0..aea75a3e 100644 --- a/CPP/7zip/Common/MethodProps.h +++ b/CPP/7zip/Common/MethodProps.h @@ -12,12 +12,27 @@ #include "../ICoder.h" +// UInt64 GetMemoryUsage_LZMA(UInt32 dict, bool isBt, UInt32 numThreads); + bool StringToBool(const wchar_t *s, bool &res); HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest); unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number); + +/* +if (name.IsEmpty() && prop.vt == VT_EMPTY), it doesn't change (resValue) and returns S_OK. + So you must set (resValue) for default value before calling */ HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue); -HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads); +/* input: (numThreads = the_number_of_processors) */ +HRESULT ParseMtProp2(const UString &name, const PROPVARIANT &prop, UInt32 &numThreads, bool &force); + +inline HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 numCPUs, UInt32 &numThreads) +{ + bool forced = false; + numThreads = numCPUs; + return ParseMtProp2(name, prop, numThreads, forced); +} + struct CProp { @@ -123,9 +138,21 @@ public: return dictSize; } + bool Get_Lzma_MatchFinder_IsBt() const + { + const int i = FindProp(NCoderPropID::kMatchFinder); + if (i >= 0) + { + const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; + if (val.vt == VT_BSTR) + return ((val.bstrVal[0] | 0x20) != 'h'); // check for "hc" + } + return GetLevel() >= 5; + } + bool Get_Lzma_Eos() const { - int i = FindProp(NCoderPropID::kEndMarker); + const int i = FindProp(NCoderPropID::kEndMarker); if (i >= 0) { const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; @@ -153,6 +180,9 @@ public: return 2; } + UInt64 Get_Lzma_MemUsage(bool addSlidingWindowSize) const; + + /* returns -1, if numThreads is unknown */ int Get_Xz_NumThreads(UInt32 &lzmaThreads) const { lzmaThreads = 1; @@ -191,6 +221,7 @@ public: const UInt32 kMinSize = (UInt32)1 << 20; const UInt32 kMaxSize = (UInt32)1 << 28; const UInt64 dictSize = Get_Lzma_DicSize(); + /* lzma2 code uses fake 4 GiB to calculate ChunkSize. So we do same */ UInt64 blockSize = (UInt64)dictSize << 2; if (blockSize < kMinSize) blockSize = kMinSize; if (blockSize > kMaxSize) blockSize = kMaxSize; @@ -268,6 +299,17 @@ public: AddPropBool(NCoderPropID::kEndMarker, eos); } + void AddProp_BlockSize2(UInt64 blockSize2) + { + if (FindProp(NCoderPropID::kBlockSize2) < 0) + { + CProp &prop = Props.AddNew(); + prop.IsOptional = true; + prop.Id = NCoderPropID::kBlockSize2; + prop.Value = blockSize2; + } + } + HRESULT ParseParamsFromString(const UString &srcString); HRESULT ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value); }; diff --git a/CPP/7zip/Compress/BZip2Crc.h b/CPP/7zip/Compress/BZip2Crc.h index 1b5755b5..3b16c60b 100644 --- a/CPP/7zip/Compress/BZip2Crc.h +++ b/CPP/7zip/Compress/BZip2Crc.h @@ -11,8 +11,8 @@ class CBZip2Crc static UInt32 Table[256]; public: static void InitTable(); - CBZip2Crc(): _value(0xFFFFFFFF) {}; - void Init() { _value = 0xFFFFFFFF; } + CBZip2Crc(UInt32 initVal = 0xFFFFFFFF): _value(initVal) {}; + void Init(UInt32 initVal = 0xFFFFFFFF) { _value = initVal; } void UpdateByte(Byte b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); } void UpdateByte(unsigned int b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); } UInt32 GetDigest() const { return _value ^ 0xFFFFFFFF; } diff --git a/CPP/7zip/Compress/CodecExports.cpp b/CPP/7zip/Compress/CodecExports.cpp index 2aea7b33..5bb6ff8d 100644 --- a/CPP/7zip/Compress/CodecExports.cpp +++ b/CPP/7zip/Compress/CodecExports.cpp @@ -230,15 +230,12 @@ STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value) value->ulVal = (ULONG)codec.NumStreams; } break; - /* case NMethodPropID::kIsFilter: - // if (codec.IsFilter) { value->vt = VT_BOOL; value->boolVal = BoolToVARIANT_BOOL(codec.IsFilter); } break; - */ /* case NMethodPropID::kDecoderFlags: { diff --git a/CPP/7zip/Guid.txt b/CPP/7zip/Guid.txt index f28afcd1..754c9df5 100644 --- a/CPP/7zip/Guid.txt +++ b/CPP/7zip/Guid.txt @@ -21,7 +21,8 @@ 11 IFolderScanProgress 20 IFileExtractCallback.h::IGetProp - 30 IFileExtractCallback.h::IFolderExtractToStreamCallback + 30 IFileExtractCallback.h::IFolderExtractToStreamCallback (old) + 31 IFileExtractCallback.h::IFolderExtractToStreamCallback (new 21.04) 03 IStream.h @@ -104,6 +105,7 @@ 80 IArchiveUpdateCallback 82 IArchiveUpdateCallback2 83 IArchiveUpdateCallbackFile + 84 IArchiveGetDiskProperty A0 IOutArchive diff --git a/CPP/7zip/ICoder.h b/CPP/7zip/ICoder.h index 314d33d4..9177f5e5 100644 --- a/CPP/7zip/ICoder.h +++ b/CPP/7zip/ICoder.h @@ -394,7 +394,8 @@ namespace NMethodPropID kDescription, kDecoderIsAssigned, kEncoderIsAssigned, - kDigestSize + kDigestSize, + kIsFilter }; } diff --git a/CPP/7zip/PropID.h b/CPP/7zip/PropID.h index 1822f402..b818954f 100644 --- a/CPP/7zip/PropID.h +++ b/CPP/7zip/PropID.h @@ -103,6 +103,9 @@ enum kpidReadOnly, kpidOutName, kpidCopyLink, + kpidArcFileName, + kpidIsHash, + kpid_NUM_DEFINED, diff --git a/CPP/7zip/UI/Agent/Agent.cpp b/CPP/7zip/UI/Agent/Agent.cpp index 76b243f2..31c91e29 100644 --- a/CPP/7zip/UI/Agent/Agent.cpp +++ b/CPP/7zip/UI/Agent/Agent.cpp @@ -27,6 +27,7 @@ CCodecs *g_CodecsObj; #ifdef EXTERNAL_CODECS CExternalCodecs g_ExternalCodecs; + const CExternalCodecs *g_ExternalCodecs_Ptr; static CCodecs::CReleaser g_CodecsReleaser; #else extern @@ -53,6 +54,7 @@ void FreeGlobalCodecs() g_CodecsReleaser.Set(NULL); g_CodecsObj = NULL; g_ExternalCodecs.ClearAndRelease(); + g_ExternalCodecs_Ptr = NULL; #else g_CodecsRef.Release(); #endif @@ -83,8 +85,11 @@ HRESULT LoadGlobalCodecs() return E_NOTIMPL; } + Codecs_AddHashArcHandler(g_CodecsObj); + #ifdef EXTERNAL_CODECS RINOK(g_ExternalCodecs.Load()); + g_ExternalCodecs_Ptr = &g_ExternalCodecs; #endif return S_OK; @@ -1223,7 +1228,11 @@ STDMETHODIMP CAgentFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value) if (_agentSpec->Is_Attrib_ReadOnly()) prop = true; else - prop = _agentSpec->IsThereReadOnlyArc(); + prop = _agentSpec->IsThere_ReadOnlyArc(); + } + else if (propID == kpidIsHash) + { + prop = _agentSpec->_isHashHandler; } else if (_proxy2) { @@ -1446,6 +1455,10 @@ STDMETHODIMP CAgentFolder::Extract(const UInt32 *indices, IFolderArchiveExtractCallback *extractCallback2) { COM_TRY_BEGIN + + if (!testMode && _agentSpec->_isHashHandler) + return E_NOTIMPL; + CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec; UStringVector pathParts; @@ -1500,6 +1513,9 @@ STDMETHODIMP CAgentFolder::Extract(const UInt32 *indices, if (_proxy2) extractCallbackSpec->SetBaseParentFolderIndex(_proxy2->Dirs[_proxyDirIndex].ArcIndex); + // do we need another base folder for subfolders ? + extractCallbackSpec->DirPathPrefix_for_HashFiles = _agentSpec->_hashBaseFolderPrefix; + CUIntVector realIndices; GetRealIndices(indices, numItems, IntToBool(includeAltStreams), false, // includeFolderSubItemsInFlatMode @@ -1536,7 +1552,8 @@ CAgent::CAgent(): _proxy(NULL), _proxy2(NULL), _updatePathPrefix_is_AltFolder(false), - _isDeviceFile(false) + _isDeviceFile(false), + _isHashHandler(false) { } @@ -1571,9 +1588,11 @@ STDMETHODIMP CAgent::Open( { COM_TRY_BEGIN _archiveFilePath = filePath; + _hashBaseFolderPrefix.Empty(); _attrib = 0; - NFile::NFind::CFileInfo fi; _isDeviceFile = false; + _isHashHandler = false; + NFile::NFind::CFileInfo fi; if (!inStream) { if (!fi.Find(us2fs(_archiveFilePath))) @@ -1582,6 +1601,12 @@ STDMETHODIMP CAgent::Open( return E_FAIL; _attrib = fi.Attrib; _isDeviceFile = fi.IsDevice; + FString dirPrefix, fileName; + if (NFile::NDir::GetFullPathAndSplit(us2fs(_archiveFilePath), dirPrefix, fileName)) + { + NFile::NName::NormalizeDirPathPrefix(dirPrefix); + _hashBaseFolderPrefix = dirPrefix; + } } CArcInfoEx archiverInfo0, archiverInfo1; @@ -1629,6 +1654,9 @@ STDMETHODIMP CAgent::Open( { RINOK(StringToBstr(ArchiveType, archiveType)); } + + if (arc.IsHashHandler(options)) + _isHashHandler = true; } return res; @@ -1745,6 +1773,10 @@ STDMETHODIMP CAgent::Extract( IFolderArchiveExtractCallback *extractCallback2) { COM_TRY_BEGIN + + if (!testMode && _isHashHandler) + return E_NOTIMPL; + CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec; extractCallbackSpec->InitForMulti( @@ -1769,6 +1801,8 @@ STDMETHODIMP CAgent::Extract( UStringVector(), false, (UInt64)(Int64)-1); + extractCallbackSpec->DirPathPrefix_for_HashFiles = _hashBaseFolderPrefix; + #ifdef SUPPORT_LINKS if (!testMode) diff --git a/CPP/7zip/UI/Agent/Agent.h b/CPP/7zip/UI/Agent/Agent.h index 498e7d0c..e9fe4103 100644 --- a/CPP/7zip/UI/Agent/Agent.h +++ b/CPP/7zip/UI/Agent/Agent.h @@ -234,7 +234,7 @@ public: UString ArchiveType; FStringVector _names; - FString _folderPrefix; + FString _folderPrefix; // for new files from disk bool _updatePathPrefix_is_AltFolder; UString _updatePathPrefix; @@ -243,6 +243,8 @@ public: UString _archiveFilePath; DWORD _attrib; bool _isDeviceFile; + bool _isHashHandler; + FString _hashBaseFolderPrefix; #ifndef EXTRACT_ONLY CObjectVector<UString> m_PropNames; @@ -258,7 +260,7 @@ public: return _attrib != INVALID_FILE_ATTRIBUTES && (_attrib & FILE_ATTRIBUTE_READONLY); } - bool IsThereReadOnlyArc() const + bool IsThere_ReadOnlyArc() const { FOR_VECTOR (i, _archiveLink.Arcs) { diff --git a/CPP/7zip/UI/Agent/AgentOut.cpp b/CPP/7zip/UI/Agent/AgentOut.cpp index 8dfb63a2..fae0e224 100644 --- a/CPP/7zip/UI/Agent/AgentOut.cpp +++ b/CPP/7zip/UI/Agent/AgentOut.cpp @@ -158,6 +158,8 @@ static void SetInArchiveInterfaces(CAgent *agent, CArchiveUpdateCallback *upd) const CArc &arc = agent->GetArc(); upd->Arc = &arc; upd->Archive = arc.Archive; + + upd->ArcFileName = ExtractFileNameFromPath(arc.Path); } struct CDirItemsCallback_AgentOut: public IDirItemsCallback @@ -190,6 +192,7 @@ struct CDirItemsCallback_AgentOut: public IDirItemsCallback } }; + STDMETHODIMP CAgent::DoOperation( FStringVector *requestedPaths, FStringVector *processedPaths, diff --git a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp index ba52f4e7..4a10ebec 100644 --- a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp +++ b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp @@ -70,6 +70,9 @@ HRESULT CAgentFolder::CommonUpdateOperation( const UInt32 *indices, UInt32 numItems, IProgress *progress) { + if (moveMode && _agentSpec->_isHashHandler) + return E_NOTIMPL; + if (!_agentSpec->CanUpdate()) return E_NOTIMPL; diff --git a/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp b/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp index d450eefe..53a13bb9 100644 --- a/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp +++ b/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp @@ -153,7 +153,7 @@ HRESULT CUpdateCallbackAgent::ReportExtractResult(Int32 opRes, Int32 isEncrypted return S_OK; } -HRESULT CUpdateCallbackAgent::ReportUpdateOpeartion(UInt32 op, const wchar_t *name, bool isDir) +HRESULT CUpdateCallbackAgent::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) { if (Callback2) { diff --git a/CPP/7zip/UI/Client7z/Client7z.cpp b/CPP/7zip/UI/Client7z/Client7z.cpp index 0c69bdc0..0fa4cdad 100644 --- a/CPP/7zip/UI/Client7z/Client7z.cpp +++ b/CPP/7zip/UI/Client7z/Client7z.cpp @@ -217,6 +217,7 @@ static const char * const kIncorrectCommand = "incorrect command"; static const char * const kTestingString = "Testing "; static const char * const kExtractingString = "Extracting "; static const char * const kSkippingString = "Skipping "; +static const char * const kReadingString = "Reading "; static const char * const kUnsupportedMethod = "Unsupported Method"; static const char * const kCRCFailed = "CRC Failed"; @@ -419,6 +420,9 @@ STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode) case NArchive::NExtract::NAskMode::kExtract: Print(kExtractingString); break; case NArchive::NExtract::NAskMode::kTest: Print(kTestingString); break; case NArchive::NExtract::NAskMode::kSkip: Print(kSkippingString); break; + case NArchive::NExtract::NAskMode::kReadExternal: Print(kReadingString); break; + default: + Print("??? "); break; }; Print(_filePath); return S_OK; diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp index 00df80e9..47e4a852 100644 --- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp +++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp @@ -133,6 +133,8 @@ enum Enum kSfx, kEmail, kHash, + // kHashGenFile, + kHashDir, kStdIn, kStdOut, @@ -141,6 +143,7 @@ enum Enum kListfileCharSet, kConsoleCharSet, kTechMode, + kListFields, kPreserveATime, kShareForWrite, @@ -273,6 +276,8 @@ static const CSwitchForm kSwitchForms[] = { "sfx", SWFRM_STRING }, { "seml", SWFRM_STRING_SINGL(0) }, { "scrc", SWFRM_STRING_MULT(0) }, + // { "scrf", SWFRM_STRING_SINGL(1) }, + { "shd", SWFRM_STRING_SINGL(1) }, { "si", SWFRM_STRING }, { "so", SWFRM_SIMPLE }, @@ -281,6 +286,7 @@ static const CSwitchForm kSwitchForms[] = { "scs", SWFRM_STRING }, { "scc", SWFRM_STRING }, { "slt", SWFRM_SIMPLE }, + { "slf", SWFRM_STRING_SINGL(1) }, { "ssp", SWFRM_SIMPLE }, { "ssw", SWFRM_SIMPLE }, @@ -626,7 +632,21 @@ static void AddSwitchWildcardsToCensor( errorMessage = "Too short switch"; break; } - + + if (!include) + { + if (name.IsEqualTo_Ascii_NoCase("td")) + { + censor.ExcludeDirItems = true; + continue; + } + if (name.IsEqualTo_Ascii_NoCase("tf")) + { + censor.ExcludeFileItems = true; + continue; + } + } + if (::MyCharLower_Ascii(name[pos]) == kRecursedIDChar) { pos++; @@ -875,6 +895,11 @@ void CArcCmdLineParser::Parse1(const UStringVector &commandStrings, options.StdInMode = parser[NKey::kStdIn].ThereIs; options.StdOutMode = parser[NKey::kStdOut].ThereIs; options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs; + if (parser[NKey::kListFields].ThereIs) + { + const UString &s = parser[NKey::kListFields].PostStrings[0]; + options.ListFields = GetAnsiString(s); + } options.TechMode = parser[NKey::kTechMode].ThereIs; options.ShowTime = parser[NKey::kShowTime].ThereIs; @@ -1094,6 +1119,27 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) if (parser[NKey::kHash].ThereIs) options.HashMethods = parser[NKey::kHash].PostStrings; + + /* + if (parser[NKey::kHashGenFile].ThereIs) + { + const UString &s = parser[NKey::kHashGenFile].PostStrings[0]; + for (unsigned i = 0 ; i < s.Len();) + { + const wchar_t c = s[i++]; + if (!options.HashOptions.ParseFlagCharOption(c, true)) + { + if (c != '=') + throw CArcCmdLineException("Unsupported hash mode switch:", s); + options.HashOptions.HashFilePath = s.Ptr(i); + break; + } + } + } + */ + + if (parser[NKey::kHashDir].ThereIs) + options.ExtractOptions.HashDir = parser[NKey::kHashDir].PostStrings[0]; if (parser[NKey::kElimDup].ThereIs) { @@ -1232,6 +1278,9 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) { CExtractOptionsBase &eo = options.ExtractOptions; + eo.ExcludeDirItems = options.Censor.ExcludeDirItems; + eo.ExcludeFileItems = options.Censor.ExcludeFileItems; + { CExtractNtOptions &nt = eo.NtOptions; nt.NtSecurity = options.NtSecurity; @@ -1252,6 +1301,11 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs; + + if (parser[NKey::kPreserveATime].ThereIs) + nt.PreserveATime = true; + if (parser[NKey::kShareForWrite].ThereIs) + nt.OpenShareForWrite = true; } options.Censor.AddPathsToCensor(NWildcard::k_AbsPath); @@ -1422,6 +1476,7 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) CHashOptions &hashOptions = options.HashOptions; hashOptions.PathMode = censorPathMode; hashOptions.Methods = options.HashMethods; + // hashOptions.HashFilePath = options.HashFilePath; if (parser[NKey::kPreserveATime].ThereIs) hashOptions.PreserveATime = true; if (parser[NKey::kShareForWrite].ThereIs) diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.h b/CPP/7zip/UI/Common/ArchiveCommandLine.h index 1e488d8c..ff4f28ca 100644 --- a/CPP/7zip/UI/Common/ArchiveCommandLine.h +++ b/CPP/7zip/UI/Common/ArchiveCommandLine.h @@ -66,6 +66,8 @@ struct CArcCmdLineOptions bool TechMode; bool ShowTime; + AString ListFields; + int ConsoleCodePage; NWildcard::CCensor Censor; @@ -79,6 +81,7 @@ struct CArcCmdLineOptions #endif UStringVector HashMethods; + // UString HashFilePath; bool AppendName; // UStringVector ArchivePathsSorted; diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp index 40e43d2a..b85a0ae6 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp @@ -47,6 +47,7 @@ static const char * const kCantRenameFile = "Cannot rename existing file"; static const char * const kCantDeleteOutputFile = "Cannot delete output file"; static const char * const kCantDeleteOutputDir = "Cannot delete output folder"; static const char * const kCantOpenOutFile = "Cannot open output file"; +static const char * const kCantOpenInFile = "Cannot open input file"; static const char * const kCantSetFileLen = "Cannot set length for output file"; #ifdef SUPPORT_LINKS static const char * const kCantCreateHardLink = "Cannot create hard link"; @@ -889,7 +890,8 @@ void CArchiveExtractCallback::CorrectPathParts() void CArchiveExtractCallback::CreateFolders() { - UStringVector &pathParts = _item.PathParts; + // 21.04 : we don't change original (_item.PathParts) here + UStringVector pathParts = _item.PathParts; if (!_item.IsDir) { @@ -1078,18 +1080,19 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream IInArchive *archive = _arc->Archive; #endif - const UStringVector &pathParts = _item.PathParts; const UInt32 index = _index; bool isAnti = false; RINOK(_arc->IsItemAnti(index, isAnti)); CorrectPathParts(); - - UString processedPath (MakePathFromParts(pathParts)); + UString processedPath (MakePathFromParts(_item.PathParts)); if (!isAnti) + { + // 21.04: CreateFolders doesn't change (_item.PathParts) CreateFolders(); + } FString fullProcessedPath (us2fs(processedPath)); if (_pathMode != NExtract::NPathMode::kAbsPaths @@ -1295,7 +1298,25 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream +HRESULT CArchiveExtractCallback::GetItem(UInt32 index) +{ + #ifndef _SFX + _item._use_baseParentFolder_mode = _use_baseParentFolder_mode; + if (_use_baseParentFolder_mode) + { + _item._baseParentFolder = (int)_baseParentFolder; + if (_pathMode == NExtract::NPathMode::kFullPaths || + _pathMode == NExtract::NPathMode::kAbsPaths) + _item._baseParentFolder = -1; + } + #endif // _SFX + + #ifdef SUPPORT_ALT_STREAMS + _item.WriteToAltStreamIfColon = _ntOptions.WriteToAltStreamIfColon; + #endif + return _arc->GetItem(index, _item); +} STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) @@ -1339,22 +1360,7 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre IInArchive *archive = _arc->Archive; - #ifndef _SFX - _item._use_baseParentFolder_mode = _use_baseParentFolder_mode; - if (_use_baseParentFolder_mode) - { - _item._baseParentFolder = (int)_baseParentFolder; - if (_pathMode == NExtract::NPathMode::kFullPaths || - _pathMode == NExtract::NPathMode::kAbsPaths) - _item._baseParentFolder = -1; - } - #endif // _SFX - - #ifdef SUPPORT_ALT_STREAMS - _item.WriteToAltStreamIfColon = _ntOptions.WriteToAltStreamIfColon; - #endif - - RINOK(_arc->GetItem(index, _item)); + RINOK(GetItem(index)); { NCOM::CPropVariant prop; @@ -1382,6 +1388,7 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre return S_OK; #endif // SUPPORT_ALT_STREAMS + // we can change (_item.PathParts) in this function UStringVector &pathParts = _item.PathParts; if (_wildcardCensor) @@ -1974,7 +1981,10 @@ STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes) #ifndef _SFX if (ExtractToStreamCallback) - return ExtractToStreamCallback->SetOperationResult7(opRes, BoolToInt(_encrypted)); + { + GetUnpackSize(); + return ExtractToStreamCallback->SetOperationResult8(opRes, BoolToInt(_encrypted), _curSize); + } #endif #ifndef _SFX @@ -2103,6 +2113,82 @@ STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password) } +// ---------- HASH functions ---------- + +FString CArchiveExtractCallback::Hash_GetFullFilePath() +{ + // this function changes _item.PathParts. + CorrectPathParts(); + const UStringVector &pathParts = _item.PathParts; + const UString processedPath (MakePathFromParts(pathParts)); + FString fullProcessedPath (us2fs(processedPath)); + if (_pathMode != NExtract::NPathMode::kAbsPaths + || !NName::IsAbsolutePath(processedPath)) + { + fullProcessedPath = MakePath_from_2_Parts( + DirPathPrefix_for_HashFiles, + // _dirPathPrefix, + fullProcessedPath); + } + return fullProcessedPath; +} + + +STDMETHODIMP CArchiveExtractCallback::GetDiskProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + if (propID == kpidSize) + { + RINOK(GetItem(index)); + const FString fullProcessedPath = Hash_GetFullFilePath(); + NFile::NFind::CFileInfo fi; + if (fi.Find_FollowLink(fullProcessedPath)) + if (!fi.IsDir()) + prop = (UInt64)fi.Size; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CArchiveExtractCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode) +{ + COM_TRY_BEGIN + *inStream = NULL; + // if (index != _index) return E_FAIL; + if (mode != NUpdateNotifyOp::kHashRead) + return E_FAIL; + + RINOK(GetItem(index)); + const FString fullProcessedPath = Hash_GetFullFilePath(); + + CInFileStream *inStreamSpec = new CInFileStream; + CMyComPtr<ISequentialInStream> inStreamRef = inStreamSpec; + inStreamSpec->File.PreserveATime = _ntOptions.PreserveATime; + if (!inStreamSpec->OpenShared(fullProcessedPath, _ntOptions.OpenShareForWrite)) + { + RINOK(SendMessageError_with_LastError(kCantOpenInFile, fullProcessedPath)); + return S_OK; + } + *inStream = inStreamRef.Detach(); + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CArchiveExtractCallback::ReportOperation( + UInt32 /* indexType */, UInt32 /* index */, UInt32 /* op */) +{ + // COM_TRY_BEGIN + return S_OK; + // COM_TRY_END +} + + +// ------------ After Extracting functions ------------ + void CDirPathSortPair::SetNumSlashes(const FChar *s) { for (unsigned numSlashes = 0;;) diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h index 25eb6444..e44801de 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h @@ -62,9 +62,15 @@ struct CExtractNtOptions bool PreAllocateOutFile; + // used for hash arcs only, when we open external files + bool PreserveATime; + bool OpenShareForWrite; + CExtractNtOptions(): ReplaceColonForAltStream(false), - WriteToAltStreamIfColon(false) + WriteToAltStreamIfColon(false), + PreserveATime(false), + OpenShareForWrite(false) { SymLinks.Val = true; SymLinks_AllowDangerous.Val = false; @@ -205,6 +211,8 @@ class CArchiveExtractCallback: public IArchiveExtractCallbackMessage, public ICryptoGetTextPassword, public ICompressProgressInfo, + public IArchiveUpdateCallbackFile, + public IArchiveGetDiskProperty, public CMyUnknownImp { const CArc *_arc; @@ -342,6 +350,9 @@ class CArchiveExtractCallback: HRESULT GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined); HRESULT GetUnpackSize(); + FString Hash_GetFullFilePath(); + +public: HRESULT SendMessageError(const char *message, const FString &path); HRESULT SendMessageError_with_LastError(const char *message, const FString &path); HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2); @@ -356,10 +367,20 @@ public: UInt64 UnpackSize; UInt64 AltStreams_UnpackSize; - MY_UNKNOWN_IMP3(IArchiveExtractCallbackMessage, ICryptoGetTextPassword, ICompressProgressInfo) + FString DirPathPrefix_for_HashFiles; + + MY_UNKNOWN_IMP5( + IArchiveExtractCallbackMessage, + ICryptoGetTextPassword, + ICompressProgressInfo, + IArchiveUpdateCallbackFile, + IArchiveGetDiskProperty + ) INTERFACE_IArchiveExtractCallback(;) INTERFACE_IArchiveExtractCallbackMessage(;) + INTERFACE_IArchiveUpdateCallbackFile(;) + INTERFACE_IArchiveGetDiskProperty(;) STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); @@ -453,6 +474,7 @@ private: bool _isRenamed; HRESULT CheckExistFile(FString &fullProcessedPath, bool &needExit); HRESULT GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit); + HRESULT GetItem(UInt32 index); HRESULT CloseFile(); HRESULT CloseReparseAndFile(); diff --git a/CPP/7zip/UI/Common/Bench.cpp b/CPP/7zip/UI/Common/Bench.cpp index fb4c1726..2ee29913 100644 --- a/CPP/7zip/UI/Common/Bench.cpp +++ b/CPP/7zip/UI/Common/Bench.cpp @@ -639,15 +639,22 @@ STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 static const unsigned kSubBits = 8; -static UInt32 GetLogSize(UInt64 size) +static unsigned GetLogSize(UInt64 size) +{ + unsigned i = 0; + for (;;) + { + i++; size >>= 1; if (size == 0) break; + } + return i; +} + + +static UInt32 GetLogSize_Sub(UInt64 size) { if (size <= 1) return 0; - unsigned i; - for (i = 2; i < 64; i++) - if (size < ((UInt64)1 << i)) - break; - i--; + const unsigned i = GetLogSize(size) - 1; UInt32 v; if (i <= kSubBits) v = (UInt32)(size) << (kSubBits - i); @@ -656,60 +663,101 @@ static UInt32 GetLogSize(UInt64 size) return ((UInt32)i << kSubBits) + (v & (((UInt32)1 << kSubBits) - 1)); } -static void NormalizeVals(UInt64 &v1, UInt64 &v2) + +static UInt64 Get_UInt64_from_double(double v) +{ + const UInt64 kMaxVal = (UInt64)1 << 62; + if (v > (double)(Int64)kMaxVal) + return kMaxVal; + return (UInt64)v; +} + +static UInt64 MyMultDiv64(UInt64 m1, UInt64 m2, UInt64 d) { - while (v1 >= ((UInt32)1 << ((64 - kBenchmarkUsageMultBits) / 2))) + if (d == 0) + d = 1; + const double v = + (double)(Int64)m1 * + (double)(Int64)m2 / + (double)(Int64)d; + return Get_UInt64_from_double(v); + /* + unsigned n1 = GetLogSize(m1); + unsigned n2 = GetLogSize(m2); + while (n1 + n2 > 64) { - v1 >>= 1; - v2 >>= 1; + if (n1 >= n2) + { + m1 >>= 1; + n1--; + } + else + { + m2 >>= 1; + n2--; + } + d >>= 1; } + + if (d == 0) + d = 1; + return m1 * m2 / d; + */ } + UInt64 CBenchInfo::GetUsage() const { UInt64 userTime = UserTime; UInt64 userFreq = UserFreq; UInt64 globalTime = GlobalTime; UInt64 globalFreq = GlobalFreq; - NormalizeVals(userTime, userFreq); - NormalizeVals(globalFreq, globalTime); + if (userFreq == 0) userFreq = 1; if (globalTime == 0) globalTime = 1; - return userTime * globalFreq * kBenchmarkUsageMult / userFreq / globalTime; + + const double v = + ((double)(Int64)userTime / (double)(Int64)userFreq) + * ((double)(Int64)globalFreq / (double)(Int64)globalTime) + * (double)(Int64)kBenchmarkUsageMult; + return Get_UInt64_from_double(v); + /* + return MyMultDiv64( + MyMultDiv64(kBenchmarkUsageMult, userTime, userFreq), + globalFreq, globalTime); + */ } + UInt64 CBenchInfo::GetRatingPerUsage(UInt64 rating) const { - UInt64 userTime = UserTime; - UInt64 userFreq = UserFreq; - UInt64 globalTime = GlobalTime; - UInt64 globalFreq = GlobalFreq; - NormalizeVals(userFreq, userTime); - NormalizeVals(globalTime, globalFreq); - if (globalFreq == 0) - globalFreq = 1; - if (userTime == 0) + if (UserTime == 0) { return 0; // userTime = 1; } - return userFreq * globalTime / globalFreq * rating / userTime; -} + UInt64 globalFreq = GlobalFreq; + if (globalFreq == 0) + globalFreq = 1; -static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq) -{ - UInt64 elTime = elapsedTime; - NormalizeVals(freq, elTime); - if (elTime == 0) - elTime = 1; - return value * freq / elTime; + const double v = + ((double)(Int64)GlobalTime / (double)(Int64)globalFreq) + * ((double)(Int64)UserFreq / (double)(Int64)UserTime) + * (double)(Int64)rating; + return Get_UInt64_from_double(v); + /* + return MyMultDiv64( + MyMultDiv64(rating, UserFreq, UserTime), + GlobalTime, globalFreq); + */ } + UInt64 CBenchInfo::GetSpeed(UInt64 numUnits) const { - return MyMultDiv64(numUnits, GlobalTime, GlobalFreq); + return MyMultDiv64(numUnits, GlobalFreq, GlobalTime); } struct CBenchProps @@ -764,24 +812,24 @@ UInt64 CBenchProps::GetCompressRating(UInt64 dictSize, UInt64 elapsedTime, UInt6 /* for (UInt64 uu = 0; uu < (UInt64)0xf << 60;) { - unsigned rr = GetLogSize(uu); + unsigned rr = GetLogSize_Sub(uu); printf("\n%16I64x , log = %4x", uu, rr); uu += 1; uu += uu / 50; } */ // throw 1; - const UInt32 t = GetLogSize(dictSize) - (kBenchMinDicLogSize << kSubBits); + const UInt32 t = GetLogSize_Sub(dictSize) - (kBenchMinDicLogSize << kSubBits); encComplex = 870 + ((t * t * 5) >> (2 * kSubBits)); } const UInt64 numCommands = (UInt64)size * encComplex; - return MyMultDiv64(numCommands, elapsedTime, freq); + return MyMultDiv64(numCommands, freq, elapsedTime); } UInt64 CBenchProps::GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) { const UInt64 numCommands = (inSize * DecComplexCompr + outSize * DecComplexUnc) * numIterations; - return MyMultDiv64(numCommands, elapsedTime, freq); + return MyMultDiv64(numCommands, freq, elapsedTime); } @@ -2675,8 +2723,8 @@ void CTotalBenchRes::Mult_For_Weight(unsigned weight) NumIterations2 *= weight; RPU *= weight; Rating *= weight; - Usage += weight; - Speed += weight; + Usage *= weight; + Speed *= weight; } void CTotalBenchRes::Update_With_Res(const CTotalBenchRes &r) @@ -3712,7 +3760,7 @@ HRESULT Bench( start = 1; const UInt64 freq = GetFreq(); // mips is constant in some compilers - const UInt64 hz = MyMultDiv64(numMilCommands * 1000000, start, freq); + const UInt64 hz = MyMultDiv64(numMilCommands * 1000000, freq, start); const UInt64 mipsVal = numMilCommands * freq / start; if (printCallback) { diff --git a/CPP/7zip/UI/Common/CompressCall.cpp b/CPP/7zip/UI/Common/CompressCall.cpp index 72a61685..84a8d22f 100644 --- a/CPP/7zip/UI/Common/CompressCall.cpp +++ b/CPP/7zip/UI/Common/CompressCall.cpp @@ -265,22 +265,56 @@ void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bo MY_TRY_FINISH_VOID } -void TestArchives(const UStringVector &arcPaths) + +void TestArchives(const UStringVector &arcPaths, bool hashMode) { MY_TRY_BEGIN UString params ('t'); + if (hashMode) + { + params += kArchiveTypeSwitch; + params += "hash"; + } ExtractGroupCommand(arcPaths, params, false); MY_TRY_FINISH_VOID } -void CalcChecksum(const UStringVector &paths, const UString &methodName) + +void CalcChecksum(const UStringVector &paths, + const UString &methodName, + const UString &arcPathPrefix, + const UString &arcFileName) { MY_TRY_BEGIN + + if (!arcFileName.IsEmpty()) + { + CompressFiles( + arcPathPrefix, + arcFileName, + UString("hash"), + false, // addExtension, + paths, + false, // email, + false, // showDialog, + false // waitFinish + ); + return; + } + UString params ('h'); if (!methodName.IsEmpty()) { params += " -scrc"; params += methodName; + /* + if (!arcFileName.IsEmpty()) + { + // not used alternate method of generating file + params += " -scrf="; + params += GetQuotedString(arcPathPrefix + arcFileName); + } + */ } ExtractGroupCommand(paths, params, true); MY_TRY_FINISH_VOID diff --git a/CPP/7zip/UI/Common/CompressCall.h b/CPP/7zip/UI/Common/CompressCall.h index c71c21f7..b817df0f 100644 --- a/CPP/7zip/UI/Common/CompressCall.h +++ b/CPP/7zip/UI/Common/CompressCall.h @@ -16,8 +16,13 @@ HRESULT CompressFiles( bool email, bool showDialog, bool waitFinish); void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup); -void TestArchives(const UStringVector &arcPaths); -void CalcChecksum(const UStringVector &paths, const UString &methodName); +void TestArchives(const UStringVector &arcPaths, bool hashMode = false); + +void CalcChecksum(const UStringVector &paths, + const UString &methodName, + const UString &arcPathPrefix, + const UString &arcFileName); + void Benchmark(bool totalMode); #endif diff --git a/CPP/7zip/UI/Common/CompressCall2.cpp b/CPP/7zip/UI/Common/CompressCall2.cpp index 8943e7d9..e6e42d64 100644 --- a/CPP/7zip/UI/Common/CompressCall2.cpp +++ b/CPP/7zip/UI/Common/CompressCall2.cpp @@ -38,7 +38,8 @@ static void ThrowException_if_Error(HRESULT res) #define CREATE_CODECS \ CCodecs *codecs = new CCodecs; \ CMyComPtr<ICompressCodecsInfo> compressCodecsInfo = codecs; \ - ThrowException_if_Error(codecs->Load()); + ThrowException_if_Error(codecs->Load()); \ + Codecs_AddHashArcHandler(codecs); #define LOAD_EXTERNAL_CODECS \ CExternalCodecs __externalCodecs; \ @@ -51,7 +52,8 @@ static void ThrowException_if_Error(HRESULT res) #define CREATE_CODECS \ CCodecs *codecs = new CCodecs; \ CMyComPtr<IUnknown> compressCodecsInfo = codecs; \ - ThrowException_if_Error(codecs->Load()); + ThrowException_if_Error(codecs->Load()); \ + Codecs_AddHashArcHandler(codecs); #define LOAD_EXTERNAL_CODECS @@ -150,7 +152,8 @@ HRESULT CompressFiles( static HRESULT ExtractGroupCommand(const UStringVector &arcPaths, - bool showDialog, const UString &outFolder, bool testMode, bool elimDup = false) + bool showDialog, const UString &outFolder, bool testMode, bool elimDup = false, + const char *kType = NULL) { MY_TRY_BEGIN @@ -187,6 +190,15 @@ static HRESULT ExtractGroupCommand(const UStringVector &arcPaths, } CObjectVector<COpenType> formatIndices; + if (kType) + { + if (!ParseOpenTypes(*codecs, UString(kType), formatIndices)) + { + throw CSystemException(E_INVALIDARG); + // ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE); + // return E_INVALIDARG; + } + } NWildcard::CCensor censor; { @@ -221,14 +233,34 @@ void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bo ExtractGroupCommand(arcPaths, showDialog, outFolder, false, elimDup); } -void TestArchives(const UStringVector &arcPaths) +void TestArchives(const UStringVector &arcPaths, bool hashMode) { - ExtractGroupCommand(arcPaths, true, UString(), true); + ExtractGroupCommand(arcPaths, true, UString(), true, + false, // elimDup + hashMode ? "hash" : NULL); } -void CalcChecksum(const UStringVector &paths, const UString &methodName) +void CalcChecksum(const UStringVector &paths, + const UString &methodName, + const UString &arcPathPrefix, + const UString &arcFileName) { MY_TRY_BEGIN + + if (!arcFileName.IsEmpty()) + { + CompressFiles( + arcPathPrefix, + arcFileName, + UString("hash"), + false, // addExtension, + paths, + false, // email, + false, // showDialog, + false // waitFinish + ); + return; + } CREATE_CODECS LOAD_EXTERNAL_CODECS @@ -245,6 +277,11 @@ void CalcChecksum(const UStringVector &paths, const UString &methodName) CHashOptions options; options.Methods.Add(methodName); + /* + if (!arcFileName.IsEmpty()) + options.HashFilePath = arcPathPrefix + arcFileName; + */ + result = HashCalcGUI(EXTERNAL_CODECS_VARS_L censor, options, messageWasDisplayed); if (result != S_OK) { diff --git a/CPP/7zip/UI/Common/DirItem.h b/CPP/7zip/UI/Common/DirItem.h index 337cd1a7..55b2872c 100644 --- a/CPP/7zip/UI/Common/DirItem.h +++ b/CPP/7zip/UI/Common/DirItem.h @@ -141,7 +141,16 @@ public: bool SymLinks; bool ScanAltStreams; - + bool ExcludeDirItems; + bool ExcludeFileItems; + + /* it must be called after anotrher checks */ + bool CanIncludeItem(bool isDir) const + { + return isDir ? !ExcludeDirItems : !ExcludeFileItems; + } + + CDirItemsStat Stat; #if !defined(UNDER_CE) diff --git a/CPP/7zip/UI/Common/EnumDirItems.cpp b/CPP/7zip/UI/Common/EnumDirItems.cpp index 7a2dd008..59baa092 100644 --- a/CPP/7zip/UI/Common/EnumDirItems.cpp +++ b/CPP/7zip/UI/Common/EnumDirItems.cpp @@ -146,6 +146,8 @@ bool InitLocalPrivileges(); CDirItems::CDirItems(): SymLinks(false), ScanAltStreams(false) + , ExcludeDirItems(false) + , ExcludeFileItems(false) #ifdef _USE_SECURITY_CODE , ReadSecure(false) #endif @@ -318,6 +320,8 @@ HRESULT CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phy */ #endif + if (CanIncludeItem(fi.IsDir())) + { int secureIndex = -1; #ifdef _USE_SECURITY_CODE if (ReadSecure) @@ -325,8 +329,8 @@ HRESULT CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phy RINOK(AddSecurityItem(phyPrefix + fi.Name, secureIndex)); } #endif - AddDirFileInfo(phyParent, logParent, secureIndex, fi); + } if (Callback && (i & kScanProgressStepMask) == kScanProgressStepMask) { @@ -392,6 +396,8 @@ HRESULT CDirItems::EnumerateItems2( phyParentCur = (int)AddPrefix(phyParent, logParent, fs2us(phyPrefixCur)); } + if (CanIncludeItem(fi.IsDir())) + { int secureIndex = -1; #ifdef _USE_SECURITY_CODE if (ReadSecure) @@ -399,8 +405,8 @@ HRESULT CDirItems::EnumerateItems2( RINOK(AddSecurityItem(phyPath, secureIndex)); } #endif - AddDirFileInfo(phyParentCur, logParent, secureIndex, fi); + } if (fi.IsDir()) { @@ -470,6 +476,9 @@ static HRESULT EnumerateAltStreams( bool addAllSubStreams, CDirItems &dirItems) { + // we don't use (ExcludeFileItems) rules for AltStreams + // if (dirItems.ExcludeFileItems) return S_OK; + NFind::CStreamEnumerator enumerator(phyPath); for (;;) { @@ -560,29 +569,42 @@ static HRESULT EnumerateForItem( int dirItemIndex = -1; #if defined(_WIN32) bool addAllSubStreams = false; + bool needAltStreams = true; #endif // _WIN32 #endif // !defined(UNDER_CE) // check the path in inlcude rules if (curNode.CheckPathToRoot(true, newParts, !fi.IsDir())) { - int secureIndex = -1; - #ifdef _USE_SECURITY_CODE - if (dirItems.ReadSecure) - { - RINOK(dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex)); - } - #endif - #if !defined(UNDER_CE) - dirItemIndex = (int)dirItems.Items.Size(); + // dirItemIndex = (int)dirItems.Items.Size(); #if defined(_WIN32) // we will not check include rules for substreams. addAllSubStreams = true; #endif // _WIN32 #endif // !defined(UNDER_CE) - dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi); + if (dirItems.CanIncludeItem(fi.IsDir())) + { + int secureIndex = -1; + #ifdef _USE_SECURITY_CODE + if (dirItems.ReadSecure) + { + RINOK(dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex)); + } + #endif + #if !defined(UNDER_CE) + dirItemIndex = (int)dirItems.Items.Size(); + #endif // !defined(UNDER_CE) + dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi); + } + else + { + #if defined(_WIN32) && !defined(UNDER_CE) + needAltStreams = false; + #endif + } + if (fi.IsDir()) enterToSubFolders = true; } @@ -600,7 +622,7 @@ static HRESULT EnumerateForItem( } #if defined(_WIN32) - if (dirItems.ScanAltStreams) + if (needAltStreams && dirItems.ScanAltStreams) { RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent, phyPrefix + fi.Name, // with (fi.Name) @@ -814,6 +836,9 @@ static HRESULT EnumerateDirItems( continue; } + + if (dirItems.CanIncludeItem(fi.IsDir())) + { int secureIndex = -1; #ifdef _USE_SECURITY_CODE if (needSecurity && dirItems.ReadSecure) @@ -848,6 +873,7 @@ static HRESULT EnumerateDirItems( #endif // defined(_WIN32) #endif // !defined(UNDER_CE) + } #ifndef _WIN32 diff --git a/CPP/7zip/UI/Common/Extract.cpp b/CPP/7zip/UI/Common/Extract.cpp index 18bd1037..de2aeb26 100644 --- a/CPP/7zip/UI/Common/Extract.cpp +++ b/CPP/7zip/UI/Common/Extract.cpp @@ -7,11 +7,13 @@ #include "../../../Common/StringConvert.h" #include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" #include "../../../Windows/ErrorMsg.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/PropVariantConv.h" #include "../Common/ExtractingFilePath.h" +#include "../Common/HashCalc.h" #include "Extract.h" #include "SetProperties.h" @@ -87,7 +89,7 @@ static HRESULT DecompressArchive( } } - bool allFilesAreAllowed = wildcardCensor.AreAllAllowed(); + const bool allFilesAreAllowed = wildcardCensor.AreAllAllowed(); if (!options.StdInMode) { @@ -98,9 +100,14 @@ static HRESULT DecompressArchive( for (UInt32 i = 0; i < numItems; i++) { - if (elimIsPossible || !allFilesAreAllowed) + if (elimIsPossible + || !allFilesAreAllowed + || options.ExcludeDirItems + || options.ExcludeFileItems) { RINOK(arc.GetItem(i, item)); + if (item.IsDir ? options.ExcludeDirItems : options.ExcludeFileItems) + continue; } else { @@ -254,6 +261,7 @@ int Find_FileName_InSortedVector(const UStringVector &fileName, const UString &n HRESULT Extract( + // DECL_EXTERNAL_CODECS_LOC_VARS CCodecs *codecs, const CObjectVector<COpenType> &types, const CIntVector &excludedFormats, @@ -409,6 +417,31 @@ HRESULT Extract( continue; } + if (arcLink.Arcs.Size() != 0) + { + if (arcLink.GetArc()->IsHashHandler(op)) + { + if (!options.TestMode) + { + /* real Extracting to files is possible. + But user can think that hash archive contains real files. + So we block extracting here. */ + return E_NOTIMPL; + } + FString dirPrefix = us2fs(options.HashDir); + if (dirPrefix.IsEmpty()) + { + if (!NFile::NDir::GetOnlyDirPrefix(us2fs(arcPath), dirPrefix)) + { + // return GetLastError_noZero_HRESULT(); + } + } + if (!dirPrefix.IsEmpty()) + NName::NormalizeDirPathPrefix(dirPrefix); + ecs->DirPathPrefix_for_HashFiles = dirPrefix; + } + } + if (!options.StdInMode) { // numVolumes += arcLink.VolumePaths.Size(); diff --git a/CPP/7zip/UI/Common/Extract.h b/CPP/7zip/UI/Common/Extract.h index bfabe195..10e06dad 100644 --- a/CPP/7zip/UI/Common/Extract.h +++ b/CPP/7zip/UI/Common/Extract.h @@ -17,7 +17,10 @@ struct CExtractOptionsBase { CBoolPair ElimDup; - + + bool ExcludeDirItems; + bool ExcludeFileItems; + bool PathMode_Force; bool OverwriteMode_Force; NExtract::NPathMode::EEnum PathMode; @@ -25,8 +28,11 @@ struct CExtractOptionsBase FString OutputDir; CExtractNtOptions NtOptions; + UString HashDir; CExtractOptionsBase(): + ExcludeDirItems(false), + ExcludeFileItems(false), PathMode_Force(false), OverwriteMode_Force(false), PathMode(NExtract::NPathMode::kFullPaths), @@ -48,9 +54,11 @@ struct CExtractOptions: public CExtractOptionsBase CObjectVector<CProperty> Properties; #endif + /* #ifdef EXTERNAL_CODECS CCodecs *Codecs; #endif + */ CExtractOptions(): StdInMode(false), @@ -77,6 +85,7 @@ struct CDecompressStat }; HRESULT Extract( + // DECL_EXTERNAL_CODECS_LOC_VARS CCodecs *codecs, const CObjectVector<COpenType> &types, const CIntVector &excludedFormats, diff --git a/CPP/7zip/UI/Common/HashCalc.cpp b/CPP/7zip/UI/Common/HashCalc.cpp index c87be443..654da86b 100644 --- a/CPP/7zip/UI/Common/HashCalc.cpp +++ b/CPP/7zip/UI/Common/HashCalc.cpp @@ -3,30 +3,40 @@ #include "StdAfx.h" #include "../../../../C/Alloc.h" +#include "../../../../C/CpuArch.h" +#include "../../../Common/DynLimBuf.h" +#include "../../../Common/IntToString.h" #include "../../../Common/StringToInt.h" #include "../../Common/FileStreams.h" -#include "../../Common/StreamUtils.h" +#include "../../Common/ProgressUtils.h" #include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "../../Archive/Common/ItemNameUtils.h" #include "EnumDirItems.h" #include "HashCalc.h" using namespace NWindows; +#ifdef EXTERNAL_CODECS +extern const CExternalCodecs *g_ExternalCodecs_Ptr; +#endif + class CHashMidBuf { void *_data; public: - CHashMidBuf(): _data(0) {} + CHashMidBuf(): _data(NULL) {} operator void *() { return _data; } bool Alloc(size_t size) { - if (_data != 0) + if (_data) return false; _data = ::MidAlloc(size); - return _data != 0; + return _data != NULL; } ~CHashMidBuf() { ::MidFree(_data); } }; @@ -91,15 +101,15 @@ HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVecto if (scp) RINOK(m.SetCoderProps(scp, NULL)); } - UInt32 digestSize = hasher->GetDigestSize(); + const UInt32 digestSize = hasher->GetDigestSize(); if (digestSize > k_HashCalc_DigestSize_Max) return E_NOTIMPL; CHasherState &h = Hashers.AddNew(); + h.DigestSize = digestSize; h.Hasher = hasher; h.Name = name; - h.DigestSize = digestSize; for (unsigned k = 0; k < k_HashCalc_NumGroups; k++) - memset(h.Digests[k], 0, digestSize); + h.InitDigestGroup(k); } return S_OK; @@ -112,7 +122,7 @@ void CHashBundle::InitForNewFile() { CHasherState &h = Hashers[i]; h.Hasher->Init(); - memset(h.Digests[k_HashCalc_Index_Current], 0, h.DigestSize); + h.InitDigestGroup(k_HashCalc_Index_Current); } } @@ -131,14 +141,46 @@ void CHashBundle::SetSize(UInt64 size) static void AddDigests(Byte *dest, const Byte *src, UInt32 size) { unsigned next = 0; - for (UInt32 i = 0; i < size; i++) + /* + // we could use big-endian addition for sha-1 and sha-256 + // but another hashers are little-endian + if (size > 8) + { + for (unsigned i = size; i != 0;) + { + i--; + next += (unsigned)dest[i] + (unsigned)src[i]; + dest[i] = (Byte)next; + next >>= 8; + } + } + else + */ { - next += (unsigned)dest[i] + (unsigned)src[i]; + for (unsigned i = 0; i < size; i++) + { + next += (unsigned)dest[i] + (unsigned)src[i]; + dest[i] = (Byte)next; + next >>= 8; + } + } + + // we use little-endian to store extra bytes + dest += k_HashCalc_DigestSize_Max; + for (unsigned i = 0; i < k_HashCalc_ExtraSize; i++) + { + next += (unsigned)dest[i]; dest[i] = (Byte)next; next >>= 8; } } +void CHasherState::AddDigest(unsigned groupIndex, const Byte *data) +{ + NumSums[groupIndex]++; + AddDigests(Digests[groupIndex], data, DigestSize); +} + void CHashBundle::Final(bool isDir, bool isAltStream, const UString &path) { if (isDir) @@ -164,9 +206,9 @@ void CHashBundle::Final(bool isDir, bool isAltStream, const UString &path) CHasherState &h = Hashers[i]; if (!isDir) { - h.Hasher->Final(h.Digests[0]); + h.Hasher->Final(h.Digests[0]); // k_HashCalc_Index_Current if (!isAltStream) - AddDigests(h.Digests[k_HashCalc_Index_DataSum], h.Digests[0], h.DigestSize); + h.AddDigest(k_HashCalc_Index_DataSum, h.Digests[0]); } h.Hasher->Init(); @@ -176,6 +218,15 @@ void CHashBundle::Final(bool isDir, bool isAltStream, const UString &path) for (unsigned k = 0; k < path.Len(); k++) { wchar_t c = path[k]; + + // 21.04: we want same hash for linux and windows paths + #if CHAR_PATH_SEPARATOR != '/' + if (c == CHAR_PATH_SEPARATOR) + c = '/'; + // if (c == (wchar_t)('\\' + 0xf000)) c = '\\'; // to debug WSL + // if (c > 0xf000 && c < 0xf080) c -= 0xf000; // to debug WSL + #endif + Byte temp[2] = { (Byte)(c & 0xFF), (Byte)((c >> 8) & 0xFF) }; h.Hasher->Update(temp, 2); } @@ -183,12 +234,221 @@ void CHashBundle::Final(bool isDir, bool isAltStream, const UString &path) Byte tempDigest[k_HashCalc_DigestSize_Max]; h.Hasher->Final(tempDigest); if (!isAltStream) - AddDigests(h.Digests[k_HashCalc_Index_NamesSum], tempDigest, h.DigestSize); - AddDigests(h.Digests[k_HashCalc_Index_StreamsSum], tempDigest, h.DigestSize); + h.AddDigest(k_HashCalc_Index_NamesSum, tempDigest); + h.AddDigest(k_HashCalc_Index_StreamsSum, tempDigest); } } +static void CSum_Name_OriginalToEscape(const AString &src, AString &dest) +{ + dest.Empty(); + for (unsigned i = 0; i < src.Len();) + { + char c = src[i++]; + if (c == '\n') + { + dest += '\\'; + c = 'n'; + } + else if (c == '\\') + dest += '\\'; + dest += c; + } +} + + +static bool CSum_Name_EscapeToOriginal(const char *s, AString &dest) +{ + bool isOK = true; + dest.Empty(); + for (;;) + { + char c = *s++; + if (c == 0) + break; + if (c == '\\') + { + const char c1 = *s; + if (c1 == 'n') + { + c = '\n'; + s++; + } + else if (c1 == '\\') + { + c = c1; + s++; + } + else + { + // original md5sum returns NULL for such bad strings + isOK = false; + } + } + dest += c; + } + return isOK; +} + + + +static void SetSpacesAndNul(char *s, unsigned num) +{ + for (unsigned i = 0; i < num; i++) + s[i] = ' '; + s[num] = 0; +} + +static const unsigned kHashColumnWidth_Min = 4 * 2; + +static unsigned GetColumnWidth(unsigned digestSize) +{ + const unsigned width = digestSize * 2; + return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width; +} + + +void HashHexToString(char *dest, const Byte *data, UInt32 size); + +static void AddHashResultLine( + AString &_s, + // bool showHash, + // UInt64 fileSize, bool showSize, + const CObjectVector<CHasherState> &hashers + // unsigned digestIndex, = k_HashCalc_Index_Current + ) +{ + FOR_VECTOR (i, hashers) + { + const CHasherState &h = hashers[i]; + char s[k_HashCalc_DigestSize_Max * 2 + 64]; + s[0] = 0; + // if (showHash) + HashHexToString(s, h.Digests[k_HashCalc_Index_Current], h.DigestSize); + const unsigned pos = (unsigned)strlen(s); + const int numSpaces = (int)GetColumnWidth(h.DigestSize) - (int)pos; + if (numSpaces > 0) + SetSpacesAndNul(s + pos, (unsigned)numSpaces); + if (i != 0) + _s += ' '; + _s += s; + } + + /* + if (showSize) + { + _s += ' '; + static const unsigned kSizeField_Len = 13; // same as in HashCon.cpp + char s[kSizeField_Len + 32]; + char *p = s; + SetSpacesAndNul(s, kSizeField_Len); + p = s + kSizeField_Len; + ConvertUInt64ToString(fileSize, p); + int numSpaces = (int)kSizeField_Len - (int)strlen(p); + if (numSpaces > 0) + p -= (unsigned)numSpaces; + _s += p; + } + */ +} + + +static void Add_LF(CDynLimBuf &hashFileString, const CHashOptionsLocal &options) +{ + hashFileString += (char)(options.HashMode_Zero.Val ? 0 : '\n'); +} + + + + +static void WriteLine(CDynLimBuf &hashFileString, + const CHashOptionsLocal &options, + const UString &path2, + bool isDir, + const AString &methodName, + const AString &hashesString) +{ + if (options.HashMode_OnlyHash.Val) + { + hashFileString += hashesString; + Add_LF(hashFileString, options); + return; + } + + UString path = path2; + + bool isBin = false; + const bool zeroMode = options.HashMode_Zero.Val; + const bool tagMode = options.HashMode_Tag.Val; + +#if CHAR_PATH_SEPARATOR != '/' + path.Replace(WCHAR_PATH_SEPARATOR, L'/'); + // path.Replace((wchar_t)('\\' + 0xf000), L'\\'); // to debug WSL +#endif + + AString utf8; + ConvertUnicodeToUTF8(path, utf8); + + AString esc; + CSum_Name_OriginalToEscape(utf8, esc); + + if (!zeroMode) + { + if (esc != utf8) + { + /* Original md5sum writes escape in that case. + We do same for compatibility with original md5sum. */ + hashFileString += '\\'; + } + } + + if (isDir && !esc.IsEmpty() && esc.Back() != '/') + esc += '/'; + + if (tagMode) + { + if (!methodName.IsEmpty()) + { + hashFileString += methodName; + hashFileString += ' '; + } + hashFileString += '('; + hashFileString += esc; + hashFileString += ')'; + hashFileString += " = "; + } + + hashFileString += hashesString; + + if (!tagMode) + { + hashFileString += ' '; + hashFileString += (char)(isBin ? '*' : ' '); + hashFileString += esc; + } + + Add_LF(hashFileString, options); +} + + + +static void WriteLine(CDynLimBuf &hashFileString, + const CHashOptionsLocal &options, + const UString &path, + bool isDir, + const CHashBundle &hb) +{ + AString methodName; + if (!hb.Hashers.IsEmpty()) + methodName = hb.Hashers[0].Name; + + AString hashesString; + AddHashResultLine(hashesString, hb.Hashers); + WriteLine(hashFileString, options, path, isDir, methodName, hashesString); +} + + HRESULT HashCalc( DECL_EXTERNAL_CODECS_LOC_VARS const NWildcard::CCensor &censor, @@ -215,6 +475,8 @@ HRESULT HashCalc( dirItems.SymLinks = options.SymLinks.Val; dirItems.ScanAltStreams = options.AltStreamsMode; + dirItems.ExcludeDirItems = censor.ExcludeDirItems; + dirItems.ExcludeFileItems = censor.ExcludeFileItems; HRESULT res = EnumerateItems(censor, options.PathMode, @@ -255,6 +517,11 @@ HRESULT HashCalc( RINOK(callback->BeforeFirstFile(hb)); + /* + CDynLimBuf hashFileString((size_t)1 << 31); + const bool needGenerate = !options.HashFilePath.IsEmpty(); + */ + for (i = 0; i < dirItems.Items.Size(); i++) { CMyComPtr<ISequentialInStream> inStream; @@ -306,12 +573,15 @@ HRESULT HashCalc( UInt64 fileSize = 0; hb.InitForNewFile(); + if (!isDir) { for (UInt32 step = 0;; step++) { if ((step & 0xFF) == 0) + { RINOK(callback->SetCompleted(&completeValue)); + } UInt32 size; RINOK(inStream->Read(buf, kBufSize, &size)); if (size == 0) @@ -321,20 +591,54 @@ HRESULT HashCalc( completeValue += size; } } + hb.Final(isDir, isAltStream, path); + + /* + if (needGenerate + && (options.HashMode_Dirs.Val || !isDir)) + { + WriteLine(hashFileString, + options, + path, // change it + isDir, + hb); + + if (hashFileString.IsError()) + return E_OUTOFMEMORY; + } + */ + RINOK(callback->SetOperationResult(fileSize, hb, !isDir)); RINOK(callback->SetCompleted(&completeValue)); } + + /* + if (needGenerate) + { + NFile::NIO::COutFile file; + if (!file.Create(us2fs(options.HashFilePath), true)) // createAlways + return GetLastError_noZero_HRESULT(); + if (!file.WriteFull(hashFileString, hashFileString.Len())) + return GetLastError_noZero_HRESULT(); + } + */ + return callback->AfterLastFile(hb); } -static inline char GetHex(unsigned v) +static inline char GetHex_Upper(unsigned v) { return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10))); } -void AddHashHexToString(char *dest, const Byte *data, UInt32 size) +static inline char GetHex_Lower(unsigned v) +{ + return (char)((v < 10) ? ('0' + v) : ('a' + (v - 10))); +} + +void HashHexToString(char *dest, const Byte *data, UInt32 size) { dest[size * 2] = 0; @@ -349,18 +653,1393 @@ void AddHashHexToString(char *dest, const Byte *data, UInt32 size) return; } - int step = 2; if (size <= 8) { - step = -2; - dest += size * 2 - 2; + dest += size * 2; + for (UInt32 i = 0; i < size; i++) + { + const unsigned b = data[i]; + dest -= 2; + dest[0] = GetHex_Upper((b >> 4) & 0xF); + dest[1] = GetHex_Upper(b & 0xF); + } + } + else + { + for (UInt32 i = 0; i < size; i++) + { + const unsigned b = data[i]; + dest[0] = GetHex_Lower((b >> 4) & 0xF); + dest[1] = GetHex_Lower(b & 0xF); + dest += 2; + } + } +} + +void CHasherState::WriteToString(unsigned digestIndex, char *s) const +{ + HashHexToString(s, Digests[digestIndex], DigestSize); + + if (digestIndex != 0 && NumSums[digestIndex] != 1) + { + unsigned numExtraBytes = GetNumExtraBytes_for_Group(digestIndex); + if (numExtraBytes > 4) + numExtraBytes = 8; + else // if (numExtraBytes >= 0) + numExtraBytes = 4; + // if (numExtraBytes != 0) + { + s += strlen(s); + *s++ = '-'; + // *s = 0; + HashHexToString(s, GetExtraData_for_Group(digestIndex), numExtraBytes); + } + } +} + + + +// ---------- Hash Handler ---------- + +namespace NHash { + +static size_t ParseHexString(const char *s, Byte *dest) throw() +{ + size_t num; + for (num = 0;; num++, s += 2) + { + unsigned c = (Byte)s[0]; + unsigned v0; + if (c >= '0' && c <= '9') v0 = (c - '0'); + else if (c >= 'A' && c <= 'F') v0 = 10 + (c - 'A'); + else if (c >= 'a' && c <= 'f') v0 = 10 + (c - 'a'); + else + return num; + c = (Byte)s[1]; + unsigned v1; + if (c >= '0' && c <= '9') v1 = (c - '0'); + else if (c >= 'A' && c <= 'F') v1 = 10 + (c - 'A'); + else if (c >= 'a' && c <= 'f') v1 = 10 + (c - 'a'); + else + return num; + if (dest) + dest[num] = (Byte)(v1 | (v0 << 4)); + } +} + + +#define IsWhite(c) ((c) == ' ' || (c) == '\t') + +bool CHashPair::IsDir() const +{ + if (Name.IsEmpty() || Name.Back() != '/') + return false; + // here we expect that Dir items contain only zeros or no Hash + for (size_t i = 0; i < Hash.Size(); i++) + if (Hash[i] != 0) + return false; + return true; +} + + +bool CHashPair::ParseCksum(const char *s) +{ + const char *end; + + const UInt32 crc = ConvertStringToUInt32(s, &end); + if (*end != ' ') + return false; + end++; + + const UInt64 size = ConvertStringToUInt64(end, &end); + if (*end != ' ') + return false; + end++; + + Name = end; + + Hash.Alloc(4); + SetBe32(Hash, crc); + + Size_from_Arc = size; + Size_from_Arc_Defined = true; + + return true; +} + + + +static const char *SkipWhite(const char *s) +{ + while (IsWhite(*s)) + s++; + return s; +} + +static const char * const k_CsumMethodNames[] = +{ + "sha256" + , "sha224" +// , "sha512/224" +// , "sha512/256" + , "sha512" + , "sha384" + , "sha1" + , "md5" + , "blake2b" + , "crc64" + , "crc32" + , "cksum" +}; + +static UString GetMethod_from_FileName(const UString &name) +{ + AString s; + ConvertUnicodeToUTF8(name, s); + const int dotPos = s.ReverseFind_Dot(); + const char *src = s.Ptr(); + bool isExtension = false; + if (dotPos >= 0) + { + isExtension = true; + src = s.Ptr(dotPos + 1); + } + const char *m = ""; + unsigned i; + for (i = 0; i < ARRAY_SIZE(k_CsumMethodNames); i++) + { + m = k_CsumMethodNames[i]; + if (isExtension) + { + if (StringsAreEqual_Ascii(src, m)) + break; + } + else if (IsString1PrefixedByString2_NoCase_Ascii(src, m)) + if (StringsAreEqual_Ascii(src + strlen(m), "sums")) + break; + } + UString res; + if (i != ARRAY_SIZE(k_CsumMethodNames)) + res = m; + return res; +} + + +bool CHashPair::Parse(const char *s) +{ + // here we keep compatibility with original md5sum / shasum + bool escape = false; + + s = SkipWhite(s); + + if (*s == '\\') + { + s++; + escape = true; + } + + // const char *kMethod = GetMethod_from_FileName(s); + // if (kMethod) + if (ParseHexString(s, NULL) < 4) + { + // BSD-style checksum line + { + const char *s2 = s; + for (; *s2 != 0; s2++) + { + const char c = *s2; + if (c == 0) + return false; + if (c == ' ' || c == '(') + break; + } + Method.SetFrom(s, (unsigned)(s2 - s)); + s = s2; + } + IsBSD = true; + if (*s == ' ') + s++; + if (*s != '(') + return false; + s++; + { + const char *s2 = s; + for (; *s2 != 0; s2++) + {} + for (;;) + { + s2--; + if (s2 < s) + return false; + if (*s2 == ')') + break; + } + Name.SetFrom(s, (unsigned)(s2 - s)); + s = s2 + 1; + } + + s = SkipWhite(s); + if (*s != '=') + return false; + s++; + s = SkipWhite(s); + } + + { + const size_t num = ParseHexString(s, NULL); + Hash.Alloc(num); + ParseHexString(s, Hash); + const size_t numChars = num * 2; + HashString.SetFrom(s, (unsigned)numChars); + s += numChars; + } + + if (IsBSD) + { + if (*s != 0) + return false; + if (escape) + { + AString temp = Name; + return CSum_Name_EscapeToOriginal(temp, Name); + } + return true; + } + + if (*s == 0) + return true; + + if (*s != ' ') + return false; + s++; + const char c = *s; + if (c != ' ' + && c != '*' + && c != 'U' // shasum Universal + && c != '^' // shasum 0/1 + ) + return false; + Mode = c; + s++; + if (escape) + return CSum_Name_EscapeToOriginal(s, Name); + Name = s; + return true; +} + + +static bool GetLine(CByteBuffer &buf, bool zeroMode, bool cr_lf_Mode, size_t &posCur, AString &s) +{ + s.Empty(); + size_t pos = posCur; + const Byte *p = buf; + unsigned numDigits = 0; + for (; pos < buf.Size(); pos++) + { + const Byte b = p[pos]; + if (b == 0) + { + numDigits = 1; + break; + } + if (zeroMode) + continue; + if (b == 0x0a) + { + numDigits = 1; + break; + } + if (!cr_lf_Mode) + continue; + if (b == 0x0d) + { + if (pos + 1 >= buf.Size()) + { + numDigits = 1; + break; + // return false; + } + if (p[pos + 1] == 0x0a) + { + numDigits = 2; + break; + } + } + } + s.SetFrom((const char *)(p + posCur), (unsigned)(pos - posCur)); + posCur = pos + numDigits; + return true; +} + + +static bool Is_CR_LF_Data(const Byte *buf, size_t size) +{ + bool isCrLf = false; + for (size_t i = 0; i < size;) + { + const Byte b = buf[i]; + if (b == 0x0a) + return false; + if (b == 0x0d) + { + if (i == size - 1) + return false; + if (buf[i + 1] != 0x0a) + return false; + isCrLf = true; + i += 2; + } + else + i++; + } + return isCrLf; +} + + +static const Byte kArcProps[] = +{ + // kpidComment, + kpidCharacts +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidMethod +}; + +static const Byte kRawProps[] = +{ + kpidChecksum +}; + + +STDMETHODIMP CHandler::GetParent(UInt32 /* index */ , UInt32 *parent, UInt32 *parentType) +{ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; + return S_OK; +} + +STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) +{ + *numProps = ARRAY_SIZE(kRawProps); + return S_OK; +} + +STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) +{ + *propID = kRawProps[index]; + *name = 0; + return S_OK; +} + +STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + + if (propID == kpidChecksum) + { + const CHashPair &hp = HashPairs[index]; + if (hp.Hash.Size() > 0) + { + *data = hp.Hash; + *dataSize = (UInt32)hp.Hash.Size(); + *propType = NPropDataType::kRaw; + } + return S_OK; + } + + return S_OK; +} + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = HashPairs.Size(); + return S_OK; +} + +static void Add_OptSpace_String(UString &dest, const char *src) +{ + dest.Add_Space_if_NotEmpty(); + dest += src; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + /* + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + // if (_sres == k_Base64_RES_NeedMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (v != 0) + prop = v; + break; + } + */ + case kpidCharacts: + { + UString s; + if (_hashSize_Defined) + { + s.Add_Space_if_NotEmpty(); + s.Add_UInt32(_hashSize * 8); + s += "-bit"; + } + if (!_nameExtenstion.IsEmpty()) + { + s.Add_Space_if_NotEmpty(); + s += _nameExtenstion; + } + if (_is_PgpMethod) + { + Add_OptSpace_String(s, "PGP"); + if (!_pgpMethod.IsEmpty()) + { + s += ":"; + s += _pgpMethod; + } + } + if (_is_ZeroMode) + Add_OptSpace_String(s, "ZERO"); + if (_are_there_Tags) + Add_OptSpace_String(s, "TAG"); + if (_are_there_Dirs) + Add_OptSpace_String(s, "DIRS"); + prop = s; + break; + } + + case kpidReadOnly: + { + if (_isArc) + if (!CanUpdate()) + prop = true; + break; + } + } + prop.Detach(value); + return S_OK; +} + + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + // COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + CHashPair &hp = HashPairs[index]; + switch (propID) + { + case kpidIsDir: + { + prop = hp.IsDir(); + break; + } + case kpidPath: + { + UString path; + hp.Get_UString_Path(path); + + NArchive::NItemName::ReplaceToOsSlashes_Remove_TailSlash(path, + true); // useBackslashReplacement + + prop = path; + break; + } + case kpidSize: + { + // client needs processed size of last file + if (hp.Size_from_Disk_Defined) + prop = (UInt64)hp.Size_from_Disk; + else if (hp.Size_from_Arc_Defined) + prop = (UInt64)hp.Size_from_Arc; + break; + } + case kpidPackSize: + { + prop = (UInt64)hp.Hash.Size(); + break; + } + case kpidMethod: + { + if (!hp.Method.IsEmpty()) + prop = hp.Method; + break; + } + } + prop.Detach(value); + return S_OK; + // COM_TRY_END +} + + +static HRESULT ReadStream_to_Buf(IInStream *stream, CByteBuffer &buf, IArchiveOpenCallback *openCallback) +{ + buf.Free(); + UInt64 len; + RINOK(stream->Seek(0, STREAM_SEEK_END, &len)); + if (len == 0 || len >= ((UInt64)1 << 31)) + return S_FALSE; + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + buf.Alloc((size_t)len); + UInt64 pos = 0; + // return ReadStream_FALSE(stream, buf, (size_t)len); + for (;;) + { + const UInt32 kBlockSize = ((UInt32)1 << 24); + const UInt32 curSize = (len < kBlockSize) ? (UInt32)len : kBlockSize; + UInt32 processedSizeLoc; + RINOK(stream->Read((Byte *)buf + pos, curSize, &processedSizeLoc)); + if (processedSizeLoc == 0) + return E_FAIL; + len -= processedSizeLoc; + pos += processedSizeLoc; + if (len == 0) + return S_OK; + if (openCallback) + { + const UInt64 files = 0; + RINOK(openCallback->SetCompleted(&files, &pos)); + } + } +} + + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback) +{ + COM_TRY_BEGIN + { + Close(); + + CByteBuffer buf; + RINOK(ReadStream_to_Buf(stream, buf, openCallback)) + + CObjectVector<CHashPair> &pairs = HashPairs; + + bool zeroMode = false; + bool cr_lf_Mode = false; + { + for (size_t i = 0; i < buf.Size(); i++) + if (buf[i] == 0) + { + zeroMode = true; + break; + } + } + _is_ZeroMode = zeroMode; + if (!zeroMode) + cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size()); + + if (openCallback) + { + CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; + openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + NCOM::CPropVariant prop; + if (openVolumeCallback) + { + RINOK(openVolumeCallback->GetProperty(kpidName, &prop)); + if (prop.vt == VT_BSTR) + _nameExtenstion = GetMethod_from_FileName(prop.bstrVal); + } + } + + bool cksumMode = false; + if (_nameExtenstion.IsEqualTo_Ascii_NoCase("cksum")) + cksumMode = true; + _is_CksumMode = cksumMode; + + size_t pos = 0; + AString s; + bool minusMode = false; + unsigned numLines = 0; + + while (pos < buf.Size()) + { + if (!GetLine(buf, zeroMode, cr_lf_Mode, pos, s)) + return S_FALSE; + numLines++; + if (s.IsEmpty()) + continue; + + if (s.IsPrefixedBy_Ascii_NoCase("; ")) + { + if (numLines != 1) + return S_FALSE; + // comment line of FileVerifier++ + continue; + } + + if (s.IsPrefixedBy_Ascii_NoCase("-----")) + { + if (minusMode) + break; // end of pgp mode + minusMode = true; + if (s.IsPrefixedBy_Ascii_NoCase("-----BEGIN PGP SIGNED MESSAGE")) + { + if (_is_PgpMethod) + return S_FALSE; + if (!GetLine(buf, zeroMode, cr_lf_Mode, pos, s)) + return S_FALSE; + const char *kStart = "Hash: "; + if (!s.IsPrefixedBy_Ascii_NoCase(kStart)) + return S_FALSE; + _pgpMethod = s.Ptr((unsigned)strlen(kStart)); + _is_PgpMethod = true; + } + continue; + } + + CHashPair pair; + pair.FullLine = s; + if (cksumMode) + { + if (!pair.ParseCksum(s)) + return S_FALSE; + } + else if (!pair.Parse(s)) + return S_FALSE; + pairs.Add(pair); + } + + { + unsigned hashSize = 0; + bool hashSize_Dismatch = false; + for (unsigned i = 0; i < HashPairs.Size(); i++) + { + const CHashPair &hp = HashPairs[i]; + if (i == 0) + hashSize = (unsigned)hp.Hash.Size(); + else + if (hashSize != hp.Hash.Size()) + hashSize_Dismatch = true; + + if (hp.IsBSD) + _are_there_Tags = true; + if (!_are_there_Dirs && hp.IsDir()) + _are_there_Dirs = true; + } + if (!hashSize_Dismatch && hashSize != 0) + { + _hashSize = hashSize; + _hashSize_Defined = true; + } + } + + _phySize = buf.Size(); + _isArc = true; + return S_OK; + } + COM_TRY_END +} + + +void CHandler::ClearVars() +{ + _phySize = 0; + _isArc = false; + _is_CksumMode = false; + _is_PgpMethod = false; + _is_ZeroMode = false; + _are_there_Tags = false; + _are_there_Dirs = false; + _hashSize_Defined = false; + _hashSize = 0; +} + + +STDMETHODIMP CHandler::Close() +{ + ClearVars(); + _nameExtenstion.Empty(); + _pgpMethod.Empty(); + HashPairs.Clear(); + return S_OK; +} + + +static bool CheckDigests(const Byte *a, const Byte *b, size_t size) +{ + if (size <= 8) + { + /* we use reversed order for one digest, when text representation + uses big-order for crc-32 and crc-64 */ + for (size_t i = 0; i < size; i++) + if (a[i] != b[size - 1 - i]) + return false; + return true; + } + { + for (size_t i = 0; i < size; i++) + if (a[i] != b[i]) + return false; + return true; + } +} + + +static void AddDefaultMethod(UStringVector &methods, unsigned size) +{ + const char *m = NULL; + if (size == 32) m = "sha256"; + else if (size == 20) m = "sha1"; + else if (size == 16) m = "md5"; + else if (size == 8) m = "crc64"; + else if (size == 4) m = "crc32"; + else + return; + #ifdef EXTERNAL_CODECS + const CExternalCodecs *__externalCodecs = g_ExternalCodecs_Ptr; + #endif + CMethodId id; + if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS + AString(m), id)) + methods.Add(UString(m)); +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + + /* + if (testMode == 0) + return E_NOTIMPL; + */ + + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = HashPairs.Size(); + if (numItems == 0) + return S_OK; + + #ifdef EXTERNAL_CODECS + const CExternalCodecs *__externalCodecs = g_ExternalCodecs_Ptr; + #endif + + CHashBundle hb_Glob; + // UStringVector methods = options.Methods; + UStringVector methods; + + if (methods.IsEmpty() && !_nameExtenstion.IsEmpty()) + { + AString utf; + ConvertUnicodeToUTF8(_nameExtenstion, utf); + CMethodId id; + if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf, id)) + methods.Add(_nameExtenstion); } - for (UInt32 i = 0; i < size; i++) + if (methods.IsEmpty() && !_pgpMethod.IsEmpty()) { - unsigned b = data[i]; - dest[0] = GetHex((b >> 4) & 0xF); - dest[1] = GetHex(b & 0xF); - dest += step; + CMethodId id; + if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS _pgpMethod, id)) + methods.Add(UString(_pgpMethod)); + } + + if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined) + AddDefaultMethod(methods, _hashSize); + + RINOK(hb_Glob.SetMethods( + EXTERNAL_CODECS_LOC_VARS + methods)); + + CMyComPtr<IArchiveUpdateCallbackFile> updateCallbackFile; + extractCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&updateCallbackFile); + if (!updateCallbackFile) + return E_NOTIMPL; + { + CMyComPtr<IArchiveGetDiskProperty> GetDiskProperty; + extractCallback->QueryInterface(IID_IArchiveGetDiskProperty, (void **)&GetDiskProperty); + if (GetDiskProperty) + { + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const UInt32 index = allFilesMode ? i : indices[i]; + const CHashPair &hp = HashPairs[index]; + if (hp.IsDir()) + continue; + { + NCOM::CPropVariant prop; + RINOK(GetDiskProperty->GetDiskProperty(index, kpidSize, &prop)); + if (prop.vt != VT_UI8) + continue; + totalSize += prop.uhVal.QuadPart; + } + } + RINOK(extractCallback->SetTotal(totalSize)); + // RINOK(Hash_SetTotalUnpacked->Hash_SetTotalUnpacked(indices, numItems)); + } + } + + const UInt32 kBufSize = 1 << 15; + CHashMidBuf buf; + if (!buf.Alloc(kBufSize)) + return E_OUTOFMEMORY; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + lps->InSize = lps->OutSize = 0; + + UInt32 i; + for (i = 0; i < numItems; i++) + { + RINOK(lps->SetCur()); + const UInt32 index = allFilesMode ? i : indices[i]; + + CHashPair &hp = HashPairs[index]; + + UString path; + hp.Get_UString_Path(path); + + CMyComPtr<ISequentialInStream> inStream; + const bool isDir = hp.IsDir(); + if (!isDir) + { + RINOK(updateCallbackFile->GetStream2(index, &inStream, NUpdateNotifyOp::kHashRead)); + if (!inStream) + { + continue; // we have shown error in GetStream2() + } + // askMode = NArchive::NExtract::NAskMode::kSkip; + } + + Int32 askMode = testMode ? + NArchive::NExtract::NAskMode::kTest : + NArchive::NExtract::NAskMode::kExtract; + + CMyComPtr<ISequentialOutStream> realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + /* PrepareOperation() can expect kExtract to set + Attrib and security of output file */ + askMode = NArchive::NExtract::NAskMode::kReadExternal; + + extractCallback->PrepareOperation(askMode); + + const bool isAltStream = false; + + UInt64 fileSize = 0; + + CHashBundle hb_Loc; + + CHashBundle *hb_Use = &hb_Glob; + + HRESULT res_SetMethods = S_OK; + + UStringVector methods_loc; + + if (!hp.Method.IsEmpty()) + { + hb_Use = &hb_Loc; + CMethodId id; + if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS hp.Method, id)) + { + methods_loc.Add(UString(hp.Method)); + RINOK(hb_Loc.SetMethods( + EXTERNAL_CODECS_LOC_VARS + methods_loc)); + } + else + res_SetMethods = E_NOTIMPL; + } + else if (methods.IsEmpty()) + { + AddDefaultMethod(methods_loc, (unsigned)hp.Hash.Size()); + if (!methods_loc.IsEmpty()) + { + hb_Use = &hb_Loc; + RINOK(hb_Loc.SetMethods( + EXTERNAL_CODECS_LOC_VARS + methods_loc)); + } + } + + const bool isSupportedMode = hp.IsSupportedMode(); + hb_Use->InitForNewFile(); + + if (inStream) + { + for (UInt32 step = 0;; step++) + { + if ((step & 0xFF) == 0) + { + RINOK(lps->SetRatioInfo(NULL, &fileSize)); + } + UInt32 size; + RINOK(inStream->Read(buf, kBufSize, &size)); + if (size == 0) + break; + hb_Use->Update(buf, size); + if (realOutStream) + { + RINOK(WriteStream(realOutStream, buf, size)); + } + fileSize += size; + } + + hp.Size_from_Disk = fileSize; + hp.Size_from_Disk_Defined = true; + } + + realOutStream.Release(); + inStream.Release(); + + lps->InSize += hp.Hash.Size(); + lps->OutSize += fileSize; + + hb_Use->Final(isDir, isAltStream, path); + + Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod; + if (isSupportedMode + && res_SetMethods != E_NOTIMPL + && hb_Use->Hashers.Size() > 0 + ) + { + const CHasherState &hs = hb_Use->Hashers[0]; + if (hs.DigestSize == hp.Hash.Size()) + { + opRes = NArchive::NExtract::NOperationResult::kCRCError; + if (CheckDigests(hp.Hash, hs.Digests[0], hs.DigestSize)) + if (!hp.Size_from_Arc_Defined || hp.Size_from_Arc == fileSize) + opRes = NArchive::NExtract::NOperationResult::kOK; + } + } + + RINOK(extractCallback->SetOperationResult(opRes)); + } + + return lps->SetCur(); + + COM_TRY_END +} + + +// ---------- UPDATE ---------- + +struct CUpdateItem +{ + int IndexInArc; + unsigned IndexInClient; + UInt64 Size; + bool NewData; + bool NewProps; + bool IsDir; + UString Path; + + CUpdateItem(): Size(0), IsDir(false) {} +}; + + +static HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, + UString &res, + bool convertSlash) +{ + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(index, propId, &prop)); + if (prop.vt == VT_BSTR) + { + res = prop.bstrVal; + if (convertSlash) + NArchive::NItemName::ReplaceSlashes_OsToUnix(res); + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + return S_OK; +} + + +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) +{ + *type = NFileTimeType::kUnix; + return S_OK; +} + + +STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *callback) +{ + COM_TRY_BEGIN + + if (_isArc && !CanUpdate()) + return E_NOTIMPL; + + // const UINT codePage = CP_UTF8; // // (_forceCodePage ? _specifiedCodePage : _openCodePage); + // const unsigned utfFlags = g_Unicode_To_UTF8_Flags; + CObjectVector<CUpdateItem> updateItems; + + UInt64 complexity = 0; + + UInt32 i; + for (i = 0; i < numItems; i++) + { + CUpdateItem ui; + Int32 newData; + Int32 newProps; + UInt32 indexInArc; + + if (!callback) + return E_FAIL; + + RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc)); + + ui.NewProps = IntToBool(newProps); + ui.NewData = IntToBool(newData); + ui.IndexInArc = (int)indexInArc; + ui.IndexInClient = i; + if (IntToBool(newProps)) + { + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidIsDir, &prop)); + if (prop.vt == VT_EMPTY) + ui.IsDir = false; + else if (prop.vt != VT_BOOL) + return E_INVALIDARG; + else + ui.IsDir = (prop.boolVal != VARIANT_FALSE); + } + + RINOK(GetPropString(callback, i, kpidPath, ui.Path, + true)); // convertSlash + /* + if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/') + ui.Name += '/'; + */ + } + + if (IntToBool(newData)) + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidSize, &prop)); + if (prop.vt == VT_UI8) + { + ui.Size = prop.uhVal.QuadPart; + complexity += ui.Size; + } + else if (prop.vt == VT_EMPTY) + ui.Size = (UInt64)(Int64)-1; + else + return E_INVALIDARG; + } + + updateItems.Add(ui); + } + + if (complexity != 0) + { + RINOK(callback->SetTotal(complexity)); + } + + #ifdef EXTERNAL_CODECS + const CExternalCodecs *__externalCodecs = g_ExternalCodecs_Ptr; + #endif + + CHashBundle hb; + UStringVector methods; + if (!_methods.IsEmpty()) + { + FOR_VECTOR(k, _methods) + { + methods.Add(_methods[k]); + } + } + else if (_crcSize_WasSet) + { + AddDefaultMethod(methods, _crcSize); + } + else + { + CMyComPtr<IArchiveGetRootProps> getRootProps; + callback->QueryInterface(IID_IArchiveGetRootProps, (void **)&getRootProps); + + NCOM::CPropVariant prop; + if (getRootProps) + { + RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop)); + if (prop.vt == VT_BSTR) + { + const UString method = GetMethod_from_FileName(prop.bstrVal); + if (!method.IsEmpty()) + methods.Add(method); + } + } + } + + RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods)); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(callback, true); + + const UInt32 kBufSize = 1 << 15; + CHashMidBuf buf; + if (!buf.Alloc(kBufSize)) + return E_OUTOFMEMORY; + + CDynLimBuf hashFileString((size_t)1 << 31); + + CHashOptionsLocal options = _options; + + if (_isArc) + { + if (!options.HashMode_Zero.Def && _is_ZeroMode) + options.HashMode_Zero.Val = true; + if (!options.HashMode_Tag.Def && _are_there_Tags) + options.HashMode_Tag.Val = true; + if (!options.HashMode_Dirs.Def && _are_there_Dirs) + options.HashMode_Dirs.Val = true; + } + if (options.HashMode_OnlyHash.Val && updateItems.Size() != 1) + options.HashMode_OnlyHash.Val = false; + + lps->OutSize = 0; + complexity = 0; + + for (i = 0; i < updateItems.Size(); i++) + { + lps->InSize = complexity; + RINOK(lps->SetCur()); + + const CUpdateItem &ui = updateItems[i]; + + /* + CHashPair item; + if (!ui.NewProps) + item = HashPairs[(unsigned)ui.IndexInArc]; + */ + + if (ui.NewData) + { + UInt64 currentComplexity = ui.Size; + CMyComPtr<ISequentialInStream> fileInStream; + bool needWrite = true; + { + HRESULT res = callback->GetStream(ui.IndexInClient, &fileInStream); + + if (res == S_FALSE) + needWrite = false; + else + { + RINOK(res); + + if (fileInStream) + { + CMyComPtr<IStreamGetProps> getProps; + fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); + if (getProps) + { + FILETIME mTime; + UInt64 size2; + if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK) + { + currentComplexity = size2; + // item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);; + } + } + } + else + { + currentComplexity = 0; + } + } + } + + hb.InitForNewFile(); + const bool isDir = ui.IsDir; + + if (needWrite && fileInStream && !isDir) + { + UInt64 fileSize = 0; + for (UInt32 step = 0;; step++) + { + if ((step & 0xFF) == 0) + { + RINOK(lps->SetRatioInfo(&fileSize, NULL)); + // RINOK(callback->SetCompleted(&completeValue)); + } + UInt32 size; + RINOK(fileInStream->Read(buf, kBufSize, &size)); + if (size == 0) + break; + hb.Update(buf, size); + fileSize += size; + } + currentComplexity = fileSize; + } + + fileInStream.Release(); + const bool isAltStream = false; + hb.Final(isDir, isAltStream, ui.Path); + + if (options.HashMode_Dirs.Val || !isDir) + { + if (!hb.Hashers.IsEmpty()) + lps->OutSize += hb.Hashers[0].DigestSize; + WriteLine(hashFileString, + options, + ui.Path, + isDir, + hb); + if (hashFileString.IsError()) + return E_OUTOFMEMORY; + } + + complexity += currentComplexity; + RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); + } + else + { + // old data + const CHashPair &existItem = HashPairs[(unsigned)ui.IndexInArc]; + if (ui.NewProps) + { + WriteLine(hashFileString, + options, + ui.Path, + ui.IsDir, + existItem.Method, existItem.HashString + ); + } + else + { + hashFileString += existItem.FullLine; + Add_LF(hashFileString, options); + } + } + if (hashFileString.IsError()) + return E_OUTOFMEMORY; + } + + RINOK(WriteStream(outStream, hashFileString, hashFileString.Len())); + + return S_OK; + COM_TRY_END +} + + + +HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) +{ + UString name = nameSpec; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + if (name.IsEqualTo("m")) // "hm" hash method + { + // COneMethodInfo omi; + // RINOK(omi.ParseMethodFromPROPVARIANT(L"", value)); + // _methods.Add(omi.MethodName); // change it. use omi.PropsString + if (value.vt != VT_BSTR) + return E_INVALIDARG; + UString s (value.bstrVal); + _methods.Add(s); + return S_OK; + } + + if (name.IsEqualTo("flags")) + { + if (value.vt != VT_BSTR) + return E_INVALIDARG; + if (!_options.ParseString(value.bstrVal)) + return E_INVALIDARG; + return S_OK; + } + + if (name.IsPrefixedBy_Ascii_NoCase("crc")) + { + name.Delete(0, 3); + _crcSize = 4; + _crcSize_WasSet = true; + return ParsePropToUInt32(name, value, _crcSize); + } + + // common properties + if (name.IsPrefixedBy_Ascii_NoCase("mt") + || name.IsPrefixedBy_Ascii_NoCase("memuse")) + return S_OK; + + return E_INVALIDARG; +} + + +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) +{ + COM_TRY_BEGIN + + InitProps(); + + for (UInt32 i = 0; i < numProps; i++) + { + RINOK(SetProperty(names[i], values[i])); + } + return S_OK; + COM_TRY_END +} + +CHandler::CHandler() +{ + ClearVars(); + InitProps(); +} + +} + + + +static IInArchive *CreateHashHandler_In() { return new NHash::CHandler; } +static IOutArchive *CreateHashHandler_Out() { return new NHash::CHandler; } + +void Codecs_AddHashArcHandler(CCodecs *codecs) +{ + { + CArcInfoEx item; + + item.Name = "Hash"; + item.CreateInArchive = CreateHashHandler_In; + item.CreateOutArchive = CreateHashHandler_Out; + item.IsArcFunc = NULL; + item.Flags = + NArcInfoFlags::kKeepName + | NArcInfoFlags::kStartOpen + | NArcInfoFlags::kByExtOnlyOpen + // | NArcInfoFlags::kPureStartOpen + | NArcInfoFlags::kHashHandler + ; + + // ubuntu uses "SHA256SUMS" file + item.AddExts(UString ( + "sha256 sha512 sha224 sha384 sha1 sha md5" + // "b2sum" + " crc32 crc64" + " asc" + " cksum" + ), + UString()); + + item.UpdateEnabled = (item.CreateOutArchive != NULL); + item.SignatureOffset = 0; + // item.Version = MY_VER_MIX; + item.NewInterface = true; + + item.Signatures.AddNew().CopyFrom(NULL, 0); + + codecs->Formats.Add(item); } } diff --git a/CPP/7zip/UI/Common/HashCalc.h b/CPP/7zip/UI/Common/HashCalc.h index b6d320b5..80a55653 100644 --- a/CPP/7zip/UI/Common/HashCalc.h +++ b/CPP/7zip/UI/Common/HashCalc.h @@ -3,15 +3,17 @@ #ifndef __HASH_CALC_H #define __HASH_CALC_H +#include "../../../Common/UTFConvert.h" #include "../../../Common/Wildcard.h" #include "../../Common/CreateCoder.h" #include "../../Common/MethodProps.h" #include "DirItem.h" +#include "IFileExtractCallback.h" const unsigned k_HashCalc_DigestSize_Max = 64; - +const unsigned k_HashCalc_ExtraSize = 8; const unsigned k_HashCalc_NumGroups = 4; enum @@ -27,9 +29,37 @@ struct CHasherState CMyComPtr<IHasher> Hasher; AString Name; UInt32 DigestSize; - Byte Digests[k_HashCalc_NumGroups][k_HashCalc_DigestSize_Max]; + UInt64 NumSums[k_HashCalc_NumGroups]; + Byte Digests[k_HashCalc_NumGroups][k_HashCalc_DigestSize_Max + k_HashCalc_ExtraSize]; + + void InitDigestGroup(unsigned groupIndex) + { + NumSums[groupIndex] = 0; + memset(Digests[groupIndex], 0, sizeof(Digests[groupIndex])); + } + + const Byte *GetExtraData_for_Group(unsigned groupIndex) const + { + return Digests[groupIndex] + k_HashCalc_DigestSize_Max; + } + + unsigned GetNumExtraBytes_for_Group(unsigned groupIndex) const + { + const Byte *p = GetExtraData_for_Group(groupIndex); + // we use little-endian to read extra bytes + for (unsigned i = k_HashCalc_ExtraSize; i != 0; i--) + if (p[i - 1] != 0) + return i; + return 0; + } + + void AddDigest(unsigned groupIndex, const Byte *data); + + void WriteToString(unsigned digestIndex, char *s) const; }; + + struct IHashCalc { virtual void InitForNewFile() = 0; @@ -89,9 +119,68 @@ struct IHashCallbackUI: public IDirItemsCallback INTERFACE_IHashCallbackUI(=0) }; + +struct CHashOptionsLocal +{ + CBoolPair HashMode_Zero; + CBoolPair HashMode_Tag; + CBoolPair HashMode_Dirs; + CBoolPair HashMode_OnlyHash; + + void Init_HashOptionsLocal() + { + HashMode_Zero.Init(); + HashMode_Tag.Init(); + HashMode_Dirs.Init(); + HashMode_OnlyHash.Init(); + // HashMode_Dirs = true; // for debug + } + + CHashOptionsLocal() + { + Init_HashOptionsLocal(); + } + + bool ParseFlagCharOption(wchar_t c, bool val) + { + c = MyCharLower_Ascii(c); + if (c == 'z') HashMode_Zero.SetVal_as_Defined(val); + else if (c == 't') HashMode_Tag.SetVal_as_Defined(val); + else if (c == 'd') HashMode_Dirs.SetVal_as_Defined(val); + else if (c == 'h') HashMode_OnlyHash.SetVal_as_Defined(val); + else return false; + return true; + } + + bool ParseString(const UString &s) + { + for (unsigned i = 0; i < s.Len();) + { + const wchar_t c = s[i++]; + bool val = true; + if (i < s.Len()) + { + const wchar_t next = s[i]; + if (next == '-') + { + val = false; + i++; + } + } + if (!ParseFlagCharOption(c, val)) + return false; + } + return true; + } +}; + + struct CHashOptions + // : public CHashOptionsLocal { UStringVector Methods; + // UString HashFilePath; + bool PreserveATime; bool OpenShareForWrite; bool StdInMode; @@ -99,7 +188,7 @@ struct CHashOptions CBoolPair SymLinks; NWildcard::ECensorPathMode PathMode; - + CHashOptions(): PreserveATime(false), OpenShareForWrite(false), @@ -108,6 +197,7 @@ struct CHashOptions PathMode(NWildcard::k_RelatPath) {}; }; + HRESULT HashCalc( DECL_EXTERNAL_CODECS_LOC_VARS const NWildcard::CCensor &censor, @@ -115,6 +205,130 @@ HRESULT HashCalc( AString &errorInfo, IHashCallbackUI *callback); -void AddHashHexToString(char *dest, const Byte *data, UInt32 size); + + +#ifndef _SFX + +namespace NHash { + +struct CHashPair +{ + CByteBuffer Hash; + char Mode; + bool IsBSD; + bool Size_from_Arc_Defined; + bool Size_from_Disk_Defined; + AString Method; + AString Name; + + AString FullLine; + AString HashString; + // unsigned HashLengthInBits; + + // AString MethodName; + UInt64 Size_from_Arc; + UInt64 Size_from_Disk; + + bool IsDir() const; + + void Get_UString_Path(UString &path) const + { + path.Empty(); + if (!ConvertUTF8ToUnicode(Name, path)) + return; + } + + bool ParseCksum(const char *s); + bool Parse(const char *s); + + bool IsSupportedMode() const + { + return Mode != 'U' && Mode != '^'; + } + + CHashPair(): + Mode(0) + , IsBSD(false) + , Size_from_Arc_Defined(false) + , Size_from_Disk_Defined(false) + // , HashLengthInBits(0) + , Size_from_Arc(0) + , Size_from_Disk(0) + {} +}; + + +class CHandler: + public IInArchive, + public IArchiveGetRawProps, + // public IGetArchiveHashHandler, + public IOutArchive, + public ISetProperties, + public CMyUnknownImp +{ + bool _isArc; + UInt64 _phySize; + CObjectVector<CHashPair> HashPairs; + UString _nameExtenstion; + // UString _method_fromName; + AString _pgpMethod; + bool _is_CksumMode; + bool _is_PgpMethod; + bool _is_ZeroMode; + bool _are_there_Tags; + bool _are_there_Dirs; + bool _hashSize_Defined; + unsigned _hashSize; + + bool _crcSize_WasSet; + UInt32 _crcSize; + UStringVector _methods; + + void ClearVars(); + + void InitProps() + { + _crcSize_WasSet = false; + _crcSize = 4; + _methods.Clear(); + _options.Init_HashOptionsLocal(); + } + + CHashOptionsLocal _options; + + bool CanUpdate() const + { + if (!_isArc || _is_PgpMethod || _is_CksumMode) + return false; + return true; + + } + + HRESULT SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value); + +public: + + CHandler(); + + MY_UNKNOWN_IMP4( + IInArchive, + IArchiveGetRawProps, + IOutArchive, + ISetProperties + /*, IGetArchiveHashHandler */ + ) + INTERFACE_IInArchive(;) + INTERFACE_IOutArchive(;) + INTERFACE_IArchiveGetRawProps(;) + // STDMETHOD(GetArchiveHashHandler)(CHandler **handler); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); +}; + +} + +void Codecs_AddHashArcHandler(CCodecs *codecs); + +#endif + #endif diff --git a/CPP/7zip/UI/Common/IFileExtractCallback.h b/CPP/7zip/UI/Common/IFileExtractCallback.h index c456c862..e6a85c6d 100644 --- a/CPP/7zip/UI/Common/IFileExtractCallback.h +++ b/CPP/7zip/UI/Common/IFileExtractCallback.h @@ -103,9 +103,9 @@ DECL_INTERFACE_SUB(IGetProp, IUnknown, 0x01, 0x20) STDMETHOD(UseExtractToStream)(Int32 *res) x; \ STDMETHOD(GetStream7)(const wchar_t *name, Int32 isDir, ISequentialOutStream **outStream, Int32 askExtractMode, IGetProp *getProp) x; \ STDMETHOD(PrepareOperation7)(Int32 askExtractMode) x; \ - STDMETHOD(SetOperationResult7)(Int32 resultEOperationResult, Int32 encrypted) x; \ + STDMETHOD(SetOperationResult8)(Int32 resultEOperationResult, Int32 encrypted, UInt64 size) x; \ -DECL_INTERFACE_SUB(IFolderExtractToStreamCallback, IUnknown, 0x01, 0x30) +DECL_INTERFACE_SUB(IFolderExtractToStreamCallback, IUnknown, 0x01, 0x31) { INTERFACE_IFolderExtractToStreamCallback(PURE) }; diff --git a/CPP/7zip/UI/Common/LoadCodecs.cpp b/CPP/7zip/UI/Common/LoadCodecs.cpp index b94720c5..377963aa 100644 --- a/CPP/7zip/UI/Common/LoadCodecs.cpp +++ b/CPP/7zip/UI/Common/LoadCodecs.cpp @@ -53,6 +53,7 @@ using namespace NWindows; #include "../../ICoder.h" #include "../../Common/RegisterArc.h" +#include "../../Common/RegisterCodec.h" #ifdef EXTERNAL_CODECS @@ -193,9 +194,9 @@ void CArcInfoEx::AddExts(const UString &ext, const UString &addExt) static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector<CByteBuffer> &signatures) { signatures.Clear(); - while (size > 0) + while (size != 0) { - unsigned len = *data++; + const unsigned len = *data++; size--; if (len > size) return false; @@ -252,6 +253,25 @@ static HRESULT GetCoderClass(Func_GetMethodProperty getMethodProperty, UInt32 in return S_OK; } + +static HRESULT GetMethodBoolProp(Func_GetMethodProperty getMethodProperty, UInt32 index, + PROPID propId, bool &resVal, bool &isAssigned) +{ + NCOM::CPropVariant prop; + resVal = false; + isAssigned = false; + RINOK(getMethodProperty(index, propId, &prop)); + if (prop.vt == VT_BOOL) + { + isAssigned = true; + resVal = VARIANT_BOOLToBool(prop.boolVal); + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + + #define MY_GET_FUNC(dest, type, func) *(void **)(&dest) = (func); // #define MY_GET_FUNC(dest, type, func) dest = (type)(func); @@ -279,6 +299,7 @@ HRESULT CCodecs::LoadCodecs() info.CodecIndex = i; RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned)); RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned)); + RINOK(GetMethodBoolProp(lib.GetMethodProperty, i, NMethodPropID::kIsFilter, info.IsFilter, info.IsFilter_Assigned)); Codecs.Add(info); } } @@ -647,8 +668,14 @@ HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPath) } if (!found) break; + #ifdef _WIN32 if (fi.IsDir()) continue; + #else + if (enumerator.DirEntry_IsDir(fi, true)) // followLink + continue; + #endif + RINOK(LoadDll(folderPrefix + fi.Name, true)); } return S_OK; @@ -725,7 +752,10 @@ HRESULT CCodecs::Load() if (arc.IsMultiSignature()) ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures); else - item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize); + { + if (arc.SignatureSize != 0) // 21.04 + item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize); + } #endif @@ -776,6 +806,8 @@ HRESULT CCodecs::Load() #endif + // we sort Formats to get fixed order of Formats after compilation. + Formats.Sort(); return S_OK; } @@ -952,6 +984,15 @@ STDMETHODIMP CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *valu prop.Detach(value); return S_OK; } + + if (propID == NMethodPropID::kIsFilter && ci.IsFilter_Assigned) + { + NCOM::CPropVariant prop; + prop = (bool)ci.IsFilter; + prop.Detach(value); + return S_OK; + } + const CCodecLib &lib = Libs[ci.LibIndex]; return lib.GetMethodProperty(ci.CodecIndex, propID, value); #else @@ -1096,6 +1137,7 @@ bool CCodecs::GetCodec_DecoderIsAssigned(UInt32 index) const #endif } + bool CCodecs::GetCodec_EncoderIsAssigned(UInt32 index) const { #ifdef EXPORT_CODECS @@ -1118,6 +1160,38 @@ bool CCodecs::GetCodec_EncoderIsAssigned(UInt32 index) const #endif } + +bool CCodecs::GetCodec_IsFilter(UInt32 index, bool &isAssigned) const +{ + isAssigned = false; + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + { + NCOM::CPropVariant prop; + if (GetProperty(index, NMethodPropID::kIsFilter, &prop) == S_OK) + { + if (prop.vt == VT_BOOL) + { + isAssigned = true; + return VARIANT_BOOLToBool(prop.boolVal); + } + } + return false; + } + #endif + + #ifdef EXTERNAL_CODECS + { + const CDllCodecInfo &c = Codecs[index - NUM_EXPORT_CODECS]; + isAssigned = c.IsFilter_Assigned; + return c.IsFilter; + } + #else + return false; + #endif +} + + UInt32 CCodecs::GetCodec_NumStreams(UInt32 index) { NCOM::CPropVariant prop; @@ -1203,3 +1277,45 @@ void CCodecs::GetCodecsErrorMessage(UString &s) } #endif // EXTERNAL_CODECS + +#ifndef _SFX + +extern unsigned g_NumCodecs; +extern const CCodecInfo *g_Codecs[]; + +void CCodecs::Get_CodecsInfoUser_Vector(CObjectVector<CCodecInfoUser> &v) +{ + v.Clear(); + { + for (unsigned i = 0; i < g_NumCodecs; i++) + { + const CCodecInfo &cod = *g_Codecs[i]; + CCodecInfoUser &u = v.AddNew(); + u.EncoderIsAssigned = (cod.CreateEncoder != NULL); + u.DecoderIsAssigned = (cod.CreateDecoder != NULL); + u.IsFilter_Assigned = true; + u.IsFilter = cod.IsFilter; + u.NumStreams = cod.NumStreams; + u.Name = cod.Name; + } + } + + + #ifdef EXTERNAL_CODECS + { + UInt32 numMethods; + if (GetNumMethods(&numMethods) == S_OK) + for (UInt32 j = 0; j < numMethods; j++) + { + CCodecInfoUser &u = v.AddNew(); + u.EncoderIsAssigned = GetCodec_EncoderIsAssigned(j); + u.DecoderIsAssigned = GetCodec_DecoderIsAssigned(j); + u.IsFilter = GetCodec_IsFilter(j, u.IsFilter_Assigned); + u.NumStreams = GetCodec_NumStreams(j); + u.Name = GetCodec_Name(j); + } + } + #endif +} + +#endif diff --git a/CPP/7zip/UI/Common/LoadCodecs.h b/CPP/7zip/UI/Common/LoadCodecs.h index 660ddee4..829472d0 100644 --- a/CPP/7zip/UI/Common/LoadCodecs.h +++ b/CPP/7zip/UI/Common/LoadCodecs.h @@ -68,6 +68,8 @@ struct CDllCodecInfo UInt32 CodecIndex; bool EncoderIsAssigned; bool DecoderIsAssigned; + bool IsFilter; + bool IsFilter_Assigned; CLSID Encoder; CLSID Decoder; }; @@ -119,6 +121,23 @@ struct CArcInfoEx CLSID ClassID; #endif + int Compare(const CArcInfoEx &a) const + { + int res = Name.Compare(a.Name); + if (res != 0) + return res; + #ifdef EXTERNAL_CODECS + return MyCompare(LibIndex, a.LibIndex); + #else + return 0; + #endif + /* + if (LibIndex < a.LibIndex) return -1; + if (LibIndex > a.LibIndex) return 1; + return 0; + */ + } + bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; } bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; } @@ -133,6 +152,7 @@ struct CArcInfoEx bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; } bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; } bool Flags_ByExtOnlyOpen() const { return (Flags & NArcInfoFlags::kByExtOnlyOpen) != 0; } + bool Flags_HashHandler() const { return (Flags & NArcInfoFlags::kHashHandler) != 0; } UString GetMainExt() const { @@ -236,6 +256,21 @@ struct CCodecError CCodecError(): ErrorCode(0) {} }; + +struct CCodecInfoUser +{ + // unsigned LibIndex; + // UInt32 CodecIndex; + // UInt64 id; + bool EncoderIsAssigned; + bool DecoderIsAssigned; + bool IsFilter; + bool IsFilter_Assigned; + UInt32 NumStreams; + AString Name; +}; + + class CCodecs: #ifdef EXTERNAL_CODECS public ICompressCodecsInfo, @@ -353,6 +388,7 @@ public: int GetCodec_LibIndex(UInt32 index) const; bool GetCodec_DecoderIsAssigned(UInt32 index) const; bool GetCodec_EncoderIsAssigned(UInt32 index) const; + bool GetCodec_IsFilter(UInt32 index, bool &isAssigned) const; UInt32 GetCodec_NumStreams(UInt32 index); HRESULT GetCodec_Id(UInt32 index, UInt64 &id); AString GetCodec_Name(UInt32 index); @@ -416,6 +452,8 @@ public: return -1; } + void Get_CodecsInfoUser_Vector(CObjectVector<CCodecInfoUser> &v); + #endif // _SFX }; @@ -432,5 +470,5 @@ public: CCodecs *codecs = new CCodecs; \ CMyComPtr<IUnknown> __codecsRef = codecs; #endif - + #endif diff --git a/CPP/7zip/UI/Common/OpenArchive.cpp b/CPP/7zip/UI/Common/OpenArchive.cpp index 7bec9d53..331793f1 100644 --- a/CPP/7zip/UI/Common/OpenArchive.cpp +++ b/CPP/7zip/UI/Common/OpenArchive.cpp @@ -1026,30 +1026,33 @@ static void MakeCheckOrder(CCodecs *codecs, { for (unsigned i = 0; i < numTypes; i++) { - int index = orderIndices[i]; + const int index = orderIndices[i]; if (index < 0) continue; const CArcInfoEx &ai = codecs->Formats[(unsigned)index]; - if (ai.SignatureOffset != 0) + if (ai.SignatureOffset == 0) { - orderIndices2.Add(index); - orderIndices[i] = -1; - continue; - } - - const CObjectVector<CByteBuffer> &sigs = ai.Signatures; - FOR_VECTOR (k, sigs) - { - const CByteBuffer &sig = sigs[k]; - if ((sig.Size() == 0 && dataSize == 0) - || (sig.Size() != 0 && sig.Size() <= dataSize - && TestSignature(data, sig, sig.Size()))) + if (ai.Signatures.IsEmpty()) { - orderIndices2.Add(index); - orderIndices[i] = -1; - break; + if (dataSize != 0) // 21.04: no Sinature means Empty Signature + continue; + } + else + { + unsigned k; + const CObjectVector<CByteBuffer> &sigs = ai.Signatures; + for (k = 0; k < sigs.Size(); k++) + { + const CByteBuffer &sig = sigs[k]; + if (sig.Size() <= dataSize && TestSignature(data, sig, sig.Size())) + break; + } + if (k == sigs.Size()) + continue; } } + orderIndices2.Add(index); + orderIndices[i] = -1; } } @@ -2143,7 +2146,7 @@ HRESULT CArc::OpenStream2(const COpenOptions &op) continue; } - bool isNewStyleSignature = IsNewStyleSignature(ai); + const bool isNewStyleSignature = IsNewStyleSignature(ai); bool needCheck = !isNewStyleSignature || ai.Signatures.IsEmpty() || ai.Flags_PureStartOpen() @@ -2156,13 +2159,12 @@ HRESULT CArc::OpenStream2(const COpenOptions &op) for (k = 0; k < ai.Signatures.Size(); k++) { const CByteBuffer &sig = ai.Signatures[k]; - UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size(); - if (processedSize < signatureEnd) + if (processedSize < ai.SignatureOffset + sig.Size()) { if (!endOfFile) needCheck = true; } - else if (memcmp(sig, byteBuffer + ai.SignatureOffset, sig.Size()) == 0) + else if (TestSignature(sig, byteBuffer + ai.SignatureOffset, sig.Size())) break; } if (k != ai.Signatures.Size()) @@ -3390,7 +3392,7 @@ HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI) return S_OK; } -HRESULT CArc::ReOpen(const COpenOptions &op) +HRESULT CArc::ReOpen(const COpenOptions &op, IArchiveOpenCallback *openCallback_Additional) { ErrorInfo.ClearErrors(); ErrorInfo.ErrorFormatIndex = -1; @@ -3420,7 +3422,10 @@ HRESULT CArc::ReOpen(const COpenOptions &op) // There are archives with embedded STUBs (like ZIP), so we must support signature scanning // But for another archives we can use 0 here. So the code can be fixed !!! UInt64 maxStartPosition = kMaxCheckStartPosition; - HRESULT res = Archive->Open(stream2, &maxStartPosition, op.callback); + IArchiveOpenCallback *openCallback = openCallback_Additional; + if (!openCallback) + openCallback = op.callback; + HRESULT res = Archive->Open(stream2, &maxStartPosition, openCallback); if (res == S_OK) { @@ -3476,7 +3481,7 @@ HRESULT CArchiveLink::ReOpen(COpenOptions &op) op.stream = stream; CArc &arc = Arcs[0]; - HRESULT res = arc.ReOpen(op); + HRESULT res = arc.ReOpen(op, openCallbackNew); PasswordWasAsked = openCallbackSpec->PasswordWasAsked; // Password = openCallbackSpec->Password; @@ -3579,6 +3584,12 @@ static bool ParseType(CCodecs &codecs, const UString &s, COpenType &type) type.CanReturnArc = false; type.CanReturnParser = true; } + else if (name.IsEqualTo_Ascii_NoCase("hash")) + { + // type.CanReturnArc = false; + // type.CanReturnParser = false; + type.IsHashType = true; + } else return false; } @@ -3606,6 +3617,7 @@ static bool ParseType(CCodecs &codecs, const UString &s, COpenType &type) bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types) { types.Clear(); + bool isHashType = false; for (unsigned pos = 0; pos < s.Len();) { int pos2 = s.Find(L'.', pos); @@ -3617,10 +3629,24 @@ bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> COpenType type; if (!ParseType(codecs, name, type)) return false; + if (isHashType) + return false; + if (type.IsHashType) + isHashType = true; types.Add(type); pos = (unsigned)pos2 + 1; } return true; } +/* +bool IsHashType(const CObjectVector<COpenType> &types) +{ + if (types.Size() != 1) + return false; + return types[0].IsHashType; +} +*/ + + #endif diff --git a/CPP/7zip/UI/Common/OpenArchive.h b/CPP/7zip/UI/Common/OpenArchive.h index ebeb91d1..4e1192cf 100644 --- a/CPP/7zip/UI/Common/OpenArchive.h +++ b/CPP/7zip/UI/Common/OpenArchive.h @@ -70,6 +70,7 @@ struct COpenType bool CanReturnArc; bool CanReturnParser; + bool IsHashType; bool EachPos; // bool SkipSfxStub; @@ -90,6 +91,7 @@ struct COpenType Recursive(true), CanReturnArc(true), CanReturnParser(false), + IsHashType(false), EachPos(false), // SkipSfxStub(true), // ExeAsUnknown(true), @@ -285,7 +287,7 @@ public: UString Path; UString filePath; UString DefaultName; - int FormatIndex; // - 1 means Parser. + int FormatIndex; // -1 means Parser UInt32 SubfileIndex; // (UInt32)(Int32)-1; means no subfile FILETIME MTime; bool MTimeDefined; @@ -358,9 +360,16 @@ public: HRESULT OpenStream(const COpenOptions &options); HRESULT OpenStreamOrFile(COpenOptions &options); - HRESULT ReOpen(const COpenOptions &options); + HRESULT ReOpen(const COpenOptions &options, IArchiveOpenCallback *openCallback_Additional); HRESULT CreateNewTailStream(CMyComPtr<IInStream> &stream); + + bool IsHashHandler(const COpenOptions &options) const + { + if (FormatIndex < 0) + return false; + return options.codecs->Formats[(unsigned)FormatIndex].Flags_HashHandler(); + } }; struct CArchiveLink @@ -421,6 +430,8 @@ struct CArchiveLink bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types); +// bool IsHashType(const CObjectVector<COpenType> &types); + struct CDirPathSortPair { diff --git a/CPP/7zip/UI/Common/Update.cpp b/CPP/7zip/UI/Common/Update.cpp index fc922a70..4bd690d6 100644 --- a/CPP/7zip/UI/Common/Update.cpp +++ b/CPP/7zip/UI/Common/Update.cpp @@ -542,9 +542,9 @@ static HRESULT Compress( #endif } - if (outArchive == 0) + if (!outArchive) throw kUpdateIsNotSupoorted; - + NFileTimeType::EEnum fileTimeType; { UInt32 value; @@ -568,6 +568,8 @@ static HRESULT Compress( return E_NOTIMPL; if (options.NtSecurity.Val && !arcInfo.Flags_NtSecure()) return E_NOTIMPL; + if (options.DeleteAfterCompressing && arcInfo.Flags_HashHandler()) + return E_NOTIMPL; } CRecordVector<CUpdatePair2> updatePairs2; @@ -745,6 +747,11 @@ static HRESULT Compress( updateCallbackSpec->ProcessedItemsStatuses = processedItemsStatuses; + { + const UString arcPath = archivePath.GetFinalPath(); + updateCallbackSpec->ArcFileName = ExtractFileNameFromPath(arcPath); + } + if (options.RenamePairs.Size() != 0) updateCallbackSpec->NewNames = &newNames; @@ -907,7 +914,7 @@ static HRESULT Compress( ft.dwHighDateTime = 0; FOR_VECTOR (i, updatePairs2) { - CUpdatePair2 &pair2 = updatePairs2[i]; + const CUpdatePair2 &pair2 = updatePairs2[i]; const FILETIME *ft2 = NULL; if (pair2.NewProps && pair2.DirIndex >= 0) ft2 = &dirItems.Items[(unsigned)pair2.DirIndex].MTime; @@ -945,9 +952,28 @@ static HRESULT Compress( result = outStreamSpec->Close(); else if (volStreamSpec) result = volStreamSpec->Close(); + + RINOK(result) + + if (processedItemsStatuses) + { + FOR_VECTOR (i, updatePairs2) + { + const CUpdatePair2 &up = updatePairs2[i]; + if (up.NewData && up.DirIndex >= 0) + { + const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex]; + if (di.AreReparseData() || (!di.IsDir() && di.Size == 0)) + processedItemsStatuses[(unsigned)up.DirIndex] = 1; + } + } + } + return result; } + + bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); static bool Censor_CheckPath(const NWildcard::CCensor &censor, const CReadArcItem &item) @@ -1288,6 +1314,8 @@ HRESULT UpdateArchive( #endif dirItems.ScanAltStreams = options.AltStreams.Val; + dirItems.ExcludeDirItems = censor.ExcludeDirItems; + dirItems.ExcludeFileItems = censor.ExcludeFileItems; HRESULT res = EnumerateItems(censor, options.PathMode, @@ -1440,7 +1468,7 @@ HRESULT UpdateArchive( CByteBuffer processedItems; if (options.DeleteAfterCompressing) { - unsigned num = dirItems.Items.Size(); + const unsigned num = dirItems.Items.Size(); processedItems.Alloc(num); for (unsigned i = 0; i < num; i++) processedItems[i] = 0; @@ -1654,17 +1682,27 @@ HRESULT UpdateArchive( } else { - if (processedItems[i] != 0 || dirItem.Size == 0) + // 21.04: we have set processedItems[*] before for all required items + if (processedItems[i] != 0 + // || dirItem.Size == 0 + // || dirItem.AreReparseData() + ) { NFind::CFileInfo fileInfo; - /* here we compare Raw FileInfo that can be link with actual file info that was processed. - we can fix it. */ - if (fileInfo.Find(phyPath)) + /* if (!SymLinks), we follow link here, similar to (dirItem) filling */ + if (fileInfo.Find(phyPath, !options.SymLinks.Val)) { - // FIXME: here we can check Find_FollowLink() also; + bool is_SameSize = false; + if (options.SymLinks.Val && dirItem.AreReparseData()) + { + /* (dirItem.Size = dirItem.ReparseData.Size()) was set before. + So we don't compare sizes for that case here */ + is_SameSize = fileInfo.IsOsSymLink(); + } + else + is_SameSize = (fileInfo.Size == dirItem.Size); - // maybe we must exclude also files with archive name: "a a.7z * -sdel" - if (fileInfo.Size == dirItem.Size + if (is_SameSize && CompareFileTime(&fileInfo.MTime, &dirItem.MTime) == 0 && CompareFileTime(&fileInfo.CTime, &dirItem.CTime) == 0) { @@ -1675,11 +1713,11 @@ HRESULT UpdateArchive( } else { - // file was skipped + // file was skipped by some reason. We can throw error for debug: /* errorInfo.SystemError = 0; errorInfo.Message = "file was not processed"; - errorInfo.FileName = phyPath; + errorInfo.FileNames.Add(phyPath); return E_FAIL; */ } diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp index 69cde093..7b705ba3 100644 --- a/CPP/7zip/UI/Common/UpdateCallback.cpp +++ b/CPP/7zip/UI/Common/UpdateCallback.cpp @@ -144,6 +144,7 @@ STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *val case kpidCTime: if (ParentDirItem) prop = ParentDirItem->CTime; break; case kpidATime: if (ParentDirItem) prop = ParentDirItem->ATime; break; case kpidMTime: if (ParentDirItem) prop = ParentDirItem->MTime; break; + case kpidArcFileName: if (!ArcFileName.IsEmpty()) prop = ArcFileName; break; } prop.Detach(value); return S_OK; @@ -475,6 +476,17 @@ STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR static NSynchronization::CCriticalSection CS; #endif +void CArchiveUpdateCallback::UpdateProcessedItemStatus(unsigned dirIndex) +{ + if (ProcessedItemsStatuses) + { + #ifndef _7ZIP_ST + NSynchronization::CCriticalSectionLock lock(CS); + #endif + ProcessedItemsStatuses[dirIndex] = 1; + } +} + STDMETHODIMP CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode) { COM_TRY_BEGIN @@ -544,6 +556,8 @@ STDMETHODIMP CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStrea CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec; inStreamSpec->Init(di.ReparseData, di.ReparseData.Size()); *inStream = inStreamLoc.Detach(); + + UpdateProcessedItemStatus((unsigned)up.DirIndex); return S_OK; } #endif // !defined(UNDER_CE) @@ -600,13 +614,7 @@ STDMETHODIMP CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStrea } // #endif - if (ProcessedItemsStatuses) - { - #ifndef _7ZIP_ST - NSynchronization::CCriticalSectionLock lock(CS); - #endif - ProcessedItemsStatuses[(unsigned)up.DirIndex] = 1; - } + UpdateProcessedItemStatus((unsigned)up.DirIndex); *inStream = inStreamLoc.Detach(); } @@ -649,7 +657,7 @@ STDMETHODIMP CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 in isDir = DirItems->Items[(unsigned)up.DirIndex].IsDir(); } } - return Callback->ReportUpdateOpeartion(op, name.IsEmpty() ? NULL : name.Ptr(), isDir); + return Callback->ReportUpdateOperation(op, name.IsEmpty() ? NULL : name.Ptr(), isDir); } wchar_t temp[16]; @@ -684,7 +692,7 @@ STDMETHODIMP CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 in if (!s) s = L""; - return Callback->ReportUpdateOpeartion(op, s, isDir); + return Callback->ReportUpdateOperation(op, s, isDir); COM_TRY_END } diff --git a/CPP/7zip/UI/Common/UpdateCallback.h b/CPP/7zip/UI/Common/UpdateCallback.h index 3fe0a647..d27776ef 100644 --- a/CPP/7zip/UI/Common/UpdateCallback.h +++ b/CPP/7zip/UI/Common/UpdateCallback.h @@ -40,7 +40,7 @@ struct CArcToDoStat virtual HRESULT ReadingFileError(const FString &path, DWORD systemError) x; \ virtual HRESULT SetOperationResult(Int32 opRes) x; \ virtual HRESULT ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) x; \ - virtual HRESULT ReportUpdateOpeartion(UInt32 op, const wchar_t *name, bool isDir) x; \ + virtual HRESULT ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) x; \ /* virtual HRESULT SetPassword(const UString &password) x; */ \ virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \ virtual HRESULT CryptoGetTextPassword(BSTR *password) x; \ @@ -87,6 +87,8 @@ class CArchiveUpdateCallback: UInt32 _hardIndex_From; UInt32 _hardIndex_To; + void UpdateProcessedItemStatus(unsigned dirIndex); + public: MY_QUERYINTERFACE_BEGIN2(IArchiveUpdateCallback2) MY_QUERYINTERFACE_ENTRY(IArchiveUpdateCallbackFile) @@ -121,6 +123,7 @@ public: CRecordVector<UInt64> VolumesSizes; FString VolName; FString VolExt; + UString ArcFileName; // without path prefix IUpdateCallbackUI *Callback; @@ -147,7 +150,6 @@ public: Byte *ProcessedItemsStatuses; - CArchiveUpdateCallback(); bool IsDir(const CUpdatePair2 &up) const diff --git a/CPP/7zip/UI/Console/Console.dsp b/CPP/7zip/UI/Console/Console.dsp index 53ec5525..f6a32547 100644 --- a/CPP/7zip/UI/Console/Console.dsp +++ b/CPP/7zip/UI/Console/Console.dsp @@ -405,6 +405,14 @@ SOURCE=..\..\..\Common\Defs.h # End Source File # Begin Source File +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + SOURCE=..\..\..\Common\IntToString.cpp # End Source File # Begin Source File @@ -886,6 +894,14 @@ SOURCE=..\..\..\..\C\Threads.h # PROP Default_Filter "" # Begin Source File +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp # End Source File # Begin Source File diff --git a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp index 23eab615..24c21e8d 100644 --- a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp @@ -187,6 +187,7 @@ static NSynchronization::CCriticalSection g_CriticalSection; static const char * const kTestString = "T"; static const char * const kExtractString = "-"; static const char * const kSkipString = "."; +static const char * const kReadString = "H"; // static const char * const kCantAutoRename = "cannot create file with auto name\n"; // static const char * const kCantRenameFile = "cannot rename existing file\n"; @@ -317,7 +318,7 @@ STDMETHODIMP CExtractCallbackConsole::AskOverwrite( return CheckBreak2(); } -STDMETHODIMP CExtractCallbackConsole::PrepareOperation(const wchar_t *name, Int32 /* isFolder */, Int32 askExtractMode, const UInt64 *position) +STDMETHODIMP CExtractCallbackConsole::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position) { MT_LOCK @@ -331,6 +332,7 @@ STDMETHODIMP CExtractCallbackConsole::PrepareOperation(const wchar_t *name, Int3 case NArchive::NExtract::NAskMode::kExtract: s = kExtractString; break; case NArchive::NExtract::NAskMode::kTest: s = kTestString; break; case NArchive::NExtract::NAskMode::kSkip: s = kSkipString; requiredLevel = 2; break; + case NArchive::NExtract::NAskMode::kReadExternal: s = kReadString; requiredLevel = 0; break; default: s = "???"; requiredLevel = 2; }; @@ -350,6 +352,12 @@ STDMETHODIMP CExtractCallbackConsole::PrepareOperation(const wchar_t *name, Int3 { _tempU = name; _so->Normalize_UString(_tempU); + // 21.04 + if (isFolder) + { + if (!_tempU.IsEmpty() && _tempU.Back() != WCHAR_PATH_SEPARATOR) + _tempU.Add_PathSepar(); + } } _so->PrintUString(_tempU, _tempA); if (position) diff --git a/CPP/7zip/UI/Console/HashCon.cpp b/CPP/7zip/UI/Console/HashCon.cpp index a70f5f8a..1bd75c15 100644 --- a/CPP/7zip/UI/Console/HashCon.cpp +++ b/CPP/7zip/UI/Console/HashCon.cpp @@ -4,6 +4,8 @@ #include "../../../Common/IntToString.h" +#include "../../../Windows/FileName.h" + #include "ConsoleClose.h" #include "HashCon.h" @@ -33,13 +35,15 @@ HRESULT CHashCallbackConsole::StartScanning() return CheckBreak2(); } -HRESULT CHashCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */) +HRESULT CHashCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) { if (NeedPercents()) { _percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams; _percent.Completed = st.GetTotalBytes(); _percent.FileName = fs2us(path); + if (isDir) + NWindows::NFile::NName::NormalizeDirPathPrefix(_percent.FileName); _percent.Print(); } return CheckBreak2(); @@ -111,6 +115,15 @@ static void SetSpacesAndNul(char *s, unsigned num) s[num] = 0; } +static void SetSpacesAndNul_if_Positive(char *s, int num) +{ + if (num < 0) + return; + for (int i = 0; i < num; i++) + s[i] = ' '; + s[num] = 0; +} + static const unsigned kSizeField_Len = 13; static const unsigned kNameField_Len = 12; @@ -122,61 +135,83 @@ static unsigned GetColumnWidth(unsigned digestSize) return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width; } -void CHashCallbackConsole::PrintSeparatorLine(const CObjectVector<CHasherState> &hashers) + +AString CHashCallbackConsole::GetFields() const { - _s.Empty(); - - for (unsigned i = 0; i < hashers.Size(); i++) - { - if (i != 0) - _s.Add_Space(); - const CHasherState &h = hashers[i]; - AddMinuses(_s, GetColumnWidth(h.DigestSize)); - } + AString s = PrintFields; + if (s.IsEmpty()) + s = "hsn"; + s.MakeLower_Ascii(); + return s; +} - if (PrintSize) - { - _s.Add_Space(); - AddMinuses(_s, kSizeField_Len); - } - if (PrintName) +void CHashCallbackConsole::PrintSeparatorLine(const CObjectVector<CHasherState> &hashers) +{ + _s.Empty(); + const AString fields = GetFields(); + for (unsigned pos = 0; pos < fields.Len(); pos++) { - AddSpacesBeforeName(); - AddMinuses(_s, kNameField_Len); + const char c = fields[pos]; + if (c == 'h') + { + for (unsigned i = 0; i < hashers.Size(); i++) + { + AddSpace(); + const CHasherState &h = hashers[i]; + AddMinuses(_s, GetColumnWidth(h.DigestSize)); + } + } + else if (c == 's') + { + AddSpace(); + AddMinuses(_s, kSizeField_Len); + } + else if (c == 'n') + { + AddSpacesBeforeName(); + AddMinuses(_s, kNameField_Len); + } } *_so << _s << endl; } + HRESULT CHashCallbackConsole::BeforeFirstFile(const CHashBundle &hb) { if (PrintHeaders && _so) { _s.Empty(); ClosePercents_for_so(); - - FOR_VECTOR (i, hb.Hashers) - { - if (i != 0) - _s.Add_Space(); - const CHasherState &h = hb.Hashers[i]; - _s += h.Name; - AddSpaces_if_Positive(_s, (int)GetColumnWidth(h.DigestSize) - (int)h.Name.Len()); - } - - if (PrintSize) - { - _s.Add_Space(); - const AString s2 ("Size"); - AddSpaces_if_Positive(_s, (int)kSizeField_Len - (int)s2.Len()); - _s += s2; - } - - if (PrintName) + + const AString fields = GetFields(); + for (unsigned pos = 0; pos < fields.Len(); pos++) { - AddSpacesBeforeName(); - _s += "Name"; + const char c = fields[pos]; + if (c == 'h') + { + FOR_VECTOR (i, hb.Hashers) + { + AddSpace(); + const CHasherState &h = hb.Hashers[i]; + _s += h.Name; + AddSpaces_if_Positive(_s, (int)GetColumnWidth(h.DigestSize) - (int)h.Name.Len()); + } + } + + else if (c == 's') + { + AddSpace(); + const AString s2 ("Size"); + AddSpaces_if_Positive(_s, (int)kSizeField_Len - (int)s2.Len()); + _s += s2; + } + else if (c == 'n') + { + AddSpacesBeforeName(); + _s += "Name"; + } } *_so << _s << endl; @@ -191,9 +226,11 @@ HRESULT CHashCallbackConsole::OpenFileError(const FString &path, DWORD systemErr return OpenFileError_Base(path, systemError); } -HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool /* isFolder */) +HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool isDir) { _fileName = name; + if (isDir) + NWindows::NFile::NName::NormalizeDirPathPrefix(_fileName); if (NeedPercents()) { @@ -208,57 +245,81 @@ HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool /* isFolder */ return CheckBreak2(); } + +static const unsigned k_DigestStringSize = k_HashCalc_DigestSize_Max * 2 + k_HashCalc_ExtraSize * 2 + 16; + + + void CHashCallbackConsole::PrintResultLine(UInt64 fileSize, - const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash) + const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash, + const AString &path) { ClosePercents_for_so(); _s.Empty(); - - FOR_VECTOR (i, hashers) - { - const CHasherState &h = hashers[i]; - char s[k_HashCalc_DigestSize_Max * 2 + 64]; - s[0] = 0; - if (showHash) - AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize); - const unsigned pos = (unsigned)strlen(s); - SetSpacesAndNul(s + pos, GetColumnWidth(h.DigestSize) - pos); - if (i != 0) - _s.Add_Space(); - _s += s; - } + const AString fields = GetFields(); - if (PrintSize) + for (unsigned pos = 0; pos < fields.Len(); pos++) { - _s.Add_Space(); - - char s[kSizeField_Len + 32]; - char *p = s; - - SetSpacesAndNul(s, kSizeField_Len); - if (showHash) + const char c = fields[pos]; + if (c == 'h') { - p = s + kSizeField_Len; - ConvertUInt64ToString(fileSize, p); - int numSpaces = (int)kSizeField_Len - (int)strlen(p); - if (numSpaces > 0) - p -= (unsigned)numSpaces; + FOR_VECTOR (i, hashers) + { + AddSpace(); + const CHasherState &h = hashers[i]; + char s[k_DigestStringSize]; + s[0] = 0; + if (showHash) + h.WriteToString(digestIndex, s); + const unsigned len = (unsigned)strlen(s); + SetSpacesAndNul_if_Positive(s + len, (int)GetColumnWidth(h.DigestSize) - (int)len); + _s += s; + } + } + else if (c == 's') + { + AddSpace(); + char s[kSizeField_Len + 32]; + char *p = s; + SetSpacesAndNul(s, kSizeField_Len); + if (showHash) + { + p = s + kSizeField_Len; + ConvertUInt64ToString(fileSize, p); + const int numSpaces = (int)kSizeField_Len - (int)strlen(p); + if (numSpaces > 0) + p -= (unsigned)numSpaces; + } + _s += p; + } + else if (c == 'n') + { + AddSpacesBeforeName(); + _s += path; } - - _s += p; } - - if (PrintName) - AddSpacesBeforeName(); *_so << _s; } + HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) { if (_so) { + AString s; + if (_fileName.IsEmpty()) + s = kEmptyFileAlias; + else + { + UString temp = _fileName; + _so->Normalize_UString(temp); + _so->Convert_UString_to_AString(temp, s); + } + PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash, s); + + /* PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash); if (PrintName) { @@ -267,7 +328,9 @@ HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBun else _so->NormalizePrint_UString(_fileName); } - *_so << endl; + */ + // if (PrintNewLine) + *_so << endl; } if (NeedPercents()) @@ -299,9 +362,9 @@ static void PrintSum(CStdOutStream &so, const CHasherState &h, unsigned digestIn so << k_DigestTitles[digestIndex]; - char s[k_HashCalc_DigestSize_Max * 2 + 64]; - s[0] = 0; - AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize); + char s[k_DigestStringSize]; + // s[0] = 0; + h.WriteToString(digestIndex, s); so << s << endl; } @@ -336,7 +399,7 @@ HRESULT CHashCallbackConsole::AfterLastFile(CHashBundle &hb) { PrintSeparatorLine(hb.Hashers); - PrintResultLine(hb.FilesSize, hb.Hashers, k_HashCalc_Index_DataSum, true); + PrintResultLine(hb.FilesSize, hb.Hashers, k_HashCalc_Index_DataSum, true, AString()); *_so << endl << endl; diff --git a/CPP/7zip/UI/Console/HashCon.h b/CPP/7zip/UI/Console/HashCon.h index 0731bd18..f926d4d3 100644 --- a/CPP/7zip/UI/Console/HashCon.h +++ b/CPP/7zip/UI/Console/HashCon.h @@ -12,15 +12,23 @@ class CHashCallbackConsole: public IHashCallbackUI, public CCallbackConsoleBase UString _fileName; AString _s; + void AddSpace() + { + _s.Add_Space_if_NotEmpty(); + } + void AddSpacesBeforeName() { - _s.Add_Space(); - _s.Add_Space(); + if (!_s.IsEmpty()) + { + _s.Add_Space(); + _s.Add_Space(); + } } void PrintSeparatorLine(const CObjectVector<CHasherState> &hashers); void PrintResultLine(UInt64 fileSize, - const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash); + const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash, const AString &path); void PrintProperty(const char *name, UInt64 value); public: @@ -28,14 +36,17 @@ public: bool PrintHeaders; - bool PrintSize; - bool PrintName; + // bool PrintSize; + // bool PrintNewLine; // set it too (false), if you need only hash for single file without LF char. + AString PrintFields; + + AString GetFields() const; CHashCallbackConsole(): PrintNameInPercents(true), - PrintHeaders(false), - PrintSize(true), - PrintName(true) + PrintHeaders(false) + // , PrintSize(true), + // , PrintNewLine(true) {} virtual ~CHashCallbackConsole() {} diff --git a/CPP/7zip/UI/Console/List.cpp b/CPP/7zip/UI/Console/List.cpp index d6cb9825..14d83eb9 100644 --- a/CPP/7zip/UI/Console/List.cpp +++ b/CPP/7zip/UI/Console/List.cpp @@ -505,7 +505,7 @@ static void PrintTime(char *dest, const FILETIME *ft) static inline char GetHex(Byte value) { - return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); + return (char)((value < 10) ? ('0' + value) : ('a' + (value - 10))); } static void HexToString(char *dest, const Byte *data, UInt32 size) @@ -1019,7 +1019,9 @@ HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item); -HRESULT ListArchives(CCodecs *codecs, +HRESULT ListArchives( + const CListOptions &listOptions, + CCodecs *codecs, const CObjectVector<COpenType> &types, const CIntVector &excludedFormats, bool stdInMode, @@ -1271,6 +1273,9 @@ HRESULT ListArchives(CCodecs *codecs, RINOK(Archive_IsItem_Dir(archive, i, fp.IsDir)); + if (fp.IsDir ? listOptions.ExcludeDirItems : listOptions.ExcludeFileItems) + continue; + if (!allFilesAreAllowed) { if (isAltStream) diff --git a/CPP/7zip/UI/Console/List.h b/CPP/7zip/UI/Console/List.h index 462c4710..79d2ed48 100644 --- a/CPP/7zip/UI/Console/List.h +++ b/CPP/7zip/UI/Console/List.h @@ -7,7 +7,20 @@ #include "../Common/LoadCodecs.h" -HRESULT ListArchives(CCodecs *codecs, +struct CListOptions +{ + bool ExcludeDirItems; + bool ExcludeFileItems; + + CListOptions(): + ExcludeDirItems(false), + ExcludeFileItems(false) + {} +}; + +HRESULT ListArchives( + const CListOptions &listOptions, + CCodecs *codecs, const CObjectVector<COpenType> &types, const CIntVector &excludedFormats, bool stdInMode, @@ -15,12 +28,12 @@ HRESULT ListArchives(CCodecs *codecs, bool processAltStreams, bool showAltStreams, const NWildcard::CCensorNode &wildcardCensor, bool enableHeaders, bool techMode, - #ifndef _NO_CRYPTO + #ifndef _NO_CRYPTO bool &passwordEnabled, UString &password, - #endif - #ifndef _SFX + #endif + #ifndef _SFX const CObjectVector<CProperty> *props, - #endif + #endif UInt64 &errors, UInt64 &numWarnings); diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp index e7d9fd1b..0455ed5d 100644 --- a/CPP/7zip/UI/Console/Main.cpp +++ b/CPP/7zip/UI/Console/Main.cpp @@ -71,6 +71,9 @@ extern const CCodecInfo *g_Codecs[]; extern unsigned g_NumHashers; extern const CHasherInfo *g_Hashers[]; +#ifdef EXTERNAL_CODECS +const CExternalCodecs *g_ExternalCodecs_Ptr; +#endif #if defined(PROG_VARIANT_Z) #define PROG_POSTFIX "z" @@ -859,9 +862,11 @@ int Main2( codecs->CaseSensitiveChange = options.CaseSensitiveChange; codecs->CaseSensitive = options.CaseSensitive; ThrowException_if_Error(codecs->Load()); + Codecs_AddHashArcHandler(codecs); #ifdef EXTERNAL_CODECS { + g_ExternalCodecs_Ptr = &__externalCodecs; UString s; codecs->GetCodecsErrorMessage(s); if (!s.IsEmpty()) @@ -872,8 +877,7 @@ int Main2( } #endif - - bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); + const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); if (codecs->Formats.Size() == 0 && (isExtractGroupCommand @@ -888,13 +892,15 @@ int Main2( throw s; } #endif - throw kNoFormats; } CObjectVector<COpenType> types; if (!ParseOpenTypes(*codecs, options.ArcType, types)) + { throw kUnsupportedArcTypeMessage; + } + CIntVector excludedFormats; FOR_VECTOR (k, options.ExcludedArcTypes) @@ -903,13 +909,16 @@ int Main2( if (!codecs->FindFormatForArchiveType(options.ExcludedArcTypes[k], tempIndices) || tempIndices.Size() != 1) throw kUnsupportedArcTypeMessage; + + + excludedFormats.AddToUniqueSorted(tempIndices[0]); // excludedFormats.Sort(); } - #ifdef EXTERNAL_CODECS if (isExtractGroupCommand + || options.Command.IsFromUpdateGroup() || options.Command.CommandType == NCommandType::kHash || options.Command.CommandType == NCommandType::kBenchmark) ThrowException_if_Error(__externalCodecs.Load()); @@ -943,7 +952,7 @@ int Main2( so << endl << "Formats:" << endl; - const char * const kArcFlags = "KSNFMGOPBELHX"; + const char * const kArcFlags = "KSNFMGOPBELHXC"; const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags); for (i = 0; i < codecs->Formats.Size(); i++) @@ -953,7 +962,7 @@ int Main2( #ifdef EXTERNAL_CODECS PrintLibIndex(so, arc.LibIndex); #else - so << " "; + so << " "; #endif so << (char)(arc.UpdateEnabled ? 'C' : ' '); @@ -989,6 +998,8 @@ int Main2( if (arc.SignatureOffset != 0) so << "offset=" << arc.SignatureOffset << ' '; + // so << "numSignatures = " << arc.Signatures.Size() << " "; + FOR_VECTOR(si, arc.Signatures) { if (si != 0) @@ -1030,6 +1041,7 @@ int Main2( so << (char)(cod.CreateEncoder ? 'E' : ' '); so << (char)(cod.CreateDecoder ? 'D' : ' '); + so << (char)(cod.IsFilter ? 'F' : ' '); so << ' '; PrintHexId(so, cod.Id); @@ -1053,6 +1065,12 @@ int Main2( so << (char)(codecs->GetCodec_EncoderIsAssigned(j) ? 'E' : ' '); so << (char)(codecs->GetCodec_DecoderIsAssigned(j) ? 'D' : ' '); + { + bool isFilter_Assigned; + const bool isFilter = codecs->GetCodec_IsFilter(j, isFilter_Assigned); + so << (char)(isFilter ? 'F' : isFilter_Assigned ? ' ' : '*'); + } + so << ' '; UInt64 id; @@ -1215,6 +1233,7 @@ int Main2( } hresultMain = Extract( + // EXTERNAL_CODECS_VARS_L codecs, types, excludedFormats, @@ -1329,7 +1348,12 @@ int Main2( // options.ExtractNtOptions.StoreAltStreams = true, if -sns[-] is not definmed + CListOptions lo; + lo.ExcludeDirItems = options.Censor.ExcludeDirItems; + lo.ExcludeFileItems = options.Censor.ExcludeFileItems; + hresultMain = ListArchives( + lo, codecs, types, excludedFormats, @@ -1429,6 +1453,7 @@ int Main2( callback.Init(g_StdStream, g_ErrStream, percentsStream); callback.PrintHeaders = options.EnableHeaders; + callback.PrintFields = options.ListFields; AString errorInfoString; hresultMain = HashCalc(EXTERNAL_CODECS_VARS_L diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp index 24056072..0a25c225 100644 --- a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp @@ -5,6 +5,7 @@ #include "../../../Common/IntToString.h" #include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileName.h" #ifndef _7ZIP_ST #include "../../../Windows/Synchronization.h" @@ -470,7 +471,7 @@ HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const return CheckBreak2(); } -HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, const char *command, bool showInLog) +HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog) { MT_LOCK @@ -489,6 +490,8 @@ HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, const char *com if (name) { _tempU = name; + if (isDir) + NWindows::NFile::NName::NormalizeDirPathPrefix(_tempU); _so->Normalize_UString(_tempU); } _so->PrintUString(_tempU, _tempA); @@ -516,7 +519,7 @@ HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, const char *com return CheckBreak2(); } -HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool /* isDir */, bool isAnti, UInt32 mode) +HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode) { if (StdOutMode) return S_OK; @@ -546,7 +549,7 @@ HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool /* isDir */, s = "Reading"; } - return PrintProgress(name, s, LogLevel >= requiredLevel); + return PrintProgress(name, isDir, s, LogLevel >= requiredLevel); } HRESULT CUpdateCallbackConsole::OpenFileError(const FString &path, DWORD systemError) @@ -594,7 +597,7 @@ HRESULT CUpdateCallbackConsole::ReportExtractResult(Int32 opRes, Int32 isEncrypt } -HRESULT CUpdateCallbackConsole::ReportUpdateOpeartion(UInt32 op, const wchar_t *name, bool /* isDir */) +HRESULT CUpdateCallbackConsole::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) { // if (StdOutMode) return S_OK; @@ -622,7 +625,7 @@ HRESULT CUpdateCallbackConsole::ReportUpdateOpeartion(UInt32 op, const wchar_t * } } - return PrintProgress(name, s, LogLevel >= requiredLevel); + return PrintProgress(name, isDir, s, LogLevel >= requiredLevel); } /* @@ -694,7 +697,7 @@ HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password) COM_TRY_END } -HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name, bool /* isDir */) +HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name, bool isDir) { if (StdOutMode) return S_OK; @@ -703,7 +706,7 @@ HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name, bool /* isDi { if (!name || name[0] == 0) name = kEmptyFileAlias; - return PrintProgress(name, "D", true); + return PrintProgress(name, isDir, "D", true); } return S_OK; } diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.h b/CPP/7zip/UI/Console/UpdateCallbackConsole.h index 5c205aad..700d511c 100644 --- a/CPP/7zip/UI/Console/UpdateCallbackConsole.h +++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.h @@ -87,7 +87,7 @@ public: CErrorPathCodes ScanErrors; UInt64 NumNonOpenFiles; - HRESULT PrintProgress(const wchar_t *name, const char *command, bool showInLog); + HRESULT PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog); }; diff --git a/CPP/7zip/UI/Console/makefile b/CPP/7zip/UI/Console/makefile index ada782b0..acc3f107 100644 --- a/CPP/7zip/UI/Console/makefile +++ b/CPP/7zip/UI/Console/makefile @@ -5,6 +5,7 @@ CFLAGS = $(CFLAGS) \ COMMON_OBJS = \ $O\CommandLineParser.obj \ $O\CRC.obj \ + $O\DynLimBuf.obj \ $O\IntToString.obj \ $O\ListFileUtils.obj \ $O\NewHandler.obj \ @@ -48,6 +49,7 @@ WIN_OBJS = \ $O\UniqBlocks.obj \ AR_COMMON_OBJS = \ + $O\ItemNameUtils.obj \ $O\OutStreamWithCRC.obj \ COMPRESS_OBJS = \ diff --git a/CPP/7zip/UI/Console/makefile.gcc b/CPP/7zip/UI/Console/makefile.gcc index e0d996c1..ed05a142 100644 --- a/CPP/7zip/UI/Console/makefile.gcc +++ b/CPP/7zip/UI/Console/makefile.gcc @@ -100,6 +100,7 @@ COMMON_OBJS = \ $O/CommandLineParser.o \ $O/CRC.o \ $O/CrcReg.o \ + $O/DynLimBuf.o \ $O/IntToString.o \ $O/ListFileUtils.o \ $O/NewHandler.o \ @@ -148,6 +149,9 @@ WIN_OBJS = \ COMPRESS_OBJS = \ $O/CopyCoder.o \ +AR_COMMON_OBJS = \ + $O/ItemNameUtils.o \ + C_OBJS = \ $O/Alloc.o \ $O/CpuArch.o \ @@ -163,6 +167,7 @@ OBJS = \ $(WIN_OBJS) \ $(SYS_OBJS) \ $(COMPRESS_OBJS) \ + $(AR_COMMON_OBJS) \ $(7ZIP_COMMON_OBJS) \ $(UI_COMMON_OBJS) \ $(CONSOLE_OBJS) \ diff --git a/CPP/7zip/UI/Explorer/ContextMenu.cpp b/CPP/7zip/UI/Explorer/ContextMenu.cpp index 0334942a..8a0842e1 100644 --- a/CPP/7zip/UI/Explorer/ContextMenu.cpp +++ b/CPP/7zip/UI/Explorer/ContextMenu.cpp @@ -3,6 +3,7 @@ #include "StdAfx.h" #include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/COM.h" @@ -15,12 +16,15 @@ #include "../../../Windows/ProcessUtils.h" #include "../../../Windows/Shell.h" +#include "../../PropID.h" + #include "../Common/ArchiveName.h" #include "../Common/CompressCall.h" #include "../Common/ExtractingFilePath.h" #include "../Common/ZipRegistry.h" #include "../FileManager/FormatUtils.h" +#include "../FileManager/PropertyName.h" #ifdef LANG #include "../FileManager/LangUtils.h" @@ -52,16 +56,65 @@ extern LONG g_DllRefCount; extern HINSTANCE g_hInstance; #endif +#ifdef SHOW_DEBUG_CTX_MENU + +void Print_Ptr(void *p, char *s) +{ + char temp[64]; + ConvertUInt64ToHex((UInt64)(void *)p, temp); + AString s2; + s2 += temp; + s2.Add_Space(); + s2 += s; + OutputDebugStringA(s2); +} + +void Print_Number(UInt32 number, char *s) +{ + char temp[64]; + ConvertUInt64ToString(number, temp); + AString s2; + s2 += temp; + s2.Add_Space(); + s2 += s; + OutputDebugStringA(s2); +} + +#define ODS(sz) Print_Ptr(this, sz) +#define ODS_U(s) OutputDebugStringW(s); +// #define ODS(sz) +// #define ODS_U(s) + +#define ODS2(sz) Print_Ptr(this, sz) + +#else + +#define Print_Number(number, s) +#define ODS(sz) +#define ODS_U(s) +#define ODS2(sz) + +#endif + + + CZipContextMenu::CZipContextMenu(): _isMenuForFM(false), - _bitmap(NULL) + _dropMode(false), + _bitmap(NULL), + IsSeparator(false), + IsRoot(true), + CurrentSubCommand(0) { + ODS("-- CZipContextMenu()"); + InterlockedIncrement(&g_DllRefCount); _bitmap = ::LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_MENU_LOGO)); } CZipContextMenu::~CZipContextMenu() { + ODS("== ~CZipContextMenu"); if (_bitmap != NULL) DeleteObject(_bitmap); InterlockedDecrement(&g_DllRefCount); @@ -184,7 +237,9 @@ static const CHashCommand g_HashCommands[] = { CZipContextMenu::kHash_CRC64, "CRC-64", "CRC64" }, { CZipContextMenu::kHash_SHA1, "SHA-1", "SHA1" }, { CZipContextMenu::kHash_SHA256, "SHA-256", "SHA256" }, - { CZipContextMenu::kHash_All, "*", "*" } + { CZipContextMenu::kHash_All, "*", "*" }, + { CZipContextMenu::kHash_Generate_SHA256, "SHA-256 -> file.sha256", "SHA256" }, + { CZipContextMenu::kHash_TestArc, "Checksum : Test", "Hash" } }; @@ -209,9 +264,19 @@ void CZipContextMenu::FillCommand(ECommandInternalID id, UString &mainString, CC cmi.Verb += command.Verb; // cmi.HelpString = cmi.Verb; LangString(command.ResourceID, mainString); + cmi.UserString = mainString; // return true; } + +static UString LangStringAlt(UInt32 id, const char *altString) +{ + UString s = LangString(id); + if (s.IsEmpty()) + s = altString; + return s; +} + void CZipContextMenu::AddCommand(ECommandInternalID id, UString &mainString, CCommandMapItem &cmi) { @@ -222,6 +287,8 @@ void CZipContextMenu::AddCommand(ECommandInternalID id, UString &mainString, CCo static void MyInsertMenu(CMenu &menu, int pos, UINT id, const UString &s, HBITMAP bitmap) { + if (!menu) + return; CMenuItem mi; mi.fType = MFT_STRING; mi.fMask = MIIM_TYPE | MIIM_ID; @@ -247,9 +314,14 @@ static void MyAddSubMenu( CZipContextMenu::CCommandMapItem cmi; cmi.CommandInternalID = CZipContextMenu::kCommandNULL; cmi.Verb = verb; + cmi.IsPopup = true; // cmi.HelpString = verb; + cmi.UserString = s; _commandMap.Add(cmi); + if (!menu) + return; + CMenuItem mi; mi.fType = MFT_STRING; mi.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID; @@ -329,7 +401,7 @@ static void MyFormatNew_ReducedName(UString &s, const UString &name) s = MyFormatNew(s, GetQuotedReducedString(name)); } -static const char * const kExtractExludeExtensions = +static const char * const kExtractExcludeExtensions = " 3gp" " aac ans ape asc asm asp aspx avi awk" " bas bat bmp" @@ -403,7 +475,7 @@ static bool FindExt(const char *p, const FString &name) static bool DoNeedExtract(const FString &name) { - return !FindExt(kExtractExludeExtensions, name); + return !FindExt(kExtractExcludeExtensions, name); } // we must use diferent Verbs for Popup subMenu. @@ -427,12 +499,12 @@ static HRESULT RETURN_WIN32_LastError_AS_HRESULT() /* - we add CCommandMapItem to _commandMap for each new Mene ID. + we add CCommandMapItem to _commandMap for each new Menu ID. so then we use _commandMap[offset]. That way we can execute commands that have menu item. Another non-implemented way: - We can return the number off all possible commnad in QueryContextMenu(). - so the caller could call InvokeCommand() via string verb aven + We can return the number off all possible commands in QueryContextMenu(). + so the caller could call InvokeCommand() via string verb even without using menu items. */ @@ -441,6 +513,7 @@ static HRESULT RETURN_WIN32_LastError_AS_HRESULT() STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT commandIDFirst, UINT commandIDLast, UINT flags) { + ODS("+ QueryContextMenu()"); COM_TRY_BEGIN try { @@ -493,9 +566,12 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, bitmap = _bitmap; UINT subIndex = indexMenu; + + ODS("### 50"); if (ci.Cascaded.Val) { + if (hMenu) if (!popupMenu.CreatePopup()) return RETURN_WIN32_LastError_AS_HRESULT(); menuDestroyer.Attach(popupMenu); @@ -514,6 +590,7 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, CMenuItem mi; mi.fType = MFT_SEPARATOR; mi.fMask = MIIM_TYPE; + if (hMenu) popupMenu.InsertItem(subIndex++, true, mi); } @@ -551,6 +628,8 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, } } + ODS("### 100"); + UString mainString; if (_fileNames.Size() == 1 && currentCommandID + 14 <= commandIDLast) @@ -567,13 +646,15 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, } if ((contextMenuFlags & NContextMenuFlags::kOpenAs) != 0 // && (!thereIsMainOpenItem || !FindExt(kNoOpenAsExtensions, fi0.Name)) + && hMenu // we want to reduce number of menu items below 16 ) { CMenu subMenu; - if (subMenu.CreatePopup()) + if (!hMenu || subMenu.CreatePopup()) { MyAddSubMenu(_commandMap, kOpenCascadedVerb, popupMenu, subIndex++, currentCommandID++, LangString(IDS_CONTEXT_OPEN), subMenu, bitmap); - + _commandMap.Back().CtxCommandType = CtxCommandType_OpenRoot; + UINT subIndex2 = 0; for (unsigned i = (thereIsMainOpenItem ? 1 : 0); i < ARRAY_SIZE(kOpenTypes); i++) { @@ -589,8 +670,10 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, cmi.Verb += mainString; // cmi.HelpString = cmi.Verb; cmi.ArcType = mainString; + cmi.CtxCommandType = CtxCommandType_OpenChild; } _commandMap.Add(cmi); + Set_UserString_in_LastCommand(mainString); MyInsertMenu(subMenu, subIndex2++, currentCommandID++, mainString, bitmap); } @@ -662,6 +745,7 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, cmi.Folder = baseFolder + specFolder; AddCommand(kExtractTo, s, cmi); MyFormatNew_ReducedName(s, specFolder); + Set_UserString_in_LastCommand(s); MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); } } @@ -720,6 +804,7 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, cmi.ArcType = "7z"; AddCommand(kCompressTo7z, s, cmi); MyFormatNew_ReducedName(s, arcName7z); + Set_UserString_in_LastCommand(s); MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); } @@ -733,6 +818,7 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, cmi.ArcType = "7z"; AddCommand(kCompressTo7zEmail, s, cmi); MyFormatNew_ReducedName(s, arcName7z); + Set_UserString_in_LastCommand(s); MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); } #endif @@ -751,6 +837,7 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, cmi.ArcType = "zip"; AddCommand(kCompressToZip, s, cmi); MyFormatNew_ReducedName(s, arcNameZip); + Set_UserString_in_LastCommand(s); MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); } @@ -764,6 +851,7 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, cmi.ArcType = "zip"; AddCommand(kCompressToZipEmail, s, cmi); MyFormatNew_ReducedName(s, arcNameZip); + Set_UserString_in_LastCommand(s); MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); } #endif @@ -779,32 +867,56 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, CMenu menu; menu.Attach(hMenu); menuDestroyer.Disable(); - MyAddSubMenu(_commandMap, kMainVerb, menu, indexMenu++, currentCommandID++, (UString)"7-Zip", popupMenu.Detach(), bitmap); + MyAddSubMenu(_commandMap, kMainVerb, menu, indexMenu++, currentCommandID++, (UString)"7-Zip", + popupMenu, // popupMenu.Detach(), + bitmap); } else { - popupMenu.Detach(); + // popupMenu.Detach(); indexMenu = subIndex; } + const bool needCrc = ((contextMenuFlags & + (NContextMenuFlags::kCRC | + NContextMenuFlags::kCRC_Cascaded)) != 0); - if (!_isMenuForFM && - ((contextMenuFlags & NContextMenuFlags::kCRC) != 0 - && currentCommandID + 1 < commandIDLast)) + if ( + // !_isMenuForFM && // 21.04: we don't hide CRC SHA menu in 7-Zip FM + needCrc + && currentCommandID + 1 < commandIDLast) { CMenu subMenu; // CMenuDestroyer menuDestroyer_CRC; - + UINT subIndex_CRC = 0; - if (subMenu.CreatePopup()) + if (!hMenu || subMenu.CreatePopup()) { // menuDestroyer_CRC.Attach(subMenu); + const bool insertHashMenuTo7zipMenu = (ci.Cascaded.Val + && (contextMenuFlags & NContextMenuFlags::kCRC_Cascaded) != 0); CMenu menu; - menu.Attach(hMenu); - // menuDestroyer_CRC.Disable(); - MyAddSubMenu(_commandMap, kCheckSumCascadedVerb, menu, indexMenu++, currentCommandID++, (UString)"CRC SHA", subMenu, bitmap); + { + int indexInParent; + if (insertHashMenuTo7zipMenu) + { + indexInParent = subIndex; + menu.Attach(popupMenu); + } + else + { + indexInParent = indexMenu; + menu.Attach(hMenu); + // menuDestroyer_CRC.Disable(); + } + MyAddSubMenu(_commandMap, kCheckSumCascadedVerb, menu, indexInParent++, currentCommandID++, (UString)"CRC SHA", subMenu, + /* insertHashMenuTo7zipMenu ? NULL : */ bitmap); + _commandMap.Back().CtxCommandType = CtxCommandType_CrcRoot; + if (!insertHashMenuTo7zipMenu) + indexMenu = indexInParent; + } for (unsigned i = 0; i < ARRAY_SIZE(g_HashCommands); i++) { @@ -816,15 +928,57 @@ STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, cmi.Verb = kCheckSumCascadedVerb; cmi.Verb += '.'; cmi.Verb += hc.MethodName; + UString s; + s += hc.UserName; + + if (hc.CommandInternalID == kHash_Generate_SHA256) + { + { + popupMenu.Attach(hMenu); + CMenuItem mi; + mi.fType = MFT_SEPARATOR; + mi.fMask = MIIM_TYPE; + subMenu.InsertItem(subIndex_CRC++, true, mi); + } + + UString name; + if (_fileNames.Size() > 1) + name = CreateArchiveName(_fileNames, _fileNames.Size() == 1 ? &fi0 : NULL); + else + name = fs2us(fi0.Name); + name += ".sha256"; + cmi.Folder= folderPrefix; + cmi.ArcName = name; + s = "SHA-256 -> "; + s += name; + } + else if (hc.CommandInternalID == kHash_TestArc) + { + s = LangStringAlt(IDS_CONTEXT_TEST, "Test archive"); + s += " : "; + s += GetNameOfProperty(kpidChecksum, UString("Checksum")); + } + // cmi.HelpString = cmi.Verb; + cmi.UserString = s; + cmi.CtxCommandType = CtxCommandType_CrcChild; _commandMap.Add(cmi); - MyInsertMenu(subMenu, subIndex_CRC++, currentCommandID++, (UString)hc.UserName, bitmap); + MyInsertMenu(subMenu, subIndex_CRC++, currentCommandID++, s, bitmap); } subMenu.Detach(); } } + popupMenu.Detach(); + + /* + if (!ci.Cascaded.Val) + indexMenu = subIndex; + */ + + ODS("### 400"); + #ifdef SHOW_DEBUG_CTX_MENU { char s[256]; sprintf(s, "Commands=%d currentCommandID - commandIDFirst = %d", _commandMap.Size(), currentCommandID - commandIDFirst); OutputDebugStringA(s); } @@ -981,9 +1135,15 @@ STDMETHODIMP CZipContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO commandInfo) if (commandOffset < 0 || (unsigned)commandOffset >= _commandMap.Size()) return E_INVALIDARG; - const CCommandMapItem &cmi = _commandMap[(unsigned)commandOffset]; - ECommandInternalID cmdID = cmi.CommandInternalID; + return InvokeCommandCommon(cmi); + COM_TRY_END +} + + +HRESULT CZipContextMenu::InvokeCommandCommon(const CCommandMapItem &cmi) +{ + const ECommandInternalID cmdID = cmi.CommandInternalID; try { @@ -1023,18 +1183,20 @@ STDMETHODIMP CZipContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO commandInfo) case kCompressToZip: case kCompressToZipEmail: { - bool email = + const bool email = (cmdID == kCompressEmail) || (cmdID == kCompressTo7zEmail) || (cmdID == kCompressToZipEmail); - bool showDialog = + const bool showDialog = (cmdID == kCompress) || (cmdID == kCompressEmail); - bool addExtension = (cmdID == kCompress || cmdID == kCompressEmail); + const bool addExtension = (cmdID == kCompress || cmdID == kCompressEmail); CompressFiles(cmi.Folder, cmi.ArcName, cmi.ArcType, addExtension, - _fileNames, email, showDialog, false); + _fileNames, email, showDialog, + false // waitFinish + ); break; } @@ -1043,13 +1205,24 @@ STDMETHODIMP CZipContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO commandInfo) case kHash_SHA1: case kHash_SHA256: case kHash_All: + case kHash_Generate_SHA256: + case kHash_TestArc: { for (unsigned i = 0; i < ARRAY_SIZE(g_HashCommands); i++) { const CHashCommand &hc = g_HashCommands[i]; if (hc.CommandInternalID == cmdID) { - CalcChecksum(_fileNames, (UString)hc.MethodName); + if (cmdID == kHash_TestArc) + { + TestArchives(_fileNames, true); // hashMode + break; + } + UString generateName; + if (cmdID == kHash_Generate_SHA256) + generateName = cmi.ArcName; + CalcChecksum(_fileNames, (UString)hc.MethodName, + cmi.Folder, generateName); break; } } @@ -1064,7 +1237,6 @@ STDMETHODIMP CZipContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO commandInfo) ::MessageBoxW(0, L"Error", L"7-Zip", MB_ICONERROR); } return S_OK; - COM_TRY_END } @@ -1136,3 +1308,371 @@ STDMETHODIMP CZipContextMenu::GetCommandString(UINT_PTR commandOffset, UINT uTyp COM_TRY_END } + + + +// ---------- IExplorerCommand ---------- + +static HRESULT WINAPI My_SHStrDupW(LPCWSTR src, LPWSTR *dest) +{ + if (src) + { + const SIZE_T size = (wcslen(src) + 1) * sizeof(WCHAR); + WCHAR *p = (WCHAR *)CoTaskMemAlloc(size); + if (p) + { + memcpy(p, src, size); + *dest = p; + return S_OK; + } + } + *dest = NULL; + return E_OUTOFMEMORY; +} + + +#define CZipExplorerCommand CZipContextMenu + +class CCoTaskWSTR +{ + LPWSTR m_str; + CLASS_NO_COPY(CCoTaskWSTR) +public: + CCoTaskWSTR(): m_str(NULL) {} + ~CCoTaskWSTR() { ::CoTaskMemFree(m_str); } + LPWSTR* operator&() { return &m_str; } + operator LPCWSTR () const { return m_str; } + // operator LPCOLESTR() const { return m_str; } + operator bool() const { return m_str != NULL; } + // bool operator!() const { return m_str == NULL; } + + /* + void Wipe_and_Free() + { + if (m_str) + { + memset(m_str, 0, ::SysStringLen(m_str) * sizeof(*m_str)); + Empty(); + } + } + */ + +private: + /* + CCoTaskWSTR(LPCOLESTR src) { m_str = ::CoTaskMemAlloc(src); } + + CCoTaskWSTR& operator=(LPCOLESTR src) + { + ::CoTaskMemFree(m_str); + m_str = ::SysAllocString(src); + return *this; + } + + + void Empty() + { + ::CoTaskMemFree(m_str); + m_str = NULL; + } + */ +}; + +static void LoadPaths(IShellItemArray *psiItemArray, UStringVector &paths) +{ + if (psiItemArray) + { + DWORD numItems = 0; + if (psiItemArray->GetCount(&numItems) == S_OK) + { + for (DWORD i = 0; i < numItems; i++) + { + CMyComPtr<IShellItem> item; + if (psiItemArray->GetItemAt(i, &item) == S_OK && item) + { + CCoTaskWSTR displayName; + if (item->GetDisplayName(SIGDN_FILESYSPATH, &displayName) == S_OK + && (bool)displayName) + { + OutputDebugStringW(displayName); + paths.Add((LPCWSTR)displayName); + } + } + } + } + } +} + + +void CZipExplorerCommand::LoadItems(IShellItemArray *psiItemArray) +{ + SubCommands.Clear(); + + UStringVector paths; + LoadPaths(psiItemArray, paths); + _fileNames = paths; + + HRESULT res = QueryContextMenu( + NULL, // hMenu, + 0, // indexMenu, + 0, // commandIDFirst, + 0 + 999, // commandIDLast, + CMF_NORMAL); + + if (FAILED(res)) + return /* res */; + + + CZipExplorerCommand *crcHandler = NULL; + CZipExplorerCommand *openHandler = NULL; + + bool useCascadedCrc = true; // false; + bool useCascadedOpen = true; // false; + + for (unsigned i = 0; i < _commandMap.Size(); i++) + { + const CCommandMapItem &cmi = _commandMap[i]; + + + if (cmi.IsPopup) + if (!cmi.IsSubMenu()) + continue; + + // if (cmi.IsSubMenu()) continue // for debug + + CZipContextMenu *shellExt = new CZipContextMenu(); + shellExt->IsRoot = false; + + if (cmi.CtxCommandType == CtxCommandType_CrcRoot && !useCascadedCrc) + shellExt->IsSeparator = true; + + { + CZipExplorerCommand *handler = this; + if (cmi.CtxCommandType == CtxCommandType_CrcChild && crcHandler) + handler = crcHandler; + else if (cmi.CtxCommandType == CtxCommandType_OpenChild && openHandler) + handler = openHandler; + handler->SubCommands.AddNew() = shellExt; + } + + shellExt->_commandMap_Cur.Add(cmi); + + ODS_U(cmi.UserString); + + if (cmi.CtxCommandType == CtxCommandType_CrcRoot && useCascadedCrc) + crcHandler = shellExt; + if (cmi.CtxCommandType == CtxCommandType_OpenRoot && useCascadedOpen) + { + // ODS2("cmi.CtxCommandType == CtxCommandType_OpenRoot"); + openHandler = shellExt; + } + } +} + + +STDMETHODIMP CZipExplorerCommand::GetTitle(IShellItemArray *psiItemArray, LPWSTR *ppszName) +{ + ODS("- GetTitle()"); + // COM_TRY_BEGIN + if (IsSeparator) + { + *ppszName = NULL; + return S_FALSE; + } + + UString name; + if (IsRoot) + { + LoadItems(psiItemArray); + name = "7-Zip"; // "New" + } + else + name = "7-Zip item"; + + if (!_commandMap_Cur.IsEmpty()) + { + const CCommandMapItem &mi = _commandMap_Cur[0]; + // s += mi.Verb; + // s += " : "; + name = mi.UserString; + } + + return My_SHStrDupW(name, ppszName); + // return S_OK; + // COM_TRY_END +} + + +STDMETHODIMP CZipExplorerCommand::GetIcon(IShellItemArray * /* psiItemArray */, LPWSTR *ppszIcon) +{ + ODS("- GetIcon()"); + // COM_TRY_BEGIN + *ppszIcon = NULL; + // return E_NOTIMPL; + UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix()); + // imageName += "7zG.exe"; + imageName += "7-zip.dll"; + // imageName += ",190"; + return My_SHStrDupW(imageName, ppszIcon); + // COM_TRY_END +} + + +STDMETHODIMP CZipExplorerCommand::GetToolTip (IShellItemArray * /* psiItemArray */, LPWSTR *ppszInfotip) +{ + // COM_TRY_BEGIN + ODS("- GetToolTip()"); + *ppszInfotip = NULL; + return E_NOTIMPL; + // COM_TRY_END +} + + +STDMETHODIMP CZipExplorerCommand::GetCanonicalName(GUID *pguidCommandName) +{ + // COM_TRY_BEGIN + ODS("- GetCanonicalName()"); + *pguidCommandName = GUID_NULL; + return E_NOTIMPL; + // COM_TRY_END +} + + +STDMETHODIMP CZipExplorerCommand::GetState(IShellItemArray * /* psiItemArray */, BOOL /* fOkToBeSlow */, EXPCMDSTATE *pCmdState) +{ + // COM_TRY_BEGIN + ODS("- GetState()"); + *pCmdState = ECS_ENABLED; + return S_OK; + // COM_TRY_END +} + + + + +STDMETHODIMP CZipExplorerCommand::Invoke(IShellItemArray *psiItemArray, IBindCtx * /* pbc */) +{ + COM_TRY_BEGIN + + if (_commandMap_Cur.IsEmpty()) + return E_INVALIDARG; + + ODS("- Invoke()"); + UStringVector paths; + LoadPaths(psiItemArray, paths); + _fileNames = paths; + return InvokeCommandCommon(_commandMap_Cur[0]); + + COM_TRY_END +} + + +STDMETHODIMP CZipExplorerCommand::GetFlags(EXPCMDFLAGS *pFlags) +{ + ODS("- GetFlags()"); + // COM_TRY_BEGIN + EXPCMDFLAGS f = ECF_DEFAULT; + if (IsSeparator) + f = ECF_ISSEPARATOR; + else if (IsRoot) + f = ECF_HASSUBCOMMANDS; + else + { + if (!_commandMap_Cur.IsEmpty()) + { + // const CCommandMapItem &cmi = ; + if (_commandMap_Cur[0].IsSubMenu()) + { + // ODS("ECF_HASSUBCOMMANDS"); + f = ECF_HASSUBCOMMANDS; + } + } + } + *pFlags = f; + return S_OK; + // COM_TRY_END +} + + +STDMETHODIMP CZipExplorerCommand::EnumSubCommands(IEnumExplorerCommand **ppEnum) +{ + ODS("- EnumSubCommands()"); + // COM_TRY_BEGIN + *ppEnum = NULL; + + if (!_commandMap_Cur.IsEmpty() && _commandMap_Cur[0].IsSubMenu()) + { + } + else + { + if (!IsRoot) + return E_NOTIMPL; + if (SubCommands.IsEmpty()) + { + return E_NOTIMPL; + } + } + + // shellExt-> + return QueryInterface(IID_IEnumExplorerCommand, (void **)ppEnum); + + // return S_OK; + // COM_TRY_END +} + + +STDMETHODIMP CZipContextMenu::Next(ULONG celt, IExplorerCommand **pUICommand, ULONG *pceltFetched) +{ + ODS("CZipContextMenu::Next()"); + Print_Number(celt, "celt"); + Print_Number(CurrentSubCommand, "CurrentSubCommand"); + Print_Number(SubCommands.Size(), "SubCommands.Size()"); + + COM_TRY_BEGIN + ULONG fetched = 0; + + ULONG i; + for (i = 0; i < celt; i++) + { + pUICommand[i] = NULL; + } + + for (i = 0; i < celt && CurrentSubCommand < SubCommands.Size(); i++) + { + pUICommand[i] = SubCommands[CurrentSubCommand++]; + pUICommand[i]->AddRef(); + fetched++; + } + + if (pceltFetched) + *pceltFetched = fetched; + + ODS(fetched == celt ? " === OK === " : "=== ERROR ==="); + + // we return S_FALSE for (fetched == 0) + return (fetched == celt) ? S_OK : S_FALSE; + COM_TRY_END +} + + +STDMETHODIMP CZipContextMenu::Skip(ULONG celt) +{ + ODS("CZipContextMenu::Skip()"); + celt = celt; + return E_NOTIMPL; +} + + +STDMETHODIMP CZipContextMenu::Reset(void) +{ + ODS("CZipContextMenu::Reset()"); + CurrentSubCommand = 0; + return S_OK; +} + + +STDMETHODIMP CZipContextMenu::Clone(IEnumExplorerCommand **ppenum) +{ + ODS("CZipContextMenu::Clone()"); + *ppenum = NULL; + return E_NOTIMPL; +} diff --git a/CPP/7zip/UI/Explorer/ContextMenu.h b/CPP/7zip/UI/Explorer/ContextMenu.h index dddb9fd1..285044e7 100644 --- a/CPP/7zip/UI/Explorer/ContextMenu.h +++ b/CPP/7zip/UI/Explorer/ContextMenu.h @@ -7,13 +7,27 @@ #include <ShlObj.h> +#include "MyExplorerCommand.h" + #include "../../../Common/MyString.h" #include "../FileManager/MyCom2.h" +enum ECtxCommandType +{ + CtxCommandType_Normal, + CtxCommandType_OpenRoot, + CtxCommandType_OpenChild, + CtxCommandType_CrcRoot, + CtxCommandType_CrcChild, +}; + + class CZipContextMenu: public IContextMenu, public IShellExtInit, + public IExplorerCommand, + public IEnumExplorerCommand, public CMyUnknownImp { public: @@ -36,10 +50,17 @@ public: kHash_CRC64, kHash_SHA1, kHash_SHA256, - kHash_All + kHash_All, + kHash_Generate_SHA256, + kHash_TestArc }; - MY_UNKNOWN_IMP2_MT(IContextMenu, IShellExtInit) + MY_UNKNOWN_IMP4_MT( + IContextMenu, + IShellExtInit, + IExplorerCommand, + IEnumExplorerCommand + ) // IShellExtInit STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder, LPDATAOBJECT dataObject, HKEY hkeyProgID); @@ -51,6 +72,24 @@ public: HRESULT InitContextMenu(const wchar_t *folder, const wchar_t * const *names, unsigned numFiles); + void LoadItems(IShellItemArray *psiItemArray); + + // IExplorerCommand + STDMETHOD (GetTitle) (IShellItemArray *psiItemArray, LPWSTR *ppszName); + STDMETHOD (GetIcon) (IShellItemArray *psiItemArray, LPWSTR *ppszIcon); + STDMETHOD (GetToolTip) (IShellItemArray *psiItemArray, LPWSTR *ppszInfotip); + STDMETHOD (GetCanonicalName) (GUID *pguidCommandName); + STDMETHOD (GetState) (IShellItemArray *psiItemArray, BOOL fOkToBeSlow, EXPCMDSTATE *pCmdState); + STDMETHOD (Invoke) (IShellItemArray *psiItemArray, IBindCtx *pbc); + STDMETHOD (GetFlags) (EXPCMDFLAGS *pFlags); + STDMETHOD (EnumSubCommands) (IEnumExplorerCommand **ppEnum); + + // IEnumExplorerCommand + STDMETHOD (Next) (ULONG celt, IExplorerCommand **pUICommand, ULONG *pceltFetched); + STDMETHOD (Skip) (ULONG celt); + STDMETHOD (Reset) (void); + STDMETHOD (Clone) (IEnumExplorerCommand **ppenum); + CZipContextMenu(); ~CZipContextMenu(); @@ -58,10 +97,25 @@ public: { ECommandInternalID CommandInternalID; UString Verb; + UString UserString; // UString HelpString; UString Folder; UString ArcName; UString ArcType; + bool IsPopup; + ECtxCommandType CtxCommandType; + + CCommandMapItem(): + IsPopup(false), + CtxCommandType(CtxCommandType_Normal) + {} + + bool IsSubMenu() const + { + return + CtxCommandType == CtxCommandType_CrcRoot || + CtxCommandType == CtxCommandType_OpenRoot; + } }; private: @@ -71,16 +125,28 @@ private: bool _dropMode; UString _dropPath; CObjectVector<CCommandMapItem> _commandMap; + CObjectVector<CCommandMapItem> _commandMap_Cur; HBITMAP _bitmap; - CBoolPair _elimDup; + bool IsSeparator; + bool IsRoot; + CObjectVector< CMyComPtr<IExplorerCommand> > SubCommands; + ULONG CurrentSubCommand; + + void Set_UserString_in_LastCommand(const UString &s) + { + _commandMap.Back().UserString = s; + } + HRESULT GetFileNames(LPDATAOBJECT dataObject, UStringVector &fileNames); int FindVerb(const UString &verb); void FillCommand(ECommandInternalID id, UString &mainString, CCommandMapItem &cmi); void AddCommand(ECommandInternalID id, UString &mainString, CCommandMapItem &cmi); void AddMapItem_ForSubMenu(const char *ver); + + HRESULT InvokeCommandCommon(const CCommandMapItem &cmi); }; #endif diff --git a/CPP/7zip/UI/Explorer/ContextMenuFlags.h b/CPP/7zip/UI/Explorer/ContextMenuFlags.h index f739cdc6..42b25f3a 100644 --- a/CPP/7zip/UI/Explorer/ContextMenuFlags.h +++ b/CPP/7zip/UI/Explorer/ContextMenuFlags.h @@ -20,6 +20,7 @@ namespace NContextMenuFlags const UInt32 kCompressToZip = 1 << 12; const UInt32 kCompressToZipEmail = 1 << 13; + const UInt32 kCRC_Cascaded = (UInt32)1 << 30; const UInt32 kCRC = (UInt32)1 << 31; } diff --git a/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp b/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp index cb4da016..91b0da52 100644 --- a/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp +++ b/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp @@ -9,6 +9,7 @@ #include "StdAfx.h" #include "../../../Common/MyWindows.h" +// #include "../../../Common/IntToString.h" #include <OleCtl.h> @@ -52,7 +53,8 @@ LONG g_DllRefCount; LONG g_DllRefCount = 0; // Reference count of this DLL. -// #define ODS(sz) OutputDebugString(L#sz) +// #define ODS(sz) OutputDebugStringW(L#sz) +#define ODS(sz) class CShellExtClassFactory: public IClassFactory, @@ -71,7 +73,12 @@ public: STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj) { - // ODS("CShellExtClassFactory::CreateInstance()\r\n"); + ODS("CShellExtClassFactory::CreateInstance()\r\n"); + /* + char s[64]; + ConvertUInt32ToHex(riid.Data1, s); + OutputDebugStringA(s); + */ *ppvObj = NULL; if (pUnkOuter) return CLASS_E_NOAGGREGATION; @@ -123,12 +130,12 @@ BOOL WINAPI DllMain( if (dwReason == DLL_PROCESS_ATTACH) { g_hInstance = (HINSTANCE)hInstance; - // ODS("In DLLMain, DLL_PROCESS_ATTACH\r\n"); + ODS("In DLLMain, DLL_PROCESS_ATTACH\r\n"); NT_CHECK } else if (dwReason == DLL_PROCESS_DETACH) { - // ODS("In DLLMain, DLL_PROCESS_DETACH\r\n"); + ODS("In DLLMain, DLL_PROCESS_DETACH\r\n"); } return TRUE; } @@ -138,13 +145,19 @@ BOOL WINAPI DllMain( STDAPI DllCanUnloadNow(void) { - // ODS("In DLLCanUnloadNow\r\n"); + ODS("In DLLCanUnloadNow\r\n"); + /* + if (g_DllRefCount == 0) + ODS( "g_DllRefCount == 0"); + else + ODS( "g_DllRefCount != 0"); + */ return (g_DllRefCount == 0 ? S_OK : S_FALSE); } STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { - // ODS("In DllGetClassObject\r\n"); + ODS("In DllGetClassObject\r\n"); *ppv = NULL; if (IsEqualIID(rclsid, CLSID_CZipContextMenu)) { @@ -168,6 +181,7 @@ STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) static BOOL RegisterServer() { + ODS("RegisterServer\r\n"); FString modulePath; if (!NDLL::MyGetModuleFileName(modulePath)) return FALSE; @@ -197,6 +211,7 @@ static BOOL RegisterServer() key.SetValue(k_Clsid, k_ShellExtName); } + ODS("RegisterServer :: return TRUE"); return TRUE; } diff --git a/CPP/7zip/UI/Explorer/Explorer.dsp b/CPP/7zip/UI/Explorer/Explorer.dsp index bd91e546..e3909176 100644 --- a/CPP/7zip/UI/Explorer/Explorer.dsp +++ b/CPP/7zip/UI/Explorer/Explorer.dsp @@ -55,7 +55,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Program Files\7-ZIP\7-Zip.dll" /opt:NOWIN98 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Util\7-Zip.dll" /opt:NOWIN98 # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "Explorer - Win32 Debug" @@ -82,7 +82,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\7-ZIP\7-Zip.dll" /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\7-Zip.dll" /pdbtype:sept !ELSEIF "$(CFG)" == "Explorer - Win32 ReleaseU" @@ -110,7 +110,7 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Program Files\7-ZIP\7-Zip.dll" /opt:NOWIN98 # SUBTRACT BASE LINK32 /pdb:none -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Program Files\7-ZIP\7-Zipn.dll" /opt:NOWIN98 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Util\7-Zip.dll" /opt:NOWIN98 # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "Explorer - Win32 DebugU" @@ -138,7 +138,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\7-ZIP\7-Zip.dll" /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\7-ZIP\7-Zip.dll" /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\7-Zip.dll" /pdbtype:sept !ENDIF @@ -226,6 +226,10 @@ SOURCE=.\ContextMenu.h # End Source File # Begin Source File +SOURCE=.\MyExplorerCommand.h +# End Source File +# Begin Source File + SOURCE=.\MyMessages.cpp # End Source File # Begin Source File @@ -274,6 +278,14 @@ SOURCE=..\FileManager\ProgramLocation.h # End Source File # Begin Source File +SOURCE=..\FileManager\PropertyName.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\PropertyName.h +# End Source File +# Begin Source File + SOURCE=..\FileManager\RegistryUtils.cpp # End Source File # Begin Source File diff --git a/CPP/7zip/UI/Explorer/MyExplorerCommand.h b/CPP/7zip/UI/Explorer/MyExplorerCommand.h new file mode 100644 index 00000000..6004d929 --- /dev/null +++ b/CPP/7zip/UI/Explorer/MyExplorerCommand.h @@ -0,0 +1,173 @@ +// MyExplorerCommand.h + +#ifndef __MY_EXPLORER_COMMAND_H +#define __MY_EXPLORER_COMMAND_H + +#if _MSC_VER >= 1910 +#define USE_SYS_shobjidl_core +#endif + +#ifdef USE_SYS_shobjidl_core + +// #include <shobjidl_core.h> + +#else + +#ifndef __IShellItemArray_INTERFACE_DEFINED__ +#define __IShellItemArray_INTERFACE_DEFINED__ + +// propsys.h + +typedef /* [v1_enum] */ +enum GETPROPERTYSTOREFLAGS +{ + GPS_DEFAULT = 0, + GPS_HANDLERPROPERTIESONLY = 0x1, + GPS_READWRITE = 0x2, + GPS_TEMPORARY = 0x4, + GPS_FASTPROPERTIESONLY = 0x8, + GPS_OPENSLOWITEM = 0x10, + GPS_DELAYCREATION = 0x20, + GPS_BESTEFFORT = 0x40, + GPS_NO_OPLOCK = 0x80, + GPS_PREFERQUERYPROPERTIES = 0x100, + GPS_EXTRINSICPROPERTIES = 0x200, + GPS_EXTRINSICPROPERTIESONLY = 0x400, + GPS_VOLATILEPROPERTIES = 0x800, + GPS_VOLATILEPROPERTIESONLY = 0x1000, + GPS_MASK_VALID = 0x1fff +} GETPROPERTYSTOREFLAGS; + +// DEFINE_ENUM_FLAG_OPERATORS(GETPROPERTYSTOREFLAGS) + + +#ifndef PROPERTYKEY_DEFINED +#define PROPERTYKEY_DEFINED + +typedef +struct _tagpropertykey +{ + GUID fmtid; + DWORD pid; +} PROPERTYKEY; + +#endif // PROPERTYKEY_DEFINED + +// propkeydef.h +#define REFPROPERTYKEY const PROPERTYKEY & + +#ifdef INITGUID +#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const PROPERTYKEY DECLSPEC_SELECTANY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid } +#else +#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const PROPERTYKEY name +#endif // INITGUID + + +// <shobjidl_core.h> +typedef /* [v1_enum] */ +enum SIATTRIBFLAGS +{ + SIATTRIBFLAGS_AND = 0x1, + SIATTRIBFLAGS_OR = 0x2, + SIATTRIBFLAGS_APPCOMPAT = 0x3, + SIATTRIBFLAGS_MASK = 0x3, + SIATTRIBFLAGS_ALLITEMS = 0x4000 +} SIATTRIBFLAGS; + +// DEFINE_ENUM_FLAG_OPERATORS(SIATTRIBFLAGS) + + +// MIDL_INTERFACE("70629033-e363-4a28-a567-0db78006e6d7") +DEFINE_GUID(IID_IEnumShellItems, 0x70629033, 0xe363, 0xe363, 0xa5, 0x67, 0x0d, 0xb7, 0x80, 0x06, 0xe6, 0xd7); + +struct IEnumShellItems : public IUnknown +{ + STDMETHOD (Next) (ULONG celt, IShellItem **rgelt, ULONG *pceltFetched) = 0; + STDMETHOD (Skip) (ULONG celt) = 0; + STDMETHOD (Reset) (void) = 0; + STDMETHOD (Clone) (IEnumShellItems **ppenum) = 0; +}; + + +// MIDL_INTERFACE("b63ea76d-1f85-456f-a19c-48159efa858b") +DEFINE_GUID(IID_IShellItemArray, 0xb63ea76d, 0x1f85, 0x456f, 0xa1, 0x9c, 0x48, 0x15, 0x9e, 0xfa, 0x85, 0x8b); + +struct IShellItemArray : public IUnknown +{ + STDMETHOD (BindToHandler) (IBindCtx *pbc, REFGUID bhid, REFIID riid, void **ppvOut) = 0; + STDMETHOD (GetPropertyStore) (GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv) = 0; + STDMETHOD (GetPropertyDescriptionList) (REFPROPERTYKEY keyType, REFIID riid, void **ppv) = 0; + STDMETHOD (GetAttributes) ( SIATTRIBFLAGS AttribFlags, SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs) = 0; + STDMETHOD (GetCount) (DWORD *pdwNumItems) = 0; + STDMETHOD (GetItemAt) (DWORD dwIndex, IShellItem **ppsi) = 0; + STDMETHOD (EnumItems) (IEnumShellItems **ppenumShellItems) = 0; +}; + + +#ifndef __IEnumExplorerCommand_INTERFACE_DEFINED__ +#define __IEnumExplorerCommand_INTERFACE_DEFINED__ + +struct IExplorerCommand; + +// MIDL_INTERFACE("a88826f8-186f-4987-aade-ea0cef8fbfe8") +DEFINE_GUID(IID_IEnumExplorerCommand , 0xa88826f8, 0x186f, 0x4987, 0xaa, 0xde, 0xea, 0x0c, 0xef, 0x8f, 0xbf, 0xe8); + +struct IEnumExplorerCommand : public IUnknown +{ + STDMETHOD (Next) (ULONG celt, IExplorerCommand **pUICommand, ULONG *pceltFetched) = 0; + STDMETHOD (Skip) (ULONG celt) = 0; + STDMETHOD (Reset) (void) = 0; + STDMETHOD (Clone) (IEnumExplorerCommand **ppenum) = 0; +}; + + +enum _EXPCMDSTATE +{ + ECS_ENABLED = 0, + ECS_DISABLED = 0x1, + ECS_HIDDEN = 0x2, + ECS_CHECKBOX = 0x4, + ECS_CHECKED = 0x8, + ECS_RADIOCHECK = 0x10 +}; + +typedef DWORD EXPCMDSTATE; + +/* [v1_enum] */ +enum _EXPCMDFLAGS +{ + ECF_DEFAULT = 0, + ECF_HASSUBCOMMANDS = 0x1, + ECF_HASSPLITBUTTON = 0x2, + ECF_HIDELABEL = 0x4, + ECF_ISSEPARATOR = 0x8, + ECF_HASLUASHIELD = 0x10, + ECF_SEPARATORBEFORE = 0x20, + ECF_SEPARATORAFTER = 0x40, + ECF_ISDROPDOWN = 0x80, + ECF_TOGGLEABLE = 0x100, + ECF_AUTOMENUICONS = 0x200 +}; +typedef DWORD EXPCMDFLAGS; + + +// MIDL_INTERFACE("a08ce4d0-fa25-44ab-b57c-c7b1c323e0b9") +DEFINE_GUID(IID_IExplorerCommand, 0xa08ce4d0, 0xfa25, 0x44ab, 0xb5, 0x7c, 0xc7, 0xb1, 0xc3, 0x23, 0xe0, 0xb9); + +struct IExplorerCommand : public IUnknown +{ + STDMETHOD (GetTitle) (IShellItemArray *psiItemArray, LPWSTR *ppszName) = 0; + STDMETHOD (GetIcon) (IShellItemArray *psiItemArray, LPWSTR *ppszIcon) = 0; + STDMETHOD (GetToolTip) (IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) = 0; + STDMETHOD (GetCanonicalName) (GUID *pguidCommandName) = 0; + STDMETHOD (GetState) (IShellItemArray *psiItemArray, BOOL fOkToBeSlow, EXPCMDSTATE *pCmdState) = 0; + STDMETHOD (Invoke) (IShellItemArray *psiItemArray, IBindCtx *pbc) = 0; + STDMETHOD (GetFlags) (EXPCMDFLAGS *pFlags) = 0; + STDMETHOD (EnumSubCommands) (IEnumExplorerCommand **ppEnum) = 0; +}; + +#endif // IShellItemArray +#endif // __IEnumExplorerCommand_INTERFACE_DEFINED__ +#endif // USE_SYS_shobjidl_core + +#endif // __MY_EXPLORER_COMMAND_H diff --git a/CPP/7zip/UI/Explorer/makefile b/CPP/7zip/UI/Explorer/makefile index 541122ab..1e79cc82 100644 --- a/CPP/7zip/UI/Explorer/makefile +++ b/CPP/7zip/UI/Explorer/makefile @@ -65,6 +65,7 @@ FM_OBJS = \ $O\HelpUtils.obj \ $O\LangUtils.obj \ $O\ProgramLocation.obj \ + $O\PropertyName.obj \ $O\RegistryUtils.obj \ C_OBJS = \ diff --git a/CPP/7zip/UI/Explorer/resource.rc b/CPP/7zip/UI/Explorer/resource.rc index 80018b45..66592908 100644 --- a/CPP/7zip/UI/Explorer/resource.rc +++ b/CPP/7zip/UI/Explorer/resource.rc @@ -6,3 +6,5 @@ MY_VERSION_INFO_DLL("7-Zip Shell Extension", "7-zip") #ifndef UNDER_CE 1 24 MOVEABLE PURE "7-zip.dll.manifest" #endif + +IDI_ICON ICON "..\FileManager\FM.ico" diff --git a/CPP/7zip/UI/Far/ExtractEngine.cpp b/CPP/7zip/UI/Far/ExtractEngine.cpp index e6fe2d01..ab5c0def 100644 --- a/CPP/7zip/UI/Far/ExtractEngine.cpp +++ b/CPP/7zip/UI/Far/ExtractEngine.cpp @@ -130,6 +130,7 @@ STDMETHODIMP CExtractCallbackImp::AskOverwrite( static const char * const kTestString = "Testing"; static const char * const kExtractString = "Extracting"; static const char * const kSkipString = "Skipping"; +static const char * const kReadString = "Reading"; STDMETHODIMP CExtractCallbackImp::PrepareOperation(const wchar_t *name, Int32 /* isFolder */, Int32 askExtractMode, const UInt64 * /* position */) { @@ -143,6 +144,7 @@ STDMETHODIMP CExtractCallbackImp::PrepareOperation(const wchar_t *name, Int32 /* case NArchive::NExtract::NAskMode::kExtract: s = kExtractString; break; case NArchive::NExtract::NAskMode::kTest: s = kTestString; break; case NArchive::NExtract::NAskMode::kSkip: s = kSkipString; break; + case NArchive::NExtract::NAskMode::kReadExternal: s = kReadString; break; default: s = "???"; // return E_FAIL; }; diff --git a/CPP/7zip/UI/Far/Far.dsp b/CPP/7zip/UI/Far/Far.dsp index b32ae6fa..bd6d8fd4 100644 --- a/CPP/7zip/UI/Far/Far.dsp +++ b/CPP/7zip/UI/Far/Far.dsp @@ -118,6 +118,14 @@ SOURCE=..\..\..\Common\CRC.cpp # End Source File # Begin Source File +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + SOURCE=..\..\..\Common\IntToString.cpp # End Source File # Begin Source File @@ -430,6 +438,14 @@ SOURCE=..\Common\HandlerLoader.h # End Source File # Begin Source File +SOURCE=..\Common\HashCalc.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\HashCalc.h +# End Source File +# Begin Source File + SOURCE=..\Common\LoadCodecs.cpp # End Source File # Begin Source File @@ -622,6 +638,14 @@ SOURCE=..\..\Common\LimitedStreams.h # End Source File # Begin Source File +SOURCE=..\..\Common\MethodProps.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.h +# End Source File +# Begin Source File + SOURCE=..\..\Common\ProgressUtils.cpp # End Source File # Begin Source File @@ -712,6 +736,14 @@ SOURCE=..\..\..\..\C\Threads.h # PROP Default_Filter "" # Begin Source File +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp # End Source File # Begin Source File diff --git a/CPP/7zip/UI/Far/Plugin.cpp b/CPP/7zip/UI/Far/Plugin.cpp index 92b62369..8dc1375a 100644 --- a/CPP/7zip/UI/Far/Plugin.cpp +++ b/CPP/7zip/UI/Far/Plugin.cpp @@ -686,9 +686,14 @@ struct CArchiveItemProperty VARTYPE Type; }; -static inline char GetHex(Byte value) +static inline char GetHex_Upper(unsigned v) { - return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); + return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10))); +} + +static inline char GetHex_Lower(unsigned v) +{ + return (char)((v < 10) ? ('0' + v) : ('a' + (v - 10))); } HRESULT CPlugin::ShowAttributesWindow() @@ -810,11 +815,21 @@ HRESULT CPlugin::ShowAttributesWindow() } else { + const bool needUpper = (dataSize <= 8) + && (property.ID == kpidCRC || property.ID == kpidChecksum); for (UInt32 k = 0; k < dataSize; k++) { - Byte b = ((const Byte *)data)[k]; - s += GetHex((Byte)((b >> 4) & 0xF)); - s += GetHex((Byte)(b & 0xF)); + unsigned b = ((const Byte *)data)[k]; + if (needUpper) + { + s += GetHex_Upper((b >> 4) & 0xF); + s += GetHex_Upper(b & 0xF); + } + else + { + s += GetHex_Lower((b >> 4) & 0xF); + s += GetHex_Lower(b & 0xF); + } } } } diff --git a/CPP/7zip/UI/Far/PluginDelete.cpp b/CPP/7zip/UI/Far/PluginDelete.cpp index 0d19c6e7..939a3558 100644 --- a/CPP/7zip/UI/Far/PluginDelete.cpp +++ b/CPP/7zip/UI/Far/PluginDelete.cpp @@ -17,7 +17,7 @@ int CPlugin::DeleteFiles(PluginPanelItem *panelItems, int numItems, int opMode) { if (numItems == 0) return FALSE; - if (_agent->IsThereReadOnlyArc()) + if (_agent->IsThere_ReadOnlyArc()) { g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); return FALSE; diff --git a/CPP/7zip/UI/Far/PluginRead.cpp b/CPP/7zip/UI/Far/PluginRead.cpp index 9df4a09f..70e7e141 100644 --- a/CPP/7zip/UI/Far/PluginRead.cpp +++ b/CPP/7zip/UI/Far/PluginRead.cpp @@ -37,6 +37,12 @@ HRESULT CPlugin::ExtractFiles( const UString &destPath, bool passwordIsDefined, const UString &password) { + if (_agent->_isHashHandler) + { + g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported); + return NFileOperationReturnCode::kError; + } + CScreenRestorer screenRestorer; CProgressBox progressBox; CProgressBox *progressBoxPointer = NULL; diff --git a/CPP/7zip/UI/Far/PluginWrite.cpp b/CPP/7zip/UI/Far/PluginWrite.cpp index bf1d13df..8a76bb4e 100644 --- a/CPP/7zip/UI/Far/PluginWrite.cpp +++ b/CPP/7zip/UI/Far/PluginWrite.cpp @@ -81,18 +81,17 @@ NFileOperationReturnCode::EEnum CPlugin::PutFiles( struct PluginPanelItem *panelItems, int numItems, int moveMode, int opMode) { - /* - if (moveMode != 0) + if (moveMode != 0 + && _agent->_isHashHandler) { g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported); return NFileOperationReturnCode::kError; } - */ if (numItems <= 0) return NFileOperationReturnCode::kError; - if (_agent->IsThereReadOnlyArc()) + if (_agent->IsThere_ReadOnlyArc()) { g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); return NFileOperationReturnCode::kError; @@ -231,8 +230,11 @@ NFileOperationReturnCode::EEnum CPlugin::PutFiles( updateCallbackSpec->PasswordIsDefined = PasswordIsDefined; updateCallbackSpec->Password = Password; - if (SetOutProperties(outArchive, compressionInfo.Level) != S_OK) - return NFileOperationReturnCode::kError; + if (!_agent->_isHashHandler) + { + if (SetOutProperties(outArchive, compressionInfo.Level) != S_OK) + return NFileOperationReturnCode::kError; + } /* outArchive->SetFolder(_folder); @@ -726,7 +728,7 @@ static const char * const k_CreateFolder_History = "NewFolder"; // we use defaul HRESULT CPlugin::CreateFolder() { - if (_agent->IsThereReadOnlyArc()) + if (_agent->IsThere_ReadOnlyArc()) { g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); return TRUE; diff --git a/CPP/7zip/UI/Far/makefile b/CPP/7zip/UI/Far/makefile index 14be13d6..0db22749 100644 --- a/CPP/7zip/UI/Far/makefile +++ b/CPP/7zip/UI/Far/makefile @@ -22,6 +22,7 @@ CURRENT_OBJS = \ $O\UpdateCallbackFar.obj \ COMMON_OBJS = \ + $O\DynLimBuf.obj \ $O\IntToString.obj \ $O\NewHandler.obj \ $O\MyString.obj \ @@ -52,6 +53,7 @@ WIN_OBJS = \ $O\FileStreams.obj \ $O\FilterCoder.obj \ $O\LimitedStreams.obj \ + $O\MethodProps.obj \ $O\ProgressUtils.obj \ $O\PropId.obj \ $O\StreamObjects.obj \ @@ -64,6 +66,7 @@ UI_COMMON_OBJS = \ $O\DefaultName.obj \ $O\EnumDirItems.obj \ $O\ExtractingFilePath.obj \ + $O\HashCalc.obj \ $O\LoadCodecs.obj \ $O\OpenArchive.obj \ $O\PropIDUtils.obj \ @@ -77,6 +80,7 @@ UI_COMMON_OBJS = \ $O\ZipRegistry.obj \ AR_COMMON_OBJS = \ + $O\ItemNameUtils.obj \ $O\OutStreamWithCRC.obj \ AGENT_OBJS = \ diff --git a/CPP/7zip/UI/FileManager/ClassDefs.cpp b/CPP/7zip/UI/FileManager/ClassDefs.cpp index 33197fc3..5c269043 100644 --- a/CPP/7zip/UI/FileManager/ClassDefs.cpp +++ b/CPP/7zip/UI/FileManager/ClassDefs.cpp @@ -9,3 +9,4 @@ #include "../Agent/Agent.h" #include "MyWindowsNew.h" +#include "../Explorer/MyExplorerCommand.h" diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.cpp b/CPP/7zip/UI/FileManager/ExtractCallback.cpp index 0e285f04..232717f8 100644 --- a/CPP/7zip/UI/FileManager/ExtractCallback.cpp +++ b/CPP/7zip/UI/FileManager/ExtractCallback.cpp @@ -44,6 +44,7 @@ void CExtractCallbackImp::Init() _lang_Extracting = LangString(IDS_PROGRESS_EXTRACTING); _lang_Testing = LangString(IDS_PROGRESS_TESTING); _lang_Skipping = LangString(IDS_PROGRESS_SKIPPING); + _lang_Reading = "Reading"; NumArchiveErrors = 0; ThereAreMessageErrors = false; @@ -233,6 +234,7 @@ STDMETHODIMP CExtractCallbackImp::PrepareOperation(const wchar_t *name, Int32 is case NArchive::NExtract::NAskMode::kExtract: msg = &_lang_Extracting; break; case NArchive::NExtract::NAskMode::kTest: msg = &_lang_Testing; break; case NArchive::NExtract::NAskMode::kSkip: msg = &_lang_Skipping; break; + case NArchive::NExtract::NAskMode::kReadExternal: msg = &_lang_Reading; break; // default: s = "Unknown operation"; } @@ -911,8 +913,10 @@ STDMETHODIMP CExtractCallbackImp::PrepareOperation7(Int32 askExtractMode) { COM_TRY_BEGIN _needUpdateStat = ( - askExtractMode == NArchive::NExtract::NAskMode::kExtract || - askExtractMode == NArchive::NExtract::NAskMode::kTest); + askExtractMode == NArchive::NExtract::NAskMode::kExtract + || askExtractMode == NArchive::NExtract::NAskMode::kTest + || askExtractMode == NArchive::NExtract::NAskMode::kReadExternal + ); /* _extractMode = false; @@ -930,7 +934,7 @@ STDMETHODIMP CExtractCallbackImp::PrepareOperation7(Int32 askExtractMode) COM_TRY_END } -STDMETHODIMP CExtractCallbackImp::SetOperationResult7(Int32 opRes, Int32 encrypted) +STDMETHODIMP CExtractCallbackImp::SetOperationResult8(Int32 opRes, Int32 encrypted, UInt64 size) { COM_TRY_BEGIN if (VirtFileSystem && _newVirtFileWasAdded) @@ -950,7 +954,7 @@ STDMETHODIMP CExtractCallbackImp::SetOperationResult7(Int32 opRes, Int32 encrypt } else if (_hashCalc && _needUpdateStat) { - _hashCalc->SetSize(_curSize); + _hashCalc->SetSize(size); // (_curSize) before 21.04 _hashCalc->Final(_isFolder, _isAltStream, _filePath); } return SetOperationResult(opRes, encrypted); diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.h b/CPP/7zip/UI/FileManager/ExtractCallback.h index 297492eb..02578bb4 100644 --- a/CPP/7zip/UI/FileManager/ExtractCallback.h +++ b/CPP/7zip/UI/FileManager/ExtractCallback.h @@ -282,6 +282,7 @@ public: UString _lang_Extracting; UString _lang_Testing; UString _lang_Skipping; + UString _lang_Reading; UString _lang_Empty; bool _totalFilesDefined; diff --git a/CPP/7zip/UI/FileManager/FM.dsp b/CPP/7zip/UI/FileManager/FM.dsp index d87beff5..a12d3307 100644 --- a/CPP/7zip/UI/FileManager/FM.dsp +++ b/CPP/7zip/UI/FileManager/FM.dsp @@ -1076,6 +1076,14 @@ SOURCE=..\..\..\Common\DynamicBuffer.h # End Source File # Begin Source File +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + SOURCE=..\..\..\Common\Exception.h # End Source File # Begin Source File @@ -1419,6 +1427,10 @@ SOURCE=..\Explorer\ContextMenuFlags.h # End Source File # Begin Source File +SOURCE=..\Explorer\MyExplorerCommand.h +# End Source File +# Begin Source File + SOURCE=..\Explorer\RegistryContextMenu.cpp # End Source File # Begin Source File @@ -1491,6 +1503,18 @@ SOURCE=..\..\IStream.h SOURCE=..\..\PropID.h # End Source File # End Group +# Begin Group "ArchiveCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# End Group # Begin Source File SOURCE=.\7zFM.exe.manifest diff --git a/CPP/7zip/UI/FileManager/ListViewDialog.rc b/CPP/7zip/UI/FileManager/ListViewDialog.rc index 961d224a..4343b755 100644 --- a/CPP/7zip/UI/FileManager/ListViewDialog.rc +++ b/CPP/7zip/UI/FileManager/ListViewDialog.rc @@ -1,7 +1,7 @@ #include "ListViewDialogRes.h" #include "../../GuiCommon.rc" -#define xc 440 +#define xc 480 #define yc 320 IDD_LISTVIEW DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT diff --git a/CPP/7zip/UI/FileManager/MenuPage.cpp b/CPP/7zip/UI/FileManager/MenuPage.cpp index ac3a7b14..05f24d71 100644 --- a/CPP/7zip/UI/FileManager/MenuPage.cpp +++ b/CPP/7zip/UI/FileManager/MenuPage.cpp @@ -63,7 +63,8 @@ static const CContextMenuItem kMenuItems[] = { IDS_CONTEXT_COMPRESS_TO_EMAIL, kCompressToZipEmail }, #endif - { IDS_PROP_CHECKSUM, kCRC } + { IDS_PROP_CHECKSUM, kCRC }, + { IDS_PROP_CHECKSUM, kCRC_Cascaded }, }; @@ -188,8 +189,11 @@ bool CMenuPage::OnInit() UString s = LangString(menuItem.ControlID); if (menuItem.Flag == kCRC) s = "CRC SHA"; - if (menuItem.Flag == kOpenAs || - menuItem.Flag == kCRC) + else if (menuItem.Flag == kCRC_Cascaded) + s = "7-Zip > CRC SHA"; + if (menuItem.Flag == kOpenAs + || menuItem.Flag == kCRC + || menuItem.Flag == kCRC_Cascaded) s += " >"; switch (menuItem.ControlID) diff --git a/CPP/7zip/UI/FileManager/MenuPage.rc b/CPP/7zip/UI/FileManager/MenuPage.rc index dd32898f..fc211074 100644 --- a/CPP/7zip/UI/FileManager/MenuPage.rc +++ b/CPP/7zip/UI/FileManager/MenuPage.rc @@ -2,7 +2,7 @@ #include "../../GuiCommon.rc" #define xc 240 -#define yc 224 +#define yc 252 IDD_MENU MY_PAGE #include "MenuPage2.rc" diff --git a/CPP/7zip/UI/FileManager/MyCom2.h b/CPP/7zip/UI/FileManager/MyCom2.h index 224a838d..c45c2155 100644 --- a/CPP/7zip/UI/FileManager/MyCom2.h +++ b/CPP/7zip/UI/FileManager/MyCom2.h @@ -36,4 +36,12 @@ STDMETHOD_(ULONG, Release)() { InterlockedDecrement((LONG *)&__m_RefCount); if ( MY_QUERYINTERFACE_ENTRY(i3) \ ) +#define MY_UNKNOWN_IMP4_MT(i1, i2, i3, i4) MY_UNKNOWN_IMP_SPEC_MT2( \ + i1, \ + MY_QUERYINTERFACE_ENTRY(i1) \ + MY_QUERYINTERFACE_ENTRY(i2) \ + MY_QUERYINTERFACE_ENTRY(i3) \ + MY_QUERYINTERFACE_ENTRY(i4) \ + ) + #endif diff --git a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp index a133a291..63167d63 100644 --- a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp +++ b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp @@ -536,6 +536,31 @@ void CFileMenu::Load(HMENU hMenu, unsigned startPos) disable = true; } } + + if (isHashFolder) + { + switch (item.wID) + { + case IDM_OPEN: + case IDM_OPEN_INSIDE: + case IDM_OPEN_INSIDE_ONE: + case IDM_OPEN_INSIDE_PARSER: + case IDM_OPEN_OUTSIDE: + case IDM_FILE_VIEW: + case IDM_FILE_EDIT: + // case IDM_RENAME: + case IDM_COPY_TO: + case IDM_MOVE_TO: + // case IDM_DELETE: + case IDM_COMMENT: + case IDM_CREATE_FOLDER: + case IDM_CREATE_FILE: + case IDM_LINK: + case IDM_DIFF: + disable = true; + } + } + if (item.wID == IDM_LINK && numItems != 1) disable = true; diff --git a/CPP/7zip/UI/FileManager/MyLoadMenu.h b/CPP/7zip/UI/FileManager/MyLoadMenu.h index 0a38a732..764bf7c7 100644 --- a/CPP/7zip/UI/FileManager/MyLoadMenu.h +++ b/CPP/7zip/UI/FileManager/MyLoadMenu.h @@ -14,16 +14,18 @@ struct CFileMenu { bool programMenu; bool readOnly; + bool isHashFolder; bool isFsFolder; bool allAreFiles; bool isAltStreamsSupported; int numItems; - UString FilePath; + FString FilePath; CFileMenu(): programMenu(false), readOnly(false), + isHashFolder(false), isFsFolder(false), allAreFiles(false), isAltStreamsSupported(true), diff --git a/CPP/7zip/UI/FileManager/Panel.cpp b/CPP/7zip/UI/FileManager/Panel.cpp index 6702fa9c..e8c0b947 100644 --- a/CPP/7zip/UI/FileManager/Panel.cpp +++ b/CPP/7zip/UI/FileManager/Panel.cpp @@ -797,6 +797,18 @@ bool CPanel::IsArcFolder() const return GetFolderTypeID().IsPrefixedBy_Ascii_NoCase("7-Zip"); } +bool CPanel::IsHashFolder() const +{ + if (_folder) + { + NCOM::CPropVariant prop; + if (_folder->GetFolderProperty(kpidIsHash, &prop) == S_OK) + if (prop.vt == VT_BOOL) + return VARIANT_BOOLToBool(prop.boolVal); + } + return false; +} + UString CPanel::GetFsPath() const { if (IsFSDrivesFolder() && !IsDeviceDrivesPrefix() && !IsSuperDrivesPrefix()) diff --git a/CPP/7zip/UI/FileManager/Panel.h b/CPP/7zip/UI/FileManager/Panel.h index f39d94e2..d1e4d244 100644 --- a/CPP/7zip/UI/FileManager/Panel.h +++ b/CPP/7zip/UI/FileManager/Panel.h @@ -647,6 +647,7 @@ public: bool IsFSDrivesFolder() const; bool IsAltStreamsFolder() const; bool IsArcFolder() const; + bool IsHashFolder() const; /* c:\Dir diff --git a/CPP/7zip/UI/FileManager/PanelCopy.cpp b/CPP/7zip/UI/FileManager/PanelCopy.cpp index e1bd0117..7e1937c9 100644 --- a/CPP/7zip/UI/FileManager/PanelCopy.cpp +++ b/CPP/7zip/UI/FileManager/PanelCopy.cpp @@ -126,6 +126,12 @@ HRESULT CPanel::CopyTo(CCopyToOptions &options, const CRecordVector<UInt32> &ind UStringVector *messages, bool &usePassword, UString &password) { + if (IsHashFolder()) + { + if (!options.testMode) + return E_NOTIMPL; + } + if (!_folderOperations) { UString errorMessage = LangString(IDS_OPERATION_IS_NOT_SUPPORTED); @@ -290,6 +296,11 @@ struct CThreadUpdate HRESULT CPanel::CopyFrom(bool moveMode, const UString &folderPrefix, const UStringVector &filePaths, bool showErrorMessages, UStringVector *messages) { + if (IsHashFolder()) + { + if (moveMode) + return E_NOTIMPL; + } // CDisableNotify disableNotify(*this); HRESULT res; diff --git a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp index 68fe7b02..ba54491d 100644 --- a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp +++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp @@ -1566,6 +1566,10 @@ tryInternal tryExternal void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bool editMode, bool useEditor, const wchar_t *type) { + // we don't want to change hash data here + if (IsHashFolder()) + return; + const UString name = GetItemName(index); const UString relPath = GetItemRelPath(index); @@ -1793,6 +1797,8 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo tpi->UsePassword = usePassword; tpi->Password = password; tpi->ReadOnly = IsThereReadOnlyFolder(); + if (IsHashFolder()) + tpi->ReadOnly = true; if (!tpi->FileInfo.Find(tempFilePath)) return; diff --git a/CPP/7zip/UI/FileManager/PanelListNotify.cpp b/CPP/7zip/UI/FileManager/PanelListNotify.cpp index 12f471b3..d2114f1c 100644 --- a/CPP/7zip/UI/FileManager/PanelListNotify.cpp +++ b/CPP/7zip/UI/FileManager/PanelListNotify.cpp @@ -92,11 +92,16 @@ UString ConvertSizeToString(UInt64 value) return s; } -static inline unsigned GetHex(unsigned v) +static inline unsigned GetHex_Upper(unsigned v) { return (v < 10) ? ('0' + v) : ('A' + (v - 10)); } +static inline unsigned GetHex_Lower(unsigned v) +{ + return (v < 10) ? ('0' + v) : ('a' + (v - 10)); +} + /* static void HexToString(char *dest, const Byte *data, UInt32 size) { @@ -350,11 +355,21 @@ LRESULT CPanel::SetItemText(LVITEMW &item) if (dataSize > limit) dataSize = limit; WCHAR *dest = text; + const bool needUpper = (dataSize <= 8) + && (propID == kpidCRC || propID == kpidChecksum); for (UInt32 i = 0; i < dataSize; i++) { unsigned b = ((const Byte *)data)[i]; - dest[0] = (WCHAR)GetHex((b >> 4) & 0xF); - dest[1] = (WCHAR)GetHex(b & 0xF); + if (needUpper) + { + dest[0] = (WCHAR)GetHex_Upper((b >> 4) & 0xF); + dest[1] = (WCHAR)GetHex_Upper(b & 0xF); + } + else + { + dest[0] = (WCHAR)GetHex_Lower((b >> 4) & 0xF); + dest[1] = (WCHAR)GetHex_Lower(b & 0xF); + } dest += 2; } *dest = 0; diff --git a/CPP/7zip/UI/FileManager/PanelMenu.cpp b/CPP/7zip/UI/FileManager/PanelMenu.cpp index 7a88f8f2..99a76cfa 100644 --- a/CPP/7zip/UI/FileManager/PanelMenu.cpp +++ b/CPP/7zip/UI/FileManager/PanelMenu.cpp @@ -133,9 +133,14 @@ static void AddPropertyString(PROPID propID, UInt64 val, CListViewDialog &dialog } -static inline char GetHex(Byte value) +static inline unsigned GetHex_Upper(unsigned v) { - return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); + return (v < 10) ? ('0' + v) : ('A' + (v - 10)); +} + +static inline unsigned GetHex_Lower(unsigned v) +{ + return (v < 10) ? ('0' + v) : ('a' + (v - 10)); } static const Byte kSpecProps[] = @@ -225,11 +230,21 @@ void CPanel::Properties() } else { + const bool needUpper = (dataSize <= 8) + && (propID == kpidCRC || propID == kpidChecksum); for (UInt32 k = 0; k < dataSize; k++) { - Byte b = ((const Byte *)data)[k]; - s += GetHex((Byte)((b >> 4) & 0xF)); - s += GetHex((Byte)(b & 0xF)); + const Byte b = ((const Byte *)data)[k]; + if (needUpper) + { + s += (char)GetHex_Upper((b >> 4) & 0xF); + s += (char)GetHex_Upper(b & 0xF); + } + else + { + s += (char)GetHex_Lower((b >> 4) & 0xF); + s += (char)GetHex_Lower(b & 0xF); + } } } } @@ -931,6 +946,7 @@ void CPanel::CreateFileMenu(HMENU menuSpec, CFileMenu fm; fm.readOnly = IsThereReadOnlyFolder(); + fm.isHashFolder = IsHashFolder(); fm.isFsFolder = Is_IO_FS_Folder(); fm.programMenu = programMenu; fm.allAreFiles = allAreFiles; @@ -939,7 +955,7 @@ void CPanel::CreateFileMenu(HMENU menuSpec, fm.isAltStreamsSupported = false; if (fm.numItems == 1) - fm.FilePath = GetItemFullPath(operatedIndices[0]); + fm.FilePath = us2fs(GetItemFullPath(operatedIndices[0])); if (_folderAltStreams) { diff --git a/CPP/7zip/UI/FileManager/PanelOperations.cpp b/CPP/7zip/UI/FileManager/PanelOperations.cpp index d3e2e978..6c59ea38 100644 --- a/CPP/7zip/UI/FileManager/PanelOperations.cpp +++ b/CPP/7zip/UI/FileManager/PanelOperations.cpp @@ -355,6 +355,9 @@ bool Dlg_CreateFolder(HWND wnd, UString &destName); void CPanel::CreateFolder() { + if (IsHashFolder()) + return; + if (!CheckBeforeUpdate(IDS_CREATE_FOLDER_ERROR)) return; @@ -415,6 +418,9 @@ void CPanel::CreateFolder() void CPanel::CreateFile() { + if (IsHashFolder()) + return; + if (!CheckBeforeUpdate(IDS_CREATE_FILE_ERROR)) return; @@ -473,6 +479,8 @@ void CPanel::RenameFile() void CPanel::ChangeComment() { + if (IsHashFolder()) + return; if (!CheckBeforeUpdate(IDS_COMMENT)) return; CDisableTimerProcessing disableTimerProcessing2(*this); diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.cpp b/CPP/7zip/UI/FileManager/ProgressDialog2.cpp index 7b132468..54273d0c 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog2.cpp +++ b/CPP/7zip/UI/FileManager/ProgressDialog2.cpp @@ -5,7 +5,7 @@ #include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" -#include "../../../Windows/Control/Static.h" +#include "../../../Windows/Clipboard.h" #include "../../../Windows/ErrorMsg.h" #include "../GUI/ExtractRes.h" @@ -239,7 +239,7 @@ void CProgressSync::AddError_Code_Name(DWORD systemError, const wchar_t *name) CProgressDialog::CProgressDialog(): _timer(0), CompressingMode(true), - MainWindow(0) + MainWindow(NULL) { _isDir = false; @@ -280,7 +280,7 @@ CProgressDialog::~CProgressDialog() } void CProgressDialog::AddToTitle(LPCWSTR s) { - if (MainWindow != 0) + if (MainWindow) { CWindow window(MainWindow); window.SetText((UString)s + MainTitle); @@ -357,6 +357,7 @@ bool CProgressDialog::OnInit() m_ProgressBar.Attach(GetItem(IDC_PROGRESS1)); _messageList.Attach(GetItem(IDL_PROGRESS_MESSAGES)); _messageList.SetUnicodeFormat(); + _messageList.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT); _wasCreated = true; _dialogCreatedEvent.Set(); @@ -1046,6 +1047,8 @@ bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) } if (_inCancelMessageBox) { + /* if user is in MessageBox(), we will call OnExternalCloseMessage() + later, when MessageBox() will be closed */ _externalCloseMessageWasReceived = true; break; } @@ -1142,13 +1145,16 @@ void CProgressDialog::OnPriorityButton() void CProgressDialog::AddMessageDirect(LPCWSTR message, bool needNumber) { - int itemIndex = _messageList.GetItemCount(); wchar_t sz[16]; sz[0] = 0; if (needNumber) ConvertUInt32ToString(_numMessages + 1, sz); - _messageList.InsertItem(itemIndex, sz); - _messageList.SetSubItem(itemIndex, 1, message); + const unsigned itemIndex = _messageStrings.Size(); // _messageList.GetItemCount(); + if (_messageList.InsertItem((int)itemIndex, sz) == (int)itemIndex) + { + _messageList.SetSubItem((int)itemIndex, 1, message); + _messageStrings.Add(message); + } } void CProgressDialog::AddMessage(LPCWSTR message) @@ -1217,24 +1223,42 @@ bool CProgressDialog::OnButtonClicked(int buttonID, HWND buttonHWND) End(IDCLOSE); break; } + + if (_cancelWasPressed) + return true; - bool paused = Sync.Get_Paused(); + const bool paused = Sync.Get_Paused(); + if (!paused) + { OnPauseButton(); + } + _inCancelMessageBox = true; - int res = ::MessageBoxW(*this, LangString(IDS_PROGRESS_ASK_CANCEL), _title, MB_YESNOCANCEL); + const int res = ::MessageBoxW(*this, LangString(IDS_PROGRESS_ASK_CANCEL), _title, MB_YESNOCANCEL); _inCancelMessageBox = false; + if (res == IDYES) + _cancelWasPressed = true; + if (!paused) + { OnPauseButton(); - if (res == IDCANCEL || res == IDNO) + } + + if (_externalCloseMessageWasReceived) { - if (_externalCloseMessageWasReceived) - OnExternalCloseMessage(); + /* we have received kCloseMessage while we were in MessageBoxW(). + so we call OnExternalCloseMessage() here. + it can show MessageBox and it can close dialog */ + OnExternalCloseMessage(); return true; } - _cancelWasPressed = true; + if (!_cancelWasPressed) + return true; + MessagesDisplayed = true; + // we will call Sync.Set_Stopped(true) in OnButtonClicked() : OnCancel() break; } @@ -1270,6 +1294,87 @@ void CProgressDialog::ProcessWasFinished() } +bool CProgressDialog::OnNotify(UINT /* controlID */, LPNMHDR header) +{ + if (header->hwndFrom != _messageList) + return false; + switch (header->code) + { + case LVN_KEYDOWN: + { + LPNMLVKEYDOWN keyDownInfo = LPNMLVKEYDOWN(header); + switch (keyDownInfo->wVKey) + { + case 'A': + { + if (IsKeyDown(VK_CONTROL)) + { + _messageList.SelectAll(); + return true; + } + break; + } + case VK_INSERT: + case 'C': + { + if (IsKeyDown(VK_CONTROL)) + { + CopyToClipboard(); + return true; + } + break; + } + } + } + } + return false; +} + + +static void ListView_GetSelected(NControl::CListView &listView, CUIntVector &vector) +{ + vector.Clear(); + int index = -1; + for (;;) + { + index = listView.GetNextSelectedItem(index); + if (index < 0) + break; + vector.Add(index); + } +} + + +void CProgressDialog::CopyToClipboard() +{ + CUIntVector indexes; + ListView_GetSelected(_messageList, indexes); + UString s; + unsigned numIndexes = indexes.Size(); + if (numIndexes == 0) + numIndexes = _messageList.GetItemCount(); + + for (unsigned i = 0; i < numIndexes; i++) + { + const unsigned index = (i < indexes.Size() ? indexes[i] : i); + // s.Add_UInt32(index); + // s += ": "; + s += _messageStrings[index]; + { + s += + #ifdef _WIN32 + "\r\n" + #else + "\n" + #endif + ; + } + } + + ClipboardSetText(*this, s); +} + + static THREAD_FUNC_DECL MyThreadFunction(void *param) { CProgressThreadVirt *p = (CProgressThreadVirt *)param; diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.h b/CPP/7zip/UI/FileManager/ProgressDialog2.h index c17dd395..d8259d6a 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog2.h +++ b/CPP/7zip/UI/FileManager/ProgressDialog2.h @@ -152,6 +152,7 @@ class CProgressDialog: public NWindows::NControl::CModalDialog NWindows::NControl::CListView _messageList; int _numMessages; + UStringVector _messageStrings; #ifdef __ITaskbarList3_INTERFACE_DEFINED__ CMyComPtr<ITaskbarList3> _taskbarList; @@ -212,6 +213,9 @@ class CProgressDialog: public NWindows::NControl::CModalDialog virtual bool OnSize(WPARAM wParam, int xSize, int ySize); virtual void OnCancel(); virtual void OnOK(); + virtual bool OnNotify(UINT /* controlID */, LPNMHDR header); + void CopyToClipboard(); + NWindows::NSynchronization::CManualResetEvent _createDialogEvent; NWindows::NSynchronization::CManualResetEvent _dialogCreatedEvent; #ifndef _SFX diff --git a/CPP/7zip/UI/FileManager/VerCtrl.cpp b/CPP/7zip/UI/FileManager/VerCtrl.cpp index efed8468..7e53d81f 100644 --- a/CPP/7zip/UI/FileManager/VerCtrl.cpp +++ b/CPP/7zip/UI/FileManager/VerCtrl.cpp @@ -18,10 +18,10 @@ using namespace NFile; using namespace NFind; using namespace NDir; -static UString ConvertPath_to_Ctrl(const UString &path) +static FString ConvertPath_to_Ctrl(const FString &path) { - UString s = path; - s.Replace(L':', L'_'); + FString s = path; + s.Replace(FChar(':'), FChar('_')); return s; } @@ -33,11 +33,11 @@ struct CFileDataInfo CFileDataInfo(): IsOpen (false) {} UInt64 GetSize() const { return (((UInt64)Info.nFileSizeHigh) << 32) + Info.nFileSizeLow; } - bool Read(const UString &path); + bool Read(const FString &path); }; -bool CFileDataInfo::Read(const UString &path) +bool CFileDataInfo::Read(const FString &path) { IsOpen = false; NIO::CInFile file; @@ -69,7 +69,7 @@ bool CFileDataInfo::Read(const UString &path) } -static bool CreateComplexDir_for_File(const UString &path) +static bool CreateComplexDir_for_File(const FString &path) { FString resDirPrefix; FString resFileName; @@ -81,7 +81,7 @@ static bool CreateComplexDir_for_File(const UString &path) static bool ParseNumberString(const FString &s, UInt32 &number) { - const wchar_t *end; + const FChar *end; UInt64 result = ConvertStringToUInt64(s, &end); if (*end != 0 || s.IsEmpty() || result > (UInt32)0x7FFFFFFF) return false; @@ -145,7 +145,7 @@ void CApp::VerCtrl(unsigned id) return; } - const UString path = panel.GetItemFullPath(indices[0]); + const FString path = us2fs(panel.GetItemFullPath(indices[0])); UString vercPath; ReadReg_VerCtrlPath(vercPath); @@ -161,8 +161,8 @@ void CApp::VerCtrl(unsigned id) return; } - const UString dirPrefix2 = vercPath + ConvertPath_to_Ctrl(dirPrefix); - const UString path2 = dirPrefix2 + fileName; + const FString dirPrefix2 = us2fs(vercPath) + ConvertPath_to_Ctrl(dirPrefix); + const FString path2 = dirPrefix2 + fileName; bool sameTime = false; bool sameData = false; @@ -362,6 +362,6 @@ void CApp::VerCtrl(unsigned id) { if (!fdi2.IsOpen) return; - DiffFiles(path2, path); + DiffFiles(fs2us(path2), fs2us(path)); } } diff --git a/CPP/7zip/UI/FileManager/makefile b/CPP/7zip/UI/FileManager/makefile index 4525d846..dd2a2f20 100644 --- a/CPP/7zip/UI/FileManager/makefile +++ b/CPP/7zip/UI/FileManager/makefile @@ -5,6 +5,7 @@ CFLAGS = $(CFLAGS) \ !include "FM.mak" COMMON_OBJS = \ + $O\DynLimBuf.obj \ $O\IntToString.obj \ $O\Lang.obj \ $O\MyString.obj \ @@ -93,6 +94,10 @@ GUI_OBJS = \ COMPRESS_OBJS = \ $O\CopyCoder.obj \ +AR_COMMON_OBJS = \ + $O\ItemNameUtils.obj \ + + C_OBJS = $(C_OBJS) \ $O\Alloc.obj \ $O\CpuArch.obj \ diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp index 3298526e..510d1ec3 100644 --- a/CPP/7zip/UI/GUI/CompressDialog.cpp +++ b/CPP/7zip/UI/GUI/CompressDialog.cpp @@ -80,8 +80,8 @@ using namespace NDir; static const unsigned kHistorySize = 20; -static const UInt32 kNoSolidBlockSize = 0; -static const UInt32 kSolidBlockSize = 64; +static const UInt32 kSolidLog_NoSolid = 0; +static const UInt32 kSolidLog_FullSolid = 64; static const UInt32 kLzmaMaxDictSize = (UInt32)15 << 28; @@ -112,7 +112,11 @@ enum EMethodID kBZip2, kDeflate, kDeflate64, - kPPMdZip + kPPMdZip, + kSha256, + kSha1, + kCrc32, + kCrc64, }; static LPCSTR const kMethodsNames[] = @@ -125,6 +129,10 @@ static LPCSTR const kMethodsNames[] = , "Deflate" , "Deflate64" , "PPMd" + , "SHA256" + , "SHA1" + , "CRC32" + , "CRC64" }; static const EMethodID g_7zMethods[] = @@ -133,6 +141,9 @@ static const EMethodID g_7zMethods[] = kLZMA, kPPMd, kBZip2 + , kDeflate + , kDeflate64 + , kCopy }; static const EMethodID g_7zSfxMethods[] = @@ -173,12 +184,20 @@ static const EMethodID g_SwfcMethods[] = // kLZMA }; +static const EMethodID g_HashMethods[] = +{ + kSha256 + , kSha1 + // , kCrc32 + // , kCrc64 +}; + struct CFormatInfo { LPCSTR Name; UInt32 LevelsMask; unsigned NumMethods; - const EMethodID *MathodIDs; + const EMethodID *MethodIDs; bool Filter; bool Solid; bool MultiThread; @@ -194,9 +213,11 @@ static const CFormatInfo g_Formats[] = { { "", - (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + // (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + ((UInt32)1 << 10) - 1, + // (UInt32)(Int32)-1, 0, 0, - false, false, false, false, false, false + false, false, true, false, false, false }, { k7zFormat, @@ -245,6 +266,12 @@ static const CFormatInfo g_Formats[] = (1 << 0), 0, 0, false, false, false, false, false, false + }, + { + "Hash", + (0 << 0), + METHODS_PAIR(g_HashMethods), + false, false, false, false, false, false } }; @@ -256,23 +283,6 @@ static bool IsMethodSupportedBySfx(int methodID) return false; } -static bool GetMaxRamSizeForProgram(UInt64 &ramSize, UInt64 &size) -{ - size = (UInt64)(sizeof(size_t)) << 29; - bool ramSize_Defined = NSystem::GetRamSize(size); - ramSize = size; - size = size / 16 * 15; - const UInt64 kMinSysSize = (1 << 24); - if (size <= kMinSysSize) - size = 0; - else - size -= kMinSysSize; - const UInt64 kMinUseSize = (1 << 24); - if (size < kMinUseSize) - size = kMinUseSize; - return ramSize_Defined; -} - static const // NCompressDialog::NUpdateMode::EEnum @@ -327,7 +337,31 @@ void CCompressDialog::GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2) b1.Val = b2.Val = val; } - + +void CCompressDialog::SetMethods(const CObjectVector<CCodecInfoUser> &userCodecs) +{ + ExternalMethods.Clear(); + { + FOR_VECTOR (i, userCodecs) + { + const CCodecInfoUser &c = userCodecs[i]; + if (!c.EncoderIsAssigned + || !c.IsFilter_Assigned + || c.IsFilter + || c.NumStreams != 1) + continue; + unsigned k; + for (k = 0; k < ARRAY_SIZE(g_7zMethods); k++) + if (c.Name.IsEqualTo_Ascii_NoCase(kMethodsNames[g_7zMethods[k]])) + break; + if (k != ARRAY_SIZE(g_7zMethods)) + continue; + ExternalMethods.Add(c.Name); + } + } +} + + bool CCompressDialog::OnInit() { #ifdef LANG @@ -335,6 +369,28 @@ bool CCompressDialog::OnInit() LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); #endif + { + UInt64 size = (UInt64)(sizeof(size_t)) << 29; + _ramSize_Defined = NSystem::GetRamSize(size); + // size = 100 << 20; // for debug only; + _ramSize = size; + const UInt64 kMinUseSize = (1 << 26); + if (size < kMinUseSize) + size = kMinUseSize; + + _ramUsage_Limit = size / 32 * 30; // it's relaxed limit for user defined settings + + unsigned bits = sizeof(size_t) * 8; + if (bits == 32) + { + const UInt32 limit2 = (UInt32)7 << 28; + if (size > limit2) + size = limit2; + } + + _ramUsage_Auto = size / 32 * 28; // it's same as in auto usage limit in handlers + } + _password1Control.Attach(GetItem(IDE_COMPRESS_PASSWORD1)); _password2Control.Attach(GetItem(IDE_COMPRESS_PASSWORD2)); _password1Control.SetText(Info.Password); @@ -400,8 +456,6 @@ bool CCompressDialog::OnInit() StartDirPrefix = DirPrefix; SetArchiveName(fileName); } - SetLevel(); - SetParams(); for (unsigned i = 0; i < m_RegistryInfo.ArcPaths.Size() && i < kHistorySize; i++) m_ArchivePath.AddString(m_RegistryInfo.ArcPaths[i]); @@ -412,8 +466,6 @@ bool CCompressDialog::OnInit() AddComboItems(m_PathMode, k_PathMode_IDs, ARRAY_SIZE(k_PathMode_IDs), k_PathMode_Vals, Info.PathMode); - SetSolidBlockSize(); - SetNumThreads(); TCHAR s[32] = { TEXT('/'), TEXT(' '), 0 }; ConvertUInt32ToString(NSystem::GetNumberOfProcessors(), s + 2); @@ -422,13 +474,10 @@ bool CCompressDialog::OnInit() CheckButton(IDX_COMPRESS_SHARED, Info.OpenShareForWrite); CheckButton(IDX_COMPRESS_DEL, Info.DeleteAfterCompressing); - CheckControlsEnable(); + FormatChanged(); // OnButtonSFX(); - SetEncryptionMethod(); - SetMemoryUsage(); - NormalizePosition(); return CModalDialog::OnInit(); @@ -497,7 +546,7 @@ void CCompressDialog::CheckSFXControlsEnable() bool enable = fi.SFX; if (enable) { - int methodID = GetMethodID(); + const int methodID = GetMethodID(); enable = (methodID == -1 || IsMethodSupportedBySfx(methodID)); } if (!enable) @@ -515,21 +564,41 @@ void CCompressDialog::CheckVolumeEnable() } */ -void CCompressDialog::CheckControlsEnable() +void CCompressDialog::EnableMultiCombo(unsigned id) +{ + NWindows::NControl::CComboBox combo; + combo.Attach(GetItem(id)); + const bool enable = (combo.GetCount() > 1); + EnableItem(id, enable); +} + + +void CCompressDialog::FormatChanged() { + SetLevel(); + SetSolidBlockSize(); + SetParams(); + SetNumThreads(); + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; Info.SolidIsSpecified = fi.Solid; - bool multiThreadEnable = fi.MultiThread; - Info.MultiThreadIsAllowed = multiThreadEnable; Info.EncryptHeadersIsAllowed = fi.EncryptFileNames; + /* + const bool multiThreadEnable = fi.MultiThread; + Info.MultiThreadIsAllowed = multiThreadEnable; EnableItem(IDC_COMPRESS_SOLID, fi.Solid); EnableItem(IDC_COMPRESS_THREADS, multiThreadEnable); + const bool methodEnable = (fi.MethodIDs != NULL); + EnableItem(IDC_COMPRESS_METHOD, methodEnable); + EnableMultiCombo(IDC_COMPRESS_DICTIONARY, methodEnable); + EnableItem(IDC_COMPRESS_ORDER, methodEnable); + */ CheckSFXControlsEnable(); { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + const CArcInfoEx &ai = Get_ArcInfoEx(); ShowItem_Bool(IDX_COMPRESS_NT_SYM_LINKS, ai.Flags_SymLinks()); ShowItem_Bool(IDX_COMPRESS_NT_HARD_LINKS, ai.Flags_HardLinks()); @@ -557,8 +626,12 @@ void CCompressDialog::CheckControlsEnable() EnableItem(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames); ShowItem_Bool(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames); + + SetEncryptionMethod(); + SetMemoryUsage(); } + bool CCompressDialog::IsSFX() { CWindow sfxButton = GetItem(IDX_COMPRESS_SFX); @@ -765,18 +838,16 @@ void CCompressDialog::OnOK() } { - UInt64 ramSize; - UInt64 maxRamSize; - const bool maxRamSize_Defined = GetMaxRamSizeForProgram(ramSize, maxRamSize); UInt64 decompressMem; const UInt64 memUsage = GetMemoryUsage_DecompMem(decompressMem); - if (maxRamSize_Defined && memUsage > maxRamSize) + if (memUsage != (UInt64)(Int64)-1) + if (_ramSize_Defined && memUsage > _ramUsage_Limit) { UString s; UString s2 = LangString(IDT_COMPRESS_MEMORY); if (s2.IsEmpty()) GetItemText(IDT_COMPRESS_MEMORY, s2); - SetErrorMessage_MemUsage(s, memUsage, ramSize, maxRamSize, s2); + SetErrorMessage_MemUsage(s, memUsage, _ramSize, _ramUsage_Limit, s2); MessageBoxError(s); return; } @@ -807,7 +878,7 @@ void CCompressDialog::OnOK() { // Info.SolidIsSpecified = g_Formats[GetStaticFormatIndex()].Solid; - UInt32 solidLogSize = GetBlockSizeSpec(); + const UInt32 solidLogSize = GetBlockSizeSpec(); Info.SolidBlockSize = 0; if (solidLogSize == (UInt32)(Int32)-1) Info.SolidIsSpecified = false; @@ -834,7 +905,7 @@ void CCompressDialog::OnOK() GetButton_Bools(IDX_COMPRESS_NT_SECUR, Info.NtSecurity, m_RegistryInfo.NtSecurity); { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + const CArcInfoEx &ai = Get_ArcInfoEx(); if (!ai.Flags_SymLinks()) Info.SymLinks.Val = false; if (!ai.Flags_HardLinks()) Info.HardLinks.Val = false; if (!ai.Flags_AltStreams()) Info.AltStreams.Val = false; @@ -924,28 +995,16 @@ bool CCompressDialog::OnCommand(int code, int itemID, LPARAM lParam) case IDC_COMPRESS_FORMAT: { - bool isSFX = IsSFX(); + const bool isSFX = IsSFX(); SaveOptionsInMem(); - m_Solid.ResetContent(); - SetLevel(); - SetSolidBlockSize(); - SetNumThreads(); - SetParams(); - CheckControlsEnable(); + FormatChanged(); SetArchiveName2(isSFX); - SetEncryptionMethod(); - SetMemoryUsage(); return true; } case IDC_COMPRESS_LEVEL: { - { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - int index = FindRegistryFormatAlways(ai.Name); - NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - fo.ResetForLevelChange(); - } + Get_FormatOptions().ResetForLevelChange(); SetMethod(); SetSolidBlockSize(); @@ -957,29 +1016,33 @@ bool CCompressDialog::OnCommand(int code, int itemID, LPARAM lParam) case IDC_COMPRESS_METHOD: { - SetDictionary(); - SetOrder(); + MethodChanged(); SetSolidBlockSize(); SetNumThreads(); CheckSFXNameChange(); SetMemoryUsage(); + if (Get_ArcInfoEx().Flags_HashHandler()) + SetArchiveName2(false); return true; } case IDC_COMPRESS_DICTIONARY: { - UInt32 blockSizeLog = GetBlockSizeSpec(); - if (blockSizeLog != (UInt32)(Int32)-1 - && blockSizeLog != kNoSolidBlockSize - && blockSizeLog != kSolidBlockSize) + /* we want to change the reported threads for Auto line + and keep selected NumThreads option + So we save selected NumThreads option in memory */ + SaveOptionsInMem(); + const UInt32 blockSizeLog = GetBlockSizeSpec(); + if (// blockSizeLog != (UInt32)(Int32)-1 && + blockSizeLog != kSolidLog_NoSolid + && blockSizeLog != kSolidLog_FullSolid) { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - int index = FindRegistryFormatAlways(ai.Name); - NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - fo.Reset_BlockLogSize(); - SetSolidBlockSize(true); + Get_FormatOptions().Reset_BlockLogSize(); + // SetSolidBlockSize(true); } + SetSolidBlockSize(); + SetNumThreads(); // we want to change the reported threads for Auto line only SetMemoryUsage(); return true; } @@ -1005,7 +1068,7 @@ bool CCompressDialog::OnCommand(int code, int itemID, LPARAM lParam) void CCompressDialog::CheckSFXNameChange() { - bool isSFX = IsSFX(); + const bool isSFX = IsSFX(); CheckSFXControlsEnable(); if (isSFX != IsSFX()) SetArchiveName2(isSFX); @@ -1063,7 +1126,18 @@ void CCompressDialog::SetArchiveName(const UString &name) else { fileName += '.'; - fileName += ai.GetMainExt(); + UString ext = ai.GetMainExt(); + if (ai.Flags_HashHandler()) + { + UString estimatedName; + GetMethodSpec(estimatedName); + if (!estimatedName.IsEmpty()) + { + ext = estimatedName; + ext.MakeLower_Ascii(); + } + } + fileName += ext; } m_ArchivePath.SetText(fileName); } @@ -1093,7 +1167,7 @@ int CCompressDialog::FindRegistryFormatAlways(const UString &name) int CCompressDialog::GetStaticFormatIndex() { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + const CArcInfoEx &ai = Get_ArcInfoEx(); for (unsigned i = 0; i < ARRAY_SIZE(g_Formats); i++) if (ai.Name.IsEqualTo_Ascii_NoCase(g_Formats[i].Name)) return i; @@ -1112,11 +1186,11 @@ void CCompressDialog::SetNearestSelectComboBox(NControl::CComboBox &comboBox, UI comboBox.SetCurSel(0); } -void CCompressDialog::SetLevel() +void CCompressDialog::SetLevel2() { m_Level.ResetContent(); const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + const CArcInfoEx &ai = Get_ArcInfoEx(); UInt32 level = 5; { int index = FindRegistryFormat(ai.Name); @@ -1132,17 +1206,23 @@ void CCompressDialog::SetLevel() } } - for (unsigned i = 0; i <= 9; i++) + for (unsigned i = 0; i < sizeof(UInt32) * 8; i++) { - if ((fi.LevelsMask & (1 << i)) != 0) + const UInt32 mask = (UInt32)1 << i; + if ((fi.LevelsMask & mask) != 0) { UInt32 langID = g_Levels[i]; - int index = (int)m_Level.AddString(LangString(langID)); + UString s; + s.Add_UInt32(i); + s += " - "; + s += LangString(langID); + int index = (int)m_Level.AddString(s); m_Level.SetItemData(index, i); } + if (fi.LevelsMask <= mask) + break; } SetNearestSelectComboBox(m_Level, level); - SetMethod(); } @@ -1151,38 +1231,78 @@ static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s) return cb.AddString((CSysString)s); } +// static const char *k_Auto = "- "; // "auto : "; -void CCompressDialog::SetMethod(int keepMethodId) +static void Modify_Auto(AString &s) +{ + s.Insert(0, "* "); + // s += " -"; +} + +void CCompressDialog::SetMethod2(int keepMethodId) { m_Method.ResetContent(); - UInt32 level = GetLevel(); - if (level == 0) + _auto_MethodId = -1; + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + const CArcInfoEx &ai = Get_ArcInfoEx(); + if (GetLevel() == 0 && !ai.Flags_HashHandler()) { - SetDictionary(); - SetOrder(); + MethodChanged(); return; } - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - int index = FindRegistryFormat(ai.Name); UString defaultMethod; - if (index >= 0) { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - defaultMethod = fo.Method; + const int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + defaultMethod = fo.Method; + } } - bool isSfx = IsSFX(); + const bool isSfx = IsSFX(); bool weUseSameMethod = false; + + const bool is7z = ai.Name.IsEqualTo_Ascii_NoCase("7z"); - for (unsigned m = 0; m < fi.NumMethods; m++) + for (unsigned m = 0;; m++) { - EMethodID methodID = fi.MathodIDs[m]; + int methodID; + const char *method; + if (m < fi.NumMethods) + { + methodID = fi.MethodIDs[m]; + method = kMethodsNames[methodID]; + if (is7z) + if (methodID == kCopy + || methodID == kDeflate + || methodID == kDeflate64 + ) + continue; + } + else + { + if (!is7z) + break; + unsigned extIndex = m - fi.NumMethods; + if (extIndex >= ExternalMethods.Size()) + break; + methodID = ARRAY_SIZE(kMethodsNames) + extIndex; + method = ExternalMethods[extIndex].Ptr(); + } if (isSfx) if (!IsMethodSupportedBySfx(methodID)) continue; - const char *method = kMethodsNames[methodID]; - int itemIndex = (int)ComboBox_AddStringAscii(m_Method, method); - m_Method.SetItemData(itemIndex, methodID); + + AString s (method); + int writtenMethodId = methodID; + if (m == 0) + { + _auto_MethodId = methodID; + writtenMethodId = -1; + Modify_Auto(s); + } + const int itemIndex = (int)ComboBox_AddStringAscii(m_Method, s); + m_Method.SetItemData(itemIndex, writtenMethodId); if (keepMethodId == methodID) { m_Method.SetCurSel(itemIndex); @@ -1194,29 +1314,26 @@ void CCompressDialog::SetMethod(int keepMethodId) } if (!weUseSameMethod) - { - SetDictionary(); - SetOrder(); - } + MethodChanged(); } + + bool CCompressDialog::IsZipFormat() { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - return ai.Name.IsEqualTo_Ascii_NoCase("zip"); + return Get_ArcInfoEx().Name.IsEqualTo_Ascii_NoCase("zip"); } bool CCompressDialog::IsXzFormat() { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - return ai.Name.IsEqualTo_Ascii_NoCase("xz"); + return Get_ArcInfoEx().Name.IsEqualTo_Ascii_NoCase("xz"); } void CCompressDialog::SetEncryptionMethod() { _encryptionMethod.ResetContent(); _default_encryptionMethod_Index = -1; - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + const CArcInfoEx &ai = Get_ArcInfoEx(); if (ai.Name.IsEqualTo_Ascii_NoCase("7z")) { ComboBox_AddStringAscii(_encryptionMethod, "AES-256"); @@ -1244,21 +1361,63 @@ void CCompressDialog::SetEncryptionMethod() } } -int CCompressDialog::GetMethodID() + +int CCompressDialog::GetMethodID_RAW() { if (m_Method.GetCount() <= 0) return -1; - return (int)(UInt32)m_Method.GetItemData_of_CurSel(); + return (int)(Int32)(UInt32)m_Method.GetItemData_of_CurSel(); } -UString CCompressDialog::GetMethodSpec() +int CCompressDialog::GetMethodID() +{ + int raw = GetMethodID_RAW(); + if (raw < 0) + return _auto_MethodId; + return raw; +} + + +UString CCompressDialog::GetMethodSpec(UString &estimatedName) { + estimatedName.Empty(); + if (m_Method.GetCount() < 1) + return estimatedName; + const int methodIdRaw = GetMethodID_RAW(); + int methodId = methodIdRaw; + if (methodIdRaw < 0) + methodId = _auto_MethodId; UString s; - if (m_Method.GetCount() > 1) - s = kMethodsNames[GetMethodID()]; + if (methodId >= 0) + { + if (methodId < ARRAY_SIZE(kMethodsNames)) + estimatedName = kMethodsNames[methodId]; + else + estimatedName = ExternalMethods[methodId - ARRAY_SIZE(kMethodsNames)]; + if (methodIdRaw >= 0) + s = estimatedName; + } return s; } + +UString CCompressDialog::GetMethodSpec() +{ + UString estimatedName; + UString s = GetMethodSpec(estimatedName); + return s; +} + +bool CCompressDialog::IsMethodEqualTo(const UString &s) +{ + UString estimatedName; + const UString shortName = GetMethodSpec(estimatedName); + if (s.IsEmpty()) + return shortName.IsEmpty(); + return s.IsEqualTo_NoCase(estimatedName); +} + + UString CCompressDialog::GetEncryptionMethodSpec() { UString s; @@ -1271,14 +1430,16 @@ UString CCompressDialog::GetEncryptionMethodSpec() return s; } +static const size_t k_Auto_Dict = (size_t)0 - 1; -void CCompressDialog::AddDict2(size_t sizeReal, size_t sizeShow) + +int CCompressDialog::AddDict2(size_t sizeReal, size_t sizeShow) { Byte c = 0; unsigned moveBits = 0; - if ((sizeShow & 0xFFFFF) == 0) { moveBits = 20; c = 'M'; } - else if ((sizeShow & 0x3FF) == 0) { moveBits = 10; c = 'K'; } - TCHAR s[32]; + if ((sizeShow & 0xFFFFF) == 0) { moveBits = 20; c = 'M'; } + else if ((sizeShow & 0x3FF) == 0) { moveBits = 10; c = 'K'; } + char s[32]; ConvertUInt64ToString(sizeShow >> moveBits, s); unsigned pos = MyStringLen(s); s[pos++] = ' '; @@ -1286,47 +1447,51 @@ void CCompressDialog::AddDict2(size_t sizeReal, size_t sizeShow) s[pos++] = c; s[pos++] = 'B'; s[pos++] = 0; - const int index = (int)m_Dictionary.AddString(s); + AString s2 (s); + if (sizeReal == k_Auto_Dict) + Modify_Auto(s2); + const int index = (int)ComboBox_AddStringAscii(m_Dictionary, s2); m_Dictionary.SetItemData(index, sizeReal); + return index; } -void CCompressDialog::AddDict(size_t size) +int CCompressDialog::AddDict(size_t size) { - AddDict2(size, size); + return AddDict2(size, size); } -void CCompressDialog::SetDictionary() +void CCompressDialog::SetDictionary2() { m_Dictionary.ResetContent(); - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - const int index = FindRegistryFormat(ai.Name); + // _auto_Dict = (UInt32)1 << 24; // we can use this dictSize to calculate _auto_Solid for unknown method for 7z + _auto_Dict = (UInt32)(Int32)-1; // for debug: + + const CArcInfoEx &ai = Get_ArcInfoEx(); UInt32 defaultDict = (UInt32)(Int32)-1; - - if (index >= 0) { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (fo.Method.IsEqualTo_NoCase(GetMethodSpec())) - defaultDict = fo.Dictionary; + const int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + if (IsMethodEqualTo(fo.Method)) + defaultDict = fo.Dictionary; + } } const int methodID = GetMethodID(); const UInt32 level = GetLevel2(); if (methodID < 0) return; - UInt64 ramSize; - UInt64 maxRamSize; - const bool maxRamSize_Defined = GetMaxRamSizeForProgram(ramSize, maxRamSize); switch (methodID) { case kLZMA: case kLZMA2: { - if (defaultDict == (UInt32)(Int32)-1) { - defaultDict = + _auto_Dict = ( level <= 3 ? ((UInt32)1 << (level * 2 + 16)) : ( level <= 6 ? ((UInt32)1 << (level + 19)) : ( level <= 7 ? ((UInt32)1 << 25) : ((UInt32)1 << 26) @@ -1334,12 +1499,13 @@ void CCompressDialog::SetDictionary() } // we use threshold 3.75 GiB to switch to kLzmaMaxDictSize. - if (defaultDict >= ((UInt32)15 << 28)) + if (defaultDict != (UInt32)(Int32)-1 + && defaultDict >= ((UInt32)15 << 28)) defaultDict = kLzmaMaxDictSize; const size_t kLzmaMaxDictSize_Up = (size_t)1 << (20 + sizeof(size_t) / 4 * 6); - int curSel = 0; + int curSel = AddDict2(k_Auto_Dict, _auto_Dict); for (unsigned i = (16 - 1) * 2; i <= (32 - 1) * 2; i++) { @@ -1354,33 +1520,36 @@ void CCompressDialog::SetDictionary() if (dict_up >= kLzmaMaxDictSize) dict = kLzmaMaxDictSize; // we reduce dictionary - AddDict(dict); + const int index = AddDict(dict); // AddDict2(dict, dict_up); // for debug : we show 4 GB - const UInt64 memUsage = GetMemoryUsageComp_Dict(dict); - if (dict <= defaultDict && (!maxRamSize_Defined || memUsage <= maxRamSize)) - curSel = m_Dictionary.GetCount() - 1; + // const UInt32 numThreads = 2; + // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(numThreads, dict); + if (defaultDict != (UInt32)(Int32)-1) + if (dict <= defaultDict || curSel <= 0) + // if (!maxRamSize_Defined || memUsage <= maxRamSize) + curSel = index; if (dict_up >= kLzmaMaxDictSize_Up) break; } m_Dictionary.SetCurSel(curSel); - // SetNearestSelectComboBox(m_Dictionary, defaultDict); break; } case kPPMd: { - if (defaultDict == (UInt32)(Int32)-1) - defaultDict = (UInt32)1 << (level + 19); + _auto_Dict = (UInt32)1 << (level + 19); const UInt32 kPpmd_Default_4g = (UInt32)0 - ((UInt32)1 << 10); const size_t kPpmd_MaxDictSize_Up = (size_t)1 << (29 + sizeof(size_t) / 8); - if (defaultDict >= ((UInt32)15 << 28)) // threshold + if (defaultDict != (UInt32)(Int32)-1 + && defaultDict >= ((UInt32)15 << 28)) // threshold defaultDict = kPpmd_Default_4g; - int curSel = 0; + int curSel = AddDict2(k_Auto_Dict, _auto_Dict); + for (unsigned i = (20 - 1) * 2; i <= (32 - 1) * 2; i++) { if (i == (20 - 1) * 2 + 1) @@ -1391,36 +1560,38 @@ void CCompressDialog::SetDictionary() if (dict_up >= kPpmd_Default_4g) dict = kPpmd_Default_4g; - AddDict2(dict, dict_up); + const int index = AddDict2(dict, dict_up); // AddDict2((UInt32)((UInt32)0 - 2), dict_up); // for debug // AddDict(dict_up); // for debug - const UInt64 memUsage = GetMemoryUsageComp_Dict(dict); - if (dict <= defaultDict && (!maxRamSize_Defined || memUsage <= maxRamSize)) - curSel = m_Dictionary.GetCount() - 1; + // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(1, dict); + if (defaultDict != (UInt32)(Int32)-1) + if (dict <= defaultDict || curSel <= 0) + // if (!maxRamSize_Defined || memUsage <= maxRamSize) + curSel = index; if (dict_up >= kPpmd_MaxDictSize_Up) break; } m_Dictionary.SetCurSel(curSel); - // SetNearestSelectComboBox(m_Dictionary, defaultDict); break; } case kPPMdZip: { - if (defaultDict == (UInt32)(Int32)-1) - defaultDict = (UInt32)1 << (level + 19); + _auto_Dict = (UInt32)1 << (level + 19); - int curSel = 0; + int curSel = AddDict2(k_Auto_Dict, _auto_Dict); + for (unsigned i = 20; i <= 28; i++) { const UInt32 dict = (UInt32)1 << i; - AddDict(dict); - const UInt64 memUsage = GetMemoryUsageComp_Dict(dict); - if ((dict <= defaultDict && (!maxRamSize_Defined || memUsage <= maxRamSize))) - curSel = m_Dictionary.GetCount() - 1; + const int index = AddDict(dict); + // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(1, dict); + if (defaultDict != (UInt32)(Int32)-1) + if (dict <= defaultDict || curSel <= 0) + // if (!maxRamSize_Defined || memUsage <= maxRamSize) + curSel = index; } m_Dictionary.SetCurSel(curSel); - // SetNearestSelectComboBox(m_Dictionary, defaultDict); break; } @@ -1428,32 +1599,43 @@ void CCompressDialog::SetDictionary() case kDeflate64: { const UInt32 dict = (methodID == kDeflate ? (UInt32)(1 << 15) : (UInt32)(1 << 16)); - AddDict(dict); + _auto_Dict = dict; + AddDict2(k_Auto_Dict, _auto_Dict); m_Dictionary.SetCurSel(0); + // EnableItem(IDC_COMPRESS_DICTIONARY, false); break; } case kBZip2: { - if (defaultDict == (UInt32)(Int32)-1) { - if (level >= 5) defaultDict = (900 << 10); - else if (level >= 3) defaultDict = (500 << 10); - else defaultDict = (100 << 10); + if (level >= 5) _auto_Dict = (900 << 10); + else if (level >= 3) _auto_Dict = (500 << 10); + else _auto_Dict = (100 << 10); } + + int curSel = AddDict2(k_Auto_Dict, _auto_Dict); - int curSel = 0; for (unsigned i = 1; i <= 9; i++) { const UInt32 dict = ((UInt32)i * 100) << 10; AddDict(dict); // AddDict2(i * 100000, dict); - if (i <= defaultDict / 100000) - curSel = m_Dictionary.GetCount() - 1; + if (defaultDict != (UInt32)(Int32)-1) + if (i <= defaultDict / 100000 || curSel <= 0) + curSel = m_Dictionary.GetCount() - 1; } m_Dictionary.SetCurSel(curSel); break; } + + case kCopy: + { + _auto_Dict = 0; + AddDict(0); + m_Dictionary.SetCurSel(0); + break; + } } } @@ -1471,6 +1653,9 @@ UInt64 CCompressDialog::GetComboValue_64(NWindows::NControl::CComboBox &c, int d if (c.GetCount() <= defMax) return (UInt64)(Int64)-1; // LRESULT is signed. so we cast it to unsigned size_t at first: + LRESULT val = c.GetItemData_of_CurSel(); + if (val == (LPARAM)(INT_PTR)(-1)) + return (UInt64)(Int64)-1; return (UInt64)(size_t)c.GetItemData_of_CurSel(); } @@ -1482,31 +1667,47 @@ UInt32 CCompressDialog::GetLevel2() return level; } + int CCompressDialog::AddOrder(UInt32 size) { - TCHAR s[32]; + char s[32]; ConvertUInt32ToString(size, s); - int index = (int)m_Order.AddString(s); + int index = (int)ComboBox_AddStringAscii(m_Order, s); m_Order.SetItemData(index, size); return index; } -void CCompressDialog::SetOrder() +int CCompressDialog::AddOrder_Auto() +{ + AString s; + s.Add_UInt32(_auto_Order); + Modify_Auto(s); + int index = (int)ComboBox_AddStringAscii(m_Order, s); + m_Order.SetItemData(index, (LPARAM)(INT_PTR)(-1)); + return index; +} + +void CCompressDialog::SetOrder2() { m_Order.ResetContent(); - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; - int index = FindRegistryFormat(ai.Name); - UInt32 defaultOrder = (UInt32)(Int32)-1; - if (index >= 0) + _auto_Order = 1; + + const CArcInfoEx &ai = Get_ArcInfoEx(); + UInt32 defaultOrder = (UInt32)(Int32)-1; + { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (fo.Method.IsEqualTo_NoCase(GetMethodSpec())) - defaultOrder = fo.Order; + const int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + if (IsMethodEqualTo(fo.Method)) + defaultOrder = fo.Order; + } } - int methodID = GetMethodID(); - UInt32 level = GetLevel2(); + const int methodID = GetMethodID(); + const UInt32 level = GetLevel2(); if (methodID < 0) return; @@ -1515,81 +1716,91 @@ void CCompressDialog::SetOrder() case kLZMA: case kLZMA2: { - if (defaultOrder == (UInt32)(Int32)-1) - defaultOrder = (level >= 7) ? 64 : 32; - for (unsigned i = 3; i <= 8; i++) - for (unsigned j = 0; j < 2; j++) - { - UInt32 order = ((UInt32)(2 + j) << (i - 1)); - if (order <= 256) - AddOrder(order); - } - AddOrder(273); - SetNearestSelectComboBox(m_Order, defaultOrder); + _auto_Order = (level < 7 ? 32 : 64); + int curSel = AddOrder_Auto(); + for (unsigned i = 2 * 2; i < 8 * 2; i++) + { + UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2)); + if (order > 256) + order = 273; + const int index = AddOrder(order); + if (defaultOrder != (UInt32)(Int32)-1) + if (order <= defaultOrder || curSel <= 0) + curSel = index; + } + m_Order.SetCurSel(curSel); break; } - - case kPPMd: + + case kDeflate: + case kDeflate64: { - if (defaultOrder == (UInt32)(Int32)-1) { - if (level >= 9) defaultOrder = 32; - else if (level >= 7) defaultOrder = 16; - else if (level >= 5) defaultOrder = 6; - else defaultOrder = 4; + if (level >= 9) _auto_Order = 128; + else if (level >= 7) _auto_Order = 64; + else _auto_Order = 32; + } + int curSel = AddOrder_Auto(); + for (unsigned i = 2 * 2; i < 8 * 2; i++) + { + UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2)); + if (order > 256) + order = (methodID == kDeflate64 ? 257 : 258); + const int index = AddOrder(order); + if (defaultOrder != (UInt32)(Int32)-1) + if (order <= defaultOrder || curSel <= 0) + curSel = index; } - AddOrder(2); - AddOrder(3); - - for (unsigned i = 2; i < 8; i++) - for (unsigned j = 0; j < 4; j++) - { - UInt32 order = (4 + j) << (i - 2); - if (order < 32) - AddOrder(order); - } - - AddOrder(32); - SetNearestSelectComboBox(m_Order, defaultOrder); + m_Order.SetCurSel(curSel); break; } - - case kDeflate: - case kDeflate64: + + case kPPMd: { - if (defaultOrder == (UInt32)(Int32)-1) { - if (level >= 9) defaultOrder = 128; - else if (level >= 7) defaultOrder = 64; - else defaultOrder = 32; + if (level >= 9) _auto_Order = 32; + else if (level >= 7) _auto_Order = 16; + else if (level >= 5) _auto_Order = 6; + else _auto_Order = 4; } - for (unsigned i = 3; i <= 8; i++) - for (unsigned j = 0; j < 2; j++) - { - UInt32 order = ((UInt32)(2 + j) << (i - 1));; - if (order <= 256) - AddOrder(order); - } - - AddOrder(methodID == kDeflate64 ? 257 : 258); - SetNearestSelectComboBox(m_Order, defaultOrder); + int curSel = AddOrder_Auto(); + + for (unsigned i = 0;; i++) + { + UInt32 order = i + 2; + if (i >= 2) + order = (4 + ((i - 2) & 3)) << ((i - 2) / 4); + const int index = AddOrder(order); + if (defaultOrder != (UInt32)(Int32)-1) + if (order <= defaultOrder || curSel <= 0) + curSel = index; + if (order >= 32) + break; + } + m_Order.SetCurSel(curSel); break; } - - case kBZip2: - break; - + case kPPMdZip: { - if (defaultOrder == (UInt32)(Int32)-1) - defaultOrder = level + 3; + _auto_Order = level + 3; + int curSel = AddOrder_Auto(); for (unsigned i = 2; i <= 16; i++) - AddOrder(i); - SetNearestSelectComboBox(m_Order, defaultOrder); + { + const int index = AddOrder(i); + if (defaultOrder != (UInt32)(Int32)-1) + if (i <= defaultOrder || curSel <= 0) + curSel = index; + } + m_Order.SetCurSel(curSel); break; } + + // case kBZip2: + default: + break; } } @@ -1620,50 +1831,67 @@ static UInt64 Get_Lzma2_ChunkSize(UInt64 dict) } -void CCompressDialog::SetSolidBlockSize(bool useDictionary) +static void Add_Size(AString &s2, UInt64 val) +{ + unsigned moveBits = 0; + Byte c = 0; + if ((val & 0x3FFFFFFF) == 0) { moveBits = 30; c = 'G'; } + else if ((val & 0xFFFFF) == 0) { moveBits = 20; c = 'M'; } + else if ((val & 0x3FF) == 0) { moveBits = 10; c = 'K'; } + char s[32]; + ConvertUInt64ToString(val >> moveBits, s); + unsigned pos = MyStringLen(s); + s[pos++] = ' '; + if (moveBits != 0) + s[pos++] = c; + s[pos++] = 'B'; + s[pos++] = 0; + s2 += s; +} + + +void CCompressDialog::SetSolidBlockSize2() { m_Solid.ResetContent(); + _auto_Solid = 1 << 20; + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; if (!fi.Solid) return; - UInt32 level = GetLevel2(); + const UInt32 level = GetLevel2(); if (level == 0) return; - UInt64 dict = GetDictSpec(); + UInt64 dict = GetDict2(); if (dict == (UInt64)(Int64)-1) - dict = 1; + { + dict = 1 << 25; // default dict for unknown methods + // return; + } + UInt32 defaultBlockSize = (UInt32)(Int32)-1; - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + const CArcInfoEx &ai = Get_ArcInfoEx(); - if (useDictionary) + /* + if (usePrevDictionary) defaultBlockSize = GetBlockSizeSpec(); else + */ { - int index = FindRegistryFormat(ai.Name); + const int index = FindRegistryFormat(ai.Name); if (index >= 0) { const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (fo.Method.IsEqualTo_NoCase(GetMethodSpec())) + if (IsMethodEqualTo(fo.Method)) defaultBlockSize = fo.BlockLogSize; } } - bool is7z = ai.Name.IsEqualTo_Ascii_NoCase("7z"); + const bool is7z = ai.Name.IsEqualTo_Ascii_NoCase("7z"); - { - UString s ('-'); - if (is7z) - LangString(IDS_COMPRESS_NON_SOLID, s); - int index = (int)m_Solid.AddString(s); - m_Solid.SetItemData(index, (UInt32)kNoSolidBlockSize); - if (defaultBlockSize == kNoSolidBlockSize) - m_Solid.SetCurSel(0); - } - const UInt64 cs = Get_Lzma2_ChunkSize(dict); // Solid Block Size @@ -1673,98 +1901,215 @@ void CCompressDialog::SetSolidBlockSize(bool useDictionary) { // we use same default block sizes as defined in 7z encoder UInt64 kMaxSize = (UInt64)1 << 32; - if (GetMethodID() == kLZMA2) + const int methodId = GetMethodID(); + if (methodId == kLZMA2) { blockSize = cs << 6; kMaxSize = (UInt64)1 << 34; } else - blockSize = (UInt64)dict << 7; + { + UInt64 dict2 = dict; + if (methodId == kBZip2) + { + dict2 /= 100000; + if (dict2 < 1) + dict2 = 1; + dict2 *= 100000; + } + blockSize = dict2 << 7; + } const UInt32 kMinSize = (UInt32)1 << 24; if (blockSize < kMinSize) blockSize = kMinSize; if (blockSize > kMaxSize) blockSize = kMaxSize; } + + _auto_Solid = blockSize; + + int curSel; + { + AString s; + Add_Size(s, _auto_Solid); + Modify_Auto(s); + int index = (int)ComboBox_AddStringAscii(m_Solid, s); + m_Solid.SetItemData(index, (UInt32)(Int32)-1); + curSel = index; + } + + if (is7z) + { + UString s ('-'); + // kSolidLog_NoSolid = 0 for xz means default blockSize + if (is7z) + LangString(IDS_COMPRESS_NON_SOLID, s); + const int index = (int)m_Solid.AddString(s); + m_Solid.SetItemData(index, (UInt32)kSolidLog_NoSolid); + if (defaultBlockSize == kSolidLog_NoSolid) + curSel = index; + } for (unsigned i = 20; i <= 36; i++) { - if (defaultBlockSize == (UInt32)(Int32)-1 && ((UInt64)1 << i) >= blockSize) - defaultBlockSize = i; - - TCHAR s[32]; - char post; - ConvertUInt32ToString(1 << (i % 10), s); - if (i < 20) post = 'K'; - else if (i < 30) post = 'M'; - else post = 'G'; - unsigned pos = (unsigned)lstrlen(s); - s[pos++] = ' '; - s[pos++] = post; - s[pos++] = 'B'; - s[pos] = 0; - int index = (int)m_Solid.AddString(s); + AString s; + Add_Size(s, (UInt64)1 << i); + const int index = (int)ComboBox_AddStringAscii(m_Solid, s); m_Solid.SetItemData(index, (UInt32)i); + if (defaultBlockSize != (UInt32)(Int32)-1) + if (i <= defaultBlockSize || index <= 1) + curSel = index; } { - int index = (int)m_Solid.AddString(LangString(IDS_COMPRESS_SOLID)); - m_Solid.SetItemData(index, kSolidBlockSize); + const int index = (int)m_Solid.AddString(LangString(IDS_COMPRESS_SOLID)); + m_Solid.SetItemData(index, kSolidLog_FullSolid); + if (defaultBlockSize == kSolidLog_FullSolid) + curSel = index; } - - if (defaultBlockSize == (UInt32)(Int32)-1) - defaultBlockSize = kSolidBlockSize; - if (defaultBlockSize != kNoSolidBlockSize) - SetNearestSelectComboBox(m_Solid, defaultBlockSize); + + m_Solid.SetCurSel(curSel); } -void CCompressDialog::SetNumThreads() + +void CCompressDialog::SetNumThreads2() { - m_NumThreads.ResetContent(); + _auto_NumThreads = 1; + m_NumThreads.ResetContent(); const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; if (!fi.MultiThread) return; - UInt32 numHardwareThreads = NSystem::GetNumberOfProcessors(); - // numHardwareThreads = 64; + const UInt32 numHardwareThreads = NSystem::GetNumberOfProcessors(); + // 64; // for debug: UInt32 defaultValue = numHardwareThreads; + bool useAutoThreads = true; { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + const CArcInfoEx &ai = Get_ArcInfoEx(); int index = FindRegistryFormat(ai.Name); if (index >= 0) { const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (fo.Method.IsEqualTo_NoCase(GetMethodSpec()) && fo.NumThreads != (UInt32)(Int32)-1) + if (IsMethodEqualTo(fo.Method) && fo.NumThreads != (UInt32)(Int32)-1) + { defaultValue = fo.NumThreads; + useAutoThreads = false; + } } } - UInt32 numAlgoThreadsMax = 1; - int methodID = GetMethodID(); + UInt32 numAlgoThreadsMax = numHardwareThreads * 2; + const int methodID = GetMethodID(); switch (methodID) { case kLZMA: numAlgoThreadsMax = 2; break; case kLZMA2: numAlgoThreadsMax = 256; break; case kBZip2: numAlgoThreadsMax = 32; break; + case kCopy: + case kPPMd: + case kDeflate: + case kDeflate64: + case kPPMdZip: + numAlgoThreadsMax = 1; } - if (IsZipFormat()) - numAlgoThreadsMax = 128; + const bool isZip = IsZipFormat(); + if (isZip) + { + numAlgoThreadsMax = + #ifdef _WIN32 + 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here + #else + 128; + #endif + } + + UInt32 autoThreads = numHardwareThreads; + if (autoThreads > numAlgoThreadsMax) + autoThreads = numAlgoThreadsMax; + + if (autoThreads > 1 && _ramSize_Defined) + { + if (isZip) + { + for (; autoThreads > 1; autoThreads--) + { + const UInt64 dict64 = GetDict2(); + UInt64 decompressMemory; + const UInt64 usage = GetMemoryUsage_Threads_Dict_DecompMem(autoThreads, dict64, decompressMemory); + if (usage <= _ramUsage_Auto) + break; + } + } + else if (methodID == kLZMA2) + { + const UInt64 dict64 = GetDict2(); + const UInt32 numThreads1 = (GetLevel2() >= 5 ? 2 : 1); + UInt32 numBlockThreads = autoThreads / numThreads1; + for (; numBlockThreads > 1; numBlockThreads--) + { + autoThreads = numBlockThreads * numThreads1; + UInt64 decompressMemory; + const UInt64 usage = GetMemoryUsage_Threads_Dict_DecompMem(autoThreads, dict64, decompressMemory); + if (usage <= _ramUsage_Auto) + break; + } + autoThreads = numBlockThreads * numThreads1; + } + } + + _auto_NumThreads = autoThreads; + + int curSel = -1; + { + AString s; + s.Add_UInt32(autoThreads); + Modify_Auto(s); + int index = (int)ComboBox_AddStringAscii(m_NumThreads, s); + m_NumThreads.SetItemData(index, (LPARAM)(INT_PTR)(-1)); + // m_NumThreads.SetItemData(index, autoThreads); + if (useAutoThreads) + curSel = index; + } + + if (numAlgoThreadsMax != autoThreads || autoThreads != 1) for (UInt32 i = 1; i <= numHardwareThreads * 2 && i <= numAlgoThreadsMax; i++) { - TCHAR s[32]; + char s[32]; ConvertUInt32ToString(i, s); - int index = (int)m_NumThreads.AddString(s); + int index = (int)ComboBox_AddStringAscii(m_NumThreads, s); m_NumThreads.SetItemData(index, (UInt32)i); + if (!useAutoThreads && i == defaultValue) + curSel = index; } - SetNearestSelectComboBox(m_NumThreads, defaultValue); + + m_NumThreads.SetCurSel(curSel); } +UInt64 CCompressDialog::GetMemoryUsage_DecompMem(UInt64 &decompressMemory) +{ + return GetMemoryUsage_Dict_DecompMem(GetDict2(), decompressMemory); +} + +UInt64 CCompressDialog::GetMemoryUsageComp_Threads_Dict(UInt32 numThreads, UInt64 dict64) +{ + UInt64 decompressMemory; + return GetMemoryUsage_Threads_Dict_DecompMem(numThreads, dict64, decompressMemory); +} + UInt64 CCompressDialog::GetMemoryUsage_Dict_DecompMem(UInt64 dict64, UInt64 &decompressMemory) { - decompressMemory = UInt64(Int64(-1)); + return GetMemoryUsage_Threads_Dict_DecompMem(GetNumThreads2(), dict64, decompressMemory); +} + +UInt64 CCompressDialog::GetMemoryUsage_Threads_Dict_DecompMem(UInt32 numThreads, UInt64 dict64, UInt64 &decompressMemory) +{ + decompressMemory = (UInt64)(Int64)-1; + if (dict64 == (UInt64)(Int64)-1) + return (UInt64)(Int64)-1; + UInt32 level = GetLevel2(); if (level == 0) { @@ -1776,21 +2121,25 @@ UInt64 CCompressDialog::GetMemoryUsage_Dict_DecompMem(UInt64 dict64, UInt64 &dec const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; if (fi.Filter && level >= 9) size += (12 << 20) * 2 + (5 << 20); - UInt32 numThreads = GetNumThreads2(); + // UInt32 numThreads = GetNumThreads2(); + UInt32 numMainZipThreads = 1; + if (IsZipFormat()) { UInt32 numSubThreads = 1; if (GetMethodID() == kLZMA && numThreads > 1 && level >= 5) numSubThreads = 2; - UInt32 numMainThreads = numThreads / numSubThreads; - if (numMainThreads > 1) - size += (UInt64)numMainThreads << 25; + numMainZipThreads = numThreads / numSubThreads; + if (numMainZipThreads > 1) + size += (UInt64)numMainZipThreads * ((size_t)sizeof(size_t) << 23); + else + numMainZipThreads = 1; } - int methidId = GetMethodID(); + const int methodId = GetMethodID(); - switch (methidId) + switch (methodId) { case kLZMA: case kLZMA2: @@ -1824,9 +2173,9 @@ UInt64 CCompressDialog::GetMemoryUsage_Dict_DecompMem(UInt64 dict64, UInt64 &dec UInt32 numBlockThreads = numThreads / numThreads1; - UInt64 chunkSize = 0; + UInt64 chunkSize = 0; // it's solid chunk - if (methidId != kLZMA && numBlockThreads != 1) + if (methodId != kLZMA && numBlockThreads != 1) { chunkSize = Get_Lzma2_ChunkSize(dict); @@ -1835,12 +2184,12 @@ UInt64 CCompressDialog::GetMemoryUsage_Dict_DecompMem(UInt64 dict64, UInt64 &dec UInt32 blockSizeLog = GetBlockSizeSpec(); if (blockSizeLog != (UInt32)(Int32)-1) { - if (blockSizeLog == kSolidBlockSize) + if (blockSizeLog == kSolidLog_FullSolid) { numBlockThreads = 1; chunkSize = 0; } - else if (blockSizeLog != kNoSolidBlockSize) + else if (blockSizeLog != kSolidLog_NoSolid) chunkSize = (UInt64)1 << blockSizeLog; } } @@ -1859,7 +2208,10 @@ UInt64 CCompressDialog::GetMemoryUsage_Dict_DecompMem(UInt64 dict64, UInt64 &dec else { size += numBlockThreads * (size1 + chunkSize); - UInt64 numPackChunks = numBlockThreads + (numBlockThreads / 4) + 2; + UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1; + if (chunkSize < ((UInt32)1 << 26)) numBlockThreads++; + if (chunkSize < ((UInt32)1 << 24)) numBlockThreads++; + if (chunkSize < ((UInt32)1 << 22)) numBlockThreads++; size += numPackChunks * chunkSize; } @@ -1876,14 +2228,10 @@ UInt64 CCompressDialog::GetMemoryUsage_Dict_DecompMem(UInt64 dict64, UInt64 &dec case kDeflate: case kDeflate64: { - /* - UInt32 order = GetOrder(); - if (order == (UInt32)(Int32)-1) - order = 32; - */ - if (level >= 7) - size += (1 << 20); - size += 3 << 20; + UInt64 size1 = 3 << 20; + // if (level >= 7) + size1 += (1 << 20); + size += size1 * numMainZipThreads; decompressMemory = (2 << 20); return size; } @@ -1905,16 +2253,6 @@ UInt64 CCompressDialog::GetMemoryUsage_Dict_DecompMem(UInt64 dict64, UInt64 &dec return (UInt64)(Int64)-1; } -UInt64 CCompressDialog::GetMemoryUsage_DecompMem(UInt64 &decompressMemory) -{ - return GetMemoryUsage_Dict_DecompMem(GetDict(), decompressMemory); -} - -UInt64 CCompressDialog::GetMemoryUsageComp_Dict(UInt64 dict64) -{ - UInt64 decompressMemory; - return GetMemoryUsage_Dict_DecompMem(dict64, decompressMemory); -} void CCompressDialog::PrintMemUsage(UINT res, UInt64 value) { @@ -1949,7 +2287,7 @@ void CCompressDialog::SetMemoryUsage() void CCompressDialog::SetParams() { - const CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()]; + const CArcInfoEx &ai = Get_ArcInfoEx(); m_Params.SetText(TEXT("")); const int index = FindRegistryFormat(ai.Name); if (index >= 0) @@ -1961,10 +2299,11 @@ void CCompressDialog::SetParams() void CCompressDialog::SaveOptionsInMem() { - const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex]; - const int index = FindRegistryFormatAlways(ai.Name); m_Params.GetText(Info.Options); Info.Options.Trim(); + + const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex]; + const int index = FindRegistryFormatAlways(ai.Name); NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; fo.Options = Info.Options; fo.Level = GetLevelSpec(); diff --git a/CPP/7zip/UI/GUI/CompressDialog.h b/CPP/7zip/UI/GUI/CompressDialog.h index 234e0239..d8091b04 100644 --- a/CPP/7zip/UI/GUI/CompressDialog.h +++ b/CPP/7zip/UI/GUI/CompressDialog.h @@ -34,7 +34,7 @@ namespace NCompressDialog NWildcard::ECensorPathMode PathMode; bool SolidIsSpecified; - bool MultiThreadIsAllowed; + // bool MultiThreadIsAllowed; UInt64 SolidBlockSize; UInt32 NumThreads; @@ -80,6 +80,8 @@ namespace NCompressDialog FormatIndex(-1) { Level = Order = (UInt32)(Int32)-1; + NumThreads = (UInt32)(Int32)-1; + SolidIsSpecified = false; Dict64 = (UInt64)(Int64)(-1); OrderMode = false; Method.Empty(); @@ -100,16 +102,23 @@ class CCompressDialog: public NWindows::NControl::CModalDialog NWindows::NControl::CComboBox m_Order; NWindows::NControl::CComboBox m_Solid; NWindows::NControl::CComboBox m_NumThreads; + NWindows::NControl::CComboBox m_Volume; + + NWindows::NControl::CDialogChildControl m_Params; NWindows::NControl::CComboBox m_UpdateMode; NWindows::NControl::CComboBox m_PathMode; - NWindows::NControl::CComboBox m_Volume; - NWindows::NControl::CDialogChildControl m_Params; - NWindows::NControl::CEdit _password1Control; NWindows::NControl::CEdit _password2Control; NWindows::NControl::CComboBox _encryptionMethod; + + int _auto_MethodId; + UInt32 _auto_Dict; // (UInt32)(Int32)-1 means unknown + UInt32 _auto_Order; + UInt64 _auto_Solid; + UInt32 _auto_NumThreads; + int _default_encryptionMethod_Index; NCompression::CInfo m_RegistryInfo; @@ -118,13 +127,30 @@ class CCompressDialog: public NWindows::NControl::CModalDialog UString DirPrefix; UString StartDirPrefix; + bool _ramSize_Defined; + UInt64 _ramSize; + UInt64 _ramUsage_Auto; + UInt64 _ramUsage_Limit; + + void CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2); void GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2); void SetArchiveName(const UString &name); int FindRegistryFormat(const UString &name); int FindRegistryFormatAlways(const UString &name); + + const CArcInfoEx &Get_ArcInfoEx() + { + return (*ArcFormats)[GetFormatIndex()]; + } + NCompression::CFormatOptions &Get_FormatOptions() + { + const CArcInfoEx &ai = Get_ArcInfoEx(); + return m_RegistryInfo.Formats[ FindRegistryFormatAlways(ai.Name) ]; + } + void CheckSFXNameChange(); void SetArchiveName2(bool prevWasSFX); @@ -132,11 +158,35 @@ class CCompressDialog: public NWindows::NControl::CModalDialog void SetNearestSelectComboBox(NWindows::NControl::CComboBox &comboBox, UInt32 value); - void SetLevel(); + void SetLevel2(); + void SetLevel() + { + SetLevel2(); + EnableMultiCombo(IDC_COMPRESS_LEVEL); + SetMethod(); + } + + void SetMethod2(int keepMethodId); + void SetMethod(int keepMethodId = -1) + { + SetMethod2(keepMethodId); + EnableMultiCombo(IDC_COMPRESS_METHOD); + } + + void MethodChanged() + { + SetDictionary2(); + EnableMultiCombo(IDC_COMPRESS_DICTIONARY); + SetOrder2(); + EnableMultiCombo(IDC_COMPRESS_ORDER); + } - void SetMethod(int keepMethodId = -1); + int GetMethodID_RAW(); int GetMethodID(); + + UString GetMethodSpec(UString &estimatedName); UString GetMethodSpec(); + bool IsMethodEqualTo(const UString &s); UString GetEncryptionMethodSpec(); bool IsZipFormat(); @@ -144,10 +194,10 @@ class CCompressDialog: public NWindows::NControl::CModalDialog void SetEncryptionMethod(); - void AddDict2(size_t sizeReal, size_t sizeShow); - void AddDict(size_t size); - - void SetDictionary(); + int AddDict2(size_t sizeReal, size_t sizeShow); + int AddDict(size_t size); + + void SetDictionary2(); UInt32 GetComboValue(NWindows::NControl::CComboBox &c, int defMax = 0); UInt64 GetComboValue_64(NWindows::NControl::CComboBox &c, int defMax = 0); @@ -155,24 +205,60 @@ class CCompressDialog: public NWindows::NControl::CModalDialog UInt32 GetLevel() { return GetComboValue(m_Level); } UInt32 GetLevelSpec() { return GetComboValue(m_Level, 1); } UInt32 GetLevel2(); - UInt64 GetDict() { return GetComboValue_64(m_Dictionary); } + UInt64 GetDictSpec() { return GetComboValue_64(m_Dictionary, 1); } - UInt32 GetOrder() { return GetComboValue(m_Order); } + UInt64 GetDict2() + { + UInt64 num = GetDictSpec(); + if (num == (UInt64)(Int64)-1) + { + if (_auto_Dict == (UInt32)(Int32)-1) + return (UInt64)(Int64)-1; // unknown + num = _auto_Dict; + } + return num; + } + + // UInt32 GetOrder() { return GetComboValue(m_Order); } UInt32 GetOrderSpec() { return GetComboValue(m_Order, 1); } UInt32 GetNumThreadsSpec() { return GetComboValue(m_NumThreads, 1); } - UInt32 GetNumThreads2() { UInt32 num = GetNumThreadsSpec(); if (num == UInt32(-1)) num = 1; return num; } + + UInt32 GetNumThreads2() + { + UInt32 num = GetNumThreadsSpec(); + if (num == (UInt32)(Int32)-1) + num = _auto_NumThreads; + return num; + } + UInt32 GetBlockSizeSpec() { return GetComboValue(m_Solid, 1); } int AddOrder(UInt32 size); - void SetOrder(); + int AddOrder_Auto(); + + void SetOrder2(); + bool GetOrderMode(); - void SetSolidBlockSize(bool useDictionary = false); - void SetNumThreads(); + void SetSolidBlockSize2(); + void SetSolidBlockSize(/* bool useDictionary = false */) + { + SetSolidBlockSize2(); + EnableMultiCombo(IDC_COMPRESS_SOLID); + } + + void SetNumThreads2(); + void SetNumThreads() + { + SetNumThreads2(); + EnableMultiCombo(IDC_COMPRESS_THREADS); + } + UInt64 GetMemoryUsage_Dict_DecompMem(UInt64 dict, UInt64 &decompressMemory); + UInt64 GetMemoryUsage_Threads_Dict_DecompMem(UInt32 numThreads, UInt64 dict, UInt64 &decompressMemory); UInt64 GetMemoryUsage_DecompMem(UInt64 &decompressMemory); - UInt64 GetMemoryUsageComp_Dict(UInt64 dict64); + UInt64 GetMemoryUsageComp_Threads_Dict(UInt32 numThreads, UInt64 dict64); void PrintMemUsage(UINT res, UInt64 value); void SetMemoryUsage(); @@ -186,9 +272,32 @@ class CCompressDialog: public NWindows::NControl::CModalDialog bool SetArcPathFields(const UString &path, UString &name, bool always); bool GetFinalPath_Smart(UString &resPath); + void CheckSFXControlsEnable(); + // void CheckVolumeEnable(); + void EnableMultiCombo(unsigned id); + void FormatChanged(); + + void OnButtonSetArchive(); + bool IsSFX(); + void OnButtonSFX(); + + virtual bool OnInit(); + virtual bool OnCommand(int code, int itemID, LPARAM lParam); + virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); + virtual void OnOK(); + virtual void OnHelp(); + + void MessageBoxError(LPCWSTR message) + { + MessageBoxW(*this, message, L"7-Zip", MB_ICONERROR); + } + public: - CObjectVector<CArcInfoEx> *ArcFormats; + const CObjectVector<CArcInfoEx> *ArcFormats; CUIntVector ArcIndices; // can not be empty, must contain Info.FormatIndex, if Info.FormatIndex >= 0 + AStringVector ExternalMethods; + + void SetMethods(const CObjectVector<CCodecInfoUser> &userCodecs); NCompressDialog::CInfo Info; UString OriginalFileName; // for bzip2, gzip2 @@ -201,28 +310,6 @@ public: } CCompressDialog(): CurrentDirWasChanged(false) {}; - - void MessageBoxError(LPCWSTR message) - { - MessageBoxW(*this, message, L"7-Zip", MB_ICONERROR); - } - -protected: - - void CheckSFXControlsEnable(); - // void CheckVolumeEnable(); - void CheckControlsEnable(); - - void OnButtonSetArchive(); - bool IsSFX(); - void OnButtonSFX(); - - virtual bool OnInit(); - virtual bool OnCommand(int code, int itemID, LPARAM lParam); - virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); - virtual void OnOK(); - virtual void OnHelp(); - }; #endif diff --git a/CPP/7zip/UI/GUI/ExtractGUI.cpp b/CPP/7zip/UI/GUI/ExtractGUI.cpp index 1e37efb8..59403ee9 100644 --- a/CPP/7zip/UI/GUI/ExtractGUI.cpp +++ b/CPP/7zip/UI/GUI/ExtractGUI.cpp @@ -64,6 +64,12 @@ class CThreadExtracting: public CProgressThreadVirt { HRESULT ProcessVirt(); public: + /* + #ifdef EXTERNAL_CODECS + const CExternalCodecs *externalCodecs; + #endif + */ + CCodecs *codecs; CExtractCallbackImp *ExtractCallbackSpec; const CObjectVector<COpenType> *FormatIndices; @@ -105,7 +111,13 @@ HRESULT CThreadExtracting::ProcessVirt() */ #endif - HRESULT res = Extract(codecs, + HRESULT res = Extract( + /* + #ifdef EXTERNAL_CODECS + externalCodecs, + #endif + */ + codecs, *FormatIndices, *ExcludedFormatIndices, *ArchivePaths, *ArchivePathsFull, *WildcardCensor, *Options, ExtractCallbackSpec, ExtractCallback, @@ -154,6 +166,7 @@ HRESULT CThreadExtracting::ProcessVirt() HRESULT ExtractGUI( + // DECL_EXTERNAL_CODECS_LOC_VARS CCodecs *codecs, const CObjectVector<COpenType> &formatIndices, const CIntVector &excludedFormatIndices, @@ -172,6 +185,11 @@ HRESULT ExtractGUI( messageWasDisplayed = false; CThreadExtracting extracter; + /* + #ifdef EXTERNAL_CODECS + extracter.externalCodecs = __externalCodecs; + #endif + */ extracter.codecs = codecs; extracter.FormatIndices = &formatIndices; extracter.ExcludedFormatIndices = &excludedFormatIndices; diff --git a/CPP/7zip/UI/GUI/ExtractGUI.h b/CPP/7zip/UI/GUI/ExtractGUI.h index d55b30de..3b412590 100644 --- a/CPP/7zip/UI/GUI/ExtractGUI.h +++ b/CPP/7zip/UI/GUI/ExtractGUI.h @@ -20,6 +20,7 @@ */ HRESULT ExtractGUI( + // DECL_EXTERNAL_CODECS_LOC_VARS CCodecs *codecs, const CObjectVector<COpenType> &formatIndices, const CIntVector &excludedFormatIndices, diff --git a/CPP/7zip/UI/GUI/GUI.cpp b/CPP/7zip/UI/GUI/GUI.cpp index 37567019..32a48e74 100644 --- a/CPP/7zip/UI/GUI/GUI.cpp +++ b/CPP/7zip/UI/GUI/GUI.cpp @@ -34,6 +34,10 @@ using namespace NWindows; +#ifdef EXTERNAL_CODECS +const CExternalCodecs *g_ExternalCodecs_Ptr; +#endif + extern HINSTANCE g_hInstance; HINSTANCE g_hInstance; @@ -134,18 +138,22 @@ static int Main2() codecs->CaseSensitiveChange = options.CaseSensitiveChange; codecs->CaseSensitive = options.CaseSensitive; ThrowException_if_Error(codecs->Load()); - + Codecs_AddHashArcHandler(codecs); + #ifdef EXTERNAL_CODECS { + g_ExternalCodecs_Ptr = &__externalCodecs; UString s; codecs->GetCodecsErrorMessage(s); if (!s.IsEmpty()) + { MessageBoxW(0, s, L"7-Zip", MB_ICONERROR); + } + } #endif - - bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); + const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); if (codecs->Formats.Size() == 0 && (isExtractGroupCommand @@ -170,7 +178,7 @@ static int Main2() return NExitCode::kFatalError; } - CIntVector excludedFormatIndices; + CIntVector excludedFormats; FOR_VECTOR (k, options.ExcludedArcTypes) { CIntVector tempIndices; @@ -180,12 +188,13 @@ static int Main2() ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE); return NExitCode::kFatalError; } - excludedFormatIndices.AddToUniqueSorted(tempIndices[0]); - // excludedFormatIndices.Sort(); + excludedFormats.AddToUniqueSorted(tempIndices[0]); + // excludedFormats.Sort(); } #ifdef EXTERNAL_CODECS if (isExtractGroupCommand + || options.Command.IsFromUpdateGroup() || options.Command.CommandType == NCommandType::kHash || options.Command.CommandType == NCommandType::kBenchmark) ThrowException_if_Error(__externalCodecs.Load()); @@ -270,8 +279,10 @@ static int Main2() ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1); - HRESULT result = ExtractGUI(codecs, - formatIndices, excludedFormatIndices, + HRESULT result = ExtractGUI( + // EXTERNAL_CODECS_VARS_L + codecs, + formatIndices, excludedFormats, ArchivePathsSorted, ArchivePathsFullSorted, options.Censor.Pairs.Front().Head, diff --git a/CPP/7zip/UI/GUI/GUI.dsp b/CPP/7zip/UI/GUI/GUI.dsp index 7e65f481..53a2c92f 100644 --- a/CPP/7zip/UI/GUI/GUI.dsp +++ b/CPP/7zip/UI/GUI/GUI.dsp @@ -872,6 +872,14 @@ SOURCE=..\..\..\Common\CRC.cpp # End Source File # Begin Source File +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + SOURCE=..\..\..\Common\IntToString.cpp # End Source File # Begin Source File @@ -1188,6 +1196,14 @@ SOURCE=..\..\..\Windows\Window.h # PROP Default_Filter "" # Begin Source File +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp # End Source File # Begin Source File diff --git a/CPP/7zip/UI/GUI/HashGUI.cpp b/CPP/7zip/UI/GUI/HashGUI.cpp index 37cd65e9..219135fb 100644 --- a/CPP/7zip/UI/GUI/HashGUI.cpp +++ b/CPP/7zip/UI/GUI/HashGUI.cpp @@ -174,10 +174,12 @@ HRESULT CHashCallbackGUI::SetOperationResult(UInt64 /* fileSize */, const CHashB return CheckBreak(); } +static const unsigned k_DigestStringSize = k_HashCalc_DigestSize_Max * 2 + k_HashCalc_ExtraSize * 2 + 16; + static void AddHashString(CProperty &s, const CHasherState &h, unsigned digestIndex) { - char temp[k_HashCalc_DigestSize_Max * 2 + 4]; - AddHashHexToString(temp, h.Digests[digestIndex], h.DigestSize); + char temp[k_DigestStringSize]; + h.WriteToString(digestIndex, temp); s.Value = temp; } diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp b/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp index 33852e3b..1f272cd9 100644 --- a/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp +++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp @@ -156,7 +156,7 @@ HRESULT CUpdateCallbackGUI::ReportExtractResult(Int32 opRes, Int32 isEncrypted, return S_OK; } -HRESULT CUpdateCallbackGUI::ReportUpdateOpeartion(UInt32 op, const wchar_t *name, bool isDir) +HRESULT CUpdateCallbackGUI::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) { return SetOperation_Base(op, name, isDir); } diff --git a/CPP/7zip/UI/GUI/UpdateGUI.cpp b/CPP/7zip/UI/GUI/UpdateGUI.cpp index 28f19d25..1bdc9ffe 100644 --- a/CPP/7zip/UI/GUI/UpdateGUI.cpp +++ b/CPP/7zip/UI/GUI/UpdateGUI.cpp @@ -146,7 +146,8 @@ static void SetOutProperties( bool orderMode, UInt32 order, bool solidIsSpecified, UInt64 solidBlockSize, - bool multiThreadIsAllowed, UInt32 numThreads, + // bool multiThreadIsAllowed, + UInt32 numThreads, const UString &encryptionMethod, bool encryptHeadersIsAllowed, bool encryptHeaders, bool /* sfxMode */) @@ -182,7 +183,9 @@ static void SetOutProperties( AddProp(properties, "he", encryptHeaders); if (solidIsSpecified) AddProp(properties, "s", GetNumInBytesString(solidBlockSize)); - if (multiThreadIsAllowed) + if ( + // multiThreadIsAllowed && + numThreads != (UInt32)(Int32)-1) AddProp(properties, "mt", numThreads); } @@ -287,6 +290,11 @@ static HRESULT ShowDialog( CCompressDialog dialog; NCompressDialog::CInfo &di = dialog.Info; dialog.ArcFormats = &codecs->Formats; + { + CObjectVector<CCodecInfoUser> userCodecs; + codecs->Get_CodecsInfoUser_Vector(userCodecs); + dialog.SetMethods(userCodecs); + } if (options.MethodMode.Type_Defined) di.FormatIndex = options.MethodMode.Type.FormatIndex; @@ -299,9 +307,13 @@ static HRESULT ShowDialog( if (!oneFile && ai.Flags_KeepName()) continue; if ((int)i != di.FormatIndex) + { + if (ai.Flags_HashHandler()) + continue; if (ai.Name.IsEqualTo_Ascii_NoCase("swfc")) if (!oneFile || name.Len() < 4 || !StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".swf")) continue; + } dialog.ArcIndices.Add(i); } if (dialog.ArcIndices.IsEmpty()) @@ -392,7 +404,8 @@ static HRESULT ShowDialog( di.Dict64, di.OrderMode, di.Order, di.SolidIsSpecified, di.SolidBlockSize, - di.MultiThreadIsAllowed, di.NumThreads, + // di.MultiThreadIsAllowed, + di.NumThreads, di.EncryptionMethod, di.EncryptHeadersIsAllowed, di.EncryptHeaders, di.SFXMode); @@ -464,6 +477,13 @@ HRESULT UpdateGUI( tu.UpdateCallbackGUI->Init(); UString title = LangString(IDS_PROGRESS_COMPRESSING); + if (!formatIndices.IsEmpty()) + { + const int fin = formatIndices[0].FormatIndex; + if (fin >= 0) + if (codecs->Formats[fin].Flags_HashHandler()) + title = LangString(IDS_CHECKSUM_CALCULATING); + } /* if (hwndParent != 0) diff --git a/CPP/7zip/UI/GUI/makefile b/CPP/7zip/UI/GUI/makefile index 255c4f24..123410c1 100644 --- a/CPP/7zip/UI/GUI/makefile +++ b/CPP/7zip/UI/GUI/makefile @@ -24,6 +24,7 @@ GUI_OBJS = \ COMMON_OBJS = \ $O\CommandLineParser.obj \ $O\CRC.obj \ + $O\DynLimBuf.obj \ $O\IntToString.obj \ $O\Lang.obj \ $O\ListFileUtils.obj \ @@ -102,6 +103,7 @@ UI_COMMON_OBJS = \ $O\ZipRegistry.obj \ AR_COMMON_OBJS = \ + $O\ItemNameUtils.obj \ $O\OutStreamWithCRC.obj \ FM_OBJS = \ |