diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2017-04-30 03:00:00 +0300 |
---|---|---|
committer | Kornel <kornel@geekhood.net> | 2017-05-05 20:56:20 +0300 |
commit | 2efa10565ac395d2ce9a679ead46e70fb2f963eb (patch) | |
tree | 84c8df4deb69ec44ea15af9378f24347db55c357 /CPP/7zip/Archive | |
parent | 603abd5528c97346e9448c0ff47949f818fe558c (diff) |
17.0017.00
Diffstat (limited to 'CPP/7zip/Archive')
98 files changed, 5767 insertions, 3380 deletions
diff --git a/CPP/7zip/Archive/7z/7zDecode.cpp b/CPP/7zip/Archive/7z/7zDecode.cpp index b0d6dd83..d2687479 100644 --- a/CPP/7zip/Archive/7z/7zDecode.cpp +++ b/CPP/7zip/Archive/7z/7zDecode.cpp @@ -226,11 +226,13 @@ HRESULT CDecoder::Decode( , ISequentialOutStream *outStream , ICompressProgressInfo *compressProgress + , ISequentialInStream ** + #ifdef USE_MIXER_ST + inStreamMainRes + #endif - #ifdef USE_MIXER_ST - inStreamMainRes - #endif + , bool &dataAfterEnd_Error _7Z_DECODER_CRYPRO_VARS_DECL @@ -239,6 +241,8 @@ HRESULT CDecoder::Decode( #endif ) { + dataAfterEnd_Error = false; + const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]]; CFolderEx folderInfo; folders.ParseFolderEx(folderIndex, folderInfo); @@ -415,12 +419,14 @@ HRESULT CDecoder::Decode( } #endif + bool finishMode = false; { CMyComPtr<ICompressSetFinishMode> setFinishMode; decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); if (setFinishMode) { - RINOK(setFinishMode->SetFinishMode(BoolToInt(fullUnpack))); + finishMode = fullUnpack; + RINOK(setFinishMode->SetFinishMode(BoolToInt(finishMode))); } } @@ -450,7 +456,7 @@ HRESULT CDecoder::Decode( unpackSize : &folders.CoderUnpackSizes[unpackStreamIndexStart + i]; - _mixer->SetCoderInfo(i, unpackSizesPointer, packSizesPointers); + _mixer->SetCoderInfo(i, unpackSizesPointer, packSizesPointers, finishMode); } if (outStream) @@ -530,7 +536,9 @@ HRESULT CDecoder::Decode( progress2 = new CDecProgress(compressProgress); ISequentialOutStream *outStreamPointer = outStream; - return _mixer->Code(inStreamPointers, &outStreamPointer, progress2 ? (ICompressProgressInfo *)progress2 : compressProgress); + return _mixer->Code(inStreamPointers, &outStreamPointer, + progress2 ? (ICompressProgressInfo *)progress2 : compressProgress, + dataAfterEnd_Error); } #ifdef USE_MIXER_ST diff --git a/CPP/7zip/Archive/7z/7zDecode.h b/CPP/7zip/Archive/7z/7zDecode.h index 5b729f6c..62a38038 100644 --- a/CPP/7zip/Archive/7z/7zDecode.h +++ b/CPP/7zip/Archive/7z/7zDecode.h @@ -53,7 +53,9 @@ public: , ISequentialOutStream *outStream , ICompressProgressInfo *compressProgress + , ISequentialInStream **inStreamMainRes + , bool &dataAfterEnd_Error _7Z_DECODER_CRYPRO_VARS_DECL diff --git a/CPP/7zip/Archive/7z/7zEncode.cpp b/CPP/7zip/Archive/7z/7zEncode.cpp index 97e9ad7a..b206faa5 100644 --- a/CPP/7zip/Archive/7z/7zEncode.cpp +++ b/CPP/7zip/Archive/7z/7zEncode.cpp @@ -333,7 +333,7 @@ HRESULT CEncoder::Encode( } for (i = 0; i < numMethods; i++) - _mixer->SetCoderInfo(i, NULL, NULL); + _mixer->SetCoderInfo(i, NULL, NULL, false); /* inStreamSize can be used by BCJ2 to set optimal range of conversion. @@ -429,10 +429,12 @@ HRESULT CEncoder::Encode( for (i = 1; i < _bindInfo.PackStreams.Size(); i++) outStreamPointers.Add(tempBuffers[i - 1]); + bool dataAfterEnd_Error; + RINOK(_mixer->Code( &inStreamPointer, &outStreamPointers.Front(), - mtProgress ? (ICompressProgressInfo *)mtProgress : compressProgress)); + mtProgress ? (ICompressProgressInfo *)mtProgress : compressProgress, dataAfterEnd_Error)); if (_bindInfo.PackStreams.Size() != 0) packSizes.Add(outStreamSizeCountSpec->GetSize()); diff --git a/CPP/7zip/Archive/7z/7zExtract.cpp b/CPP/7zip/Archive/7z/7zExtract.cpp index 05fd80de..8fea5aa5 100644 --- a/CPP/7zip/Archive/7z/7zExtract.cpp +++ b/CPP/7zip/Archive/7z/7zExtract.cpp @@ -348,6 +348,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, #endif + bool dataAfterEnd_Error = false; + HRESULT result = decoder.Decode( EXTERNAL_CODECS_VARS _inStream, @@ -358,6 +360,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, outStream, progress, NULL // *inStreamMainRes + , dataAfterEnd_Error _7Z_DECODER_CRYPRO_VARS #if !defined(_7ZIP_ST) && !defined(_SFX) @@ -365,13 +368,19 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, #endif ); - if (result == S_FALSE || result == E_NOTIMPL) + if (result == S_FALSE || result == E_NOTIMPL || dataAfterEnd_Error) { bool wasFinished = folderOutStream->WasWritingFinished(); - - int resOp = (result == S_FALSE ? - NExtract::NOperationResult::kDataError : - NExtract::NOperationResult::kUnsupportedMethod); + + int resOp = NExtract::NOperationResult::kDataError; + + if (result != S_FALSE) + { + if (result == E_NOTIMPL) + resOp = NExtract::NOperationResult::kUnsupportedMethod; + else if (wasFinished && dataAfterEnd_Error) + resOp = NExtract::NOperationResult::kDataAfterEnd; + } RINOK(folderOutStream->FlushCorrupted(resOp)); diff --git a/CPP/7zip/Archive/7z/7zHandler.cpp b/CPP/7zip/Archive/7z/7zHandler.cpp index ccd2c624..2642e691 100644 --- a/CPP/7zip/Archive/7z/7zHandler.cpp +++ b/CPP/7zip/Archive/7z/7zHandler.cpp @@ -540,7 +540,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val */ const CFileItem &item = _db.Files[index]; - UInt32 index2 = index; + const UInt32 index2 = index; switch (propID) { @@ -575,7 +575,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidCTime: SetFileTimeProp_From_UInt64Def(value, _db.CTime, index2); break; case kpidATime: SetFileTimeProp_From_UInt64Def(value, _db.ATime, index2); break; case kpidMTime: SetFileTimeProp_From_UInt64Def(value, _db.MTime, index2); break; - case kpidAttrib: if (item.AttribDefined) PropVarEm_Set_UInt32(value, item.Attrib); break; + case kpidAttrib: if (_db.Attrib.ValidAndDefined(index2)) PropVarEm_Set_UInt32(value, _db.Attrib.Vals[index2]); break; case kpidCRC: if (item.CrcDefined) PropVarEm_Set_UInt32(value, item.Crc); break; case kpidEncrypted: PropVarEm_Set_Bool(value, IsFolderEncrypted(_db.FileIndexToFolderIndexMap[index2])); break; case kpidIsAnti: PropVarEm_Set_Bool(value, _db.IsItemAnti(index2)); break; diff --git a/CPP/7zip/Archive/7z/7zHandler.h b/CPP/7zip/Archive/7z/7zHandler.h index d46401af..89e3275f 100644 --- a/CPP/7zip/Archive/7z/7zHandler.h +++ b/CPP/7zip/Archive/7z/7zHandler.h @@ -54,6 +54,7 @@ public: CBoolPair Write_CTime; CBoolPair Write_ATime; CBoolPair Write_MTime; + CBoolPair Write_Attrib; bool _useMultiThreadMixer; diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp index 2b86ed26..c4fabed7 100644 --- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp +++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp @@ -18,11 +18,12 @@ using namespace NWindows; namespace NArchive { namespace N7z { -static const char *k_LZMA_Name = "LZMA"; -static const char *kDefaultMethodName = "LZMA2"; -static const char *k_Copy_Name = "Copy"; +#define k_LZMA_Name "LZMA" +#define kDefaultMethodName "LZMA2" +#define k_Copy_Name "Copy" + +#define k_MatchFinder_ForHeaders "BT2" -static const char *k_MatchFinder_ForHeaders = "BT2"; static const UInt32 k_NumFastBytes_ForHeaders = 273; static const UInt32 k_Level_ForHeaders = 5; static const UInt32 k_Dictionary_ForHeaders = @@ -113,11 +114,11 @@ HRESULT CHandler::SetMainMethod( FOR_VECTOR (i, methods) { COneMethodInfo &oneMethodInfo = methods[i]; - SetGlobalLevelAndThreads(oneMethodInfo - #ifndef _7ZIP_ST - , numThreads - #endif - ); + + SetGlobalLevelTo(oneMethodInfo); + #ifndef _7ZIP_ST + CMultiMethodProps::SetMethodThreadsTo(oneMethodInfo, numThreads); + #endif CMethodFull &methodFull = methodMode.Methods.AddNew(); RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo)); @@ -282,15 +283,18 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt bool need_CTime = (Write_CTime.Def && Write_CTime.Val); bool need_ATime = (Write_ATime.Def && Write_ATime.Val); bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def); + bool need_Attrib = (Write_Attrib.Def && Write_Attrib.Val || !Write_Attrib.Def); if (db && !db->Files.IsEmpty()) { if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty(); + if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty(); } - UString s; + // UString s; + UString name; for (UInt32 i = 0; i < numItems; i++) { @@ -307,7 +311,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt ui.IsAnti = false; ui.Size = 0; - UString name; + name.Empty(); // bool isAltStream = false; if (ui.IndexInArchive != -1) { @@ -334,6 +338,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (ui.NewProps) { bool folderStatusIsDefined; + if (need_Attrib) { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop)); @@ -377,7 +382,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return E_INVALIDARG; else { - name = NItemName::MakeLegalName(prop.bstrVal); + name = prop.bstrVal; + NItemName::ReplaceSlashes_OsToUnix(name); } } { @@ -614,6 +620,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt options.HeaderOptions.WriteCTime = Write_CTime; options.HeaderOptions.WriteATime = Write_ATime; options.HeaderOptions.WriteMTime = Write_MTime; + options.HeaderOptions.WriteAttrib = Write_Attrib; */ options.NumSolidFiles = _numSolidFiles; @@ -705,6 +712,7 @@ void COutHandler::InitProps() Write_CTime.Init(); Write_ATime.Init(); Write_MTime.Init(); + Write_Attrib.Init(); _useMultiThreadMixer = true; @@ -830,6 +838,8 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime); if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime); + if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib); + if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer); if (name.IsEqualTo("qs")) return PROPVARIANT_to_bool(value, _useTypeSorting); diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp index d8c27175..3db5f515 100644 --- a/CPP/7zip/Archive/7z/7zIn.cpp +++ b/CPP/7zip/Archive/7z/7zIn.cpp @@ -32,6 +32,21 @@ using namespace NCOM; namespace NArchive { namespace N7z { +unsigned BoolVector_CountSum(const CBoolVector &v) +{ + unsigned sum = 0; + const unsigned size = v.Size(); + for (unsigned i = 0; i < size; i++) + if (v[i]) + sum++; + return sum; +} + +static inline bool BoolVector_Item_IsValidAndTrue(const CBoolVector &v, unsigned i) +{ + return (i < v.Size() ? v[i] : false); +} + static void BoolVector_Fill_False(CBoolVector &v, unsigned size) { v.ClearAndSetSize(size); @@ -40,6 +55,7 @@ static void BoolVector_Fill_False(CBoolVector &v, unsigned size) p[i] = false; } + class CInArchiveException {}; class CUnsupportedFeatureException: public CInArchiveException {}; @@ -566,21 +582,30 @@ void CInArchive::WaitId(UInt64 id) } } -void CInArchive::ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs) + +void CInArchive::Read_UInt32_Vector(CUInt32DefVector &v) { - ReadBoolVector2(numItems, crcs.Defs); - crcs.Vals.ClearAndSetSize(numItems); - UInt32 *p = &crcs.Vals[0]; - const bool *defs = &crcs.Defs[0]; + unsigned numItems = v.Defs.Size(); + v.Vals.ClearAndSetSize(numItems); + UInt32 *p = &v.Vals[0]; + const bool *defs = &v.Defs[0]; for (unsigned i = 0; i < numItems; i++) { - UInt32 crc = 0; + UInt32 a = 0; if (defs[i]) - crc = ReadUInt32(); - p[i] = crc; + a = ReadUInt32(); + p[i] = a; } } + +void CInArchive::ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs) +{ + ReadBoolVector2(numItems, crcs.Defs); + Read_UInt32_Vector(crcs); +} + + #define k_Scan_NumCoders_MAX 64 #define k_Scan_NumCodersStreams_in_Folder_MAX 64 @@ -1075,6 +1100,8 @@ HRESULT CInArchive::ReadAndDecodePackedStreams( CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; outStreamSpec->Init(data, unpackSize); + bool dataAfterEnd_Error = false; + HRESULT result = decoder.Decode( EXTERNAL_CODECS_LOC_VARS _stream, baseOffset + dataOffset, @@ -1083,16 +1110,23 @@ HRESULT CInArchive::ReadAndDecodePackedStreams( outStream, NULL, // *compressProgress + NULL // **inStreamMainRes + , dataAfterEnd_Error _7Z_DECODER_CRYPRO_VARS #if !defined(_7ZIP_ST) && !defined(_SFX) , false // mtMode , 1 // numThreads #endif + ); + RINOK(result); + if (dataAfterEnd_Error) + ThereIsHeaderError = true; + if (folders.FolderCRCs.ValidAndDefined(i)) if (CrcCalc(data, unpackSize) != folders.FolderCRCs.Vals[i]) ThrowIncorrect(); @@ -1148,19 +1182,10 @@ HRESULT CInArchive::ReadHeader( type = ReadID(); } - db.Files.Clear(); - if (type == NID::kFilesInfo) { const CNum numFiles = ReadNum(); - db.Files.ClearAndSetSize(numFiles); - /* - db.Files.Reserve(numFiles); - CNum i; - for (i = 0; i < numFiles; i++) - db.Files.Add(CFileItem()); - */ db.ArcInfo.FileInfoPopIDs.Add(NID::kSize); // if (!db.PackSizes.IsEmpty()) @@ -1169,7 +1194,6 @@ HRESULT CInArchive::ReadHeader( db.ArcInfo.FileInfoPopIDs.Add(NID::kCRC); CBoolVector emptyStreamVector; - BoolVector_Fill_False(emptyStreamVector, (unsigned)numFiles); CBoolVector emptyFileVector; CBoolVector antiFileVector; CNum numEmptyStreams = 0; @@ -1197,10 +1221,10 @@ HRESULT CInArchive::ReadHeader( size_t rem = _inByteBack->GetRem(); db.NamesBuf.Alloc(rem); ReadBytes(db.NamesBuf, rem); - db.NameOffsets.Alloc(db.Files.Size() + 1); + db.NameOffsets.Alloc(numFiles + 1); size_t pos = 0; unsigned i; - for (i = 0; i < db.Files.Size(); i++) + for (i = 0; i < numFiles; i++) { size_t curRem = (rem - pos) / 2; const UInt16 *buf = (const UInt16 *)(db.NamesBuf + pos); @@ -1216,36 +1240,31 @@ HRESULT CInArchive::ReadHeader( ThereIsHeaderError = true; break; } + case NID::kWinAttrib: { - CBoolVector boolVector; - ReadBoolVector2(db.Files.Size(), boolVector); + ReadBoolVector2(numFiles, db.Attrib.Defs); CStreamSwitch streamSwitch; streamSwitch.Set(this, &dataVector); - for (CNum i = 0; i < numFiles; i++) - { - CFileItem &file = db.Files[i]; - file.AttribDefined = boolVector[i]; - if (file.AttribDefined) - file.Attrib = ReadUInt32(); - } + Read_UInt32_Vector(db.Attrib); break; } + /* case NID::kIsAux: { - ReadBoolVector(db.Files.Size(), db.IsAux); + ReadBoolVector(numFiles, db.IsAux); break; } case NID::kParent: { db.IsTree = true; // CBoolVector boolVector; - // ReadBoolVector2(db.Files.Size(), boolVector); + // ReadBoolVector2(numFiles, boolVector); // CStreamSwitch streamSwitch; // streamSwitch.Set(this, &dataVector); CBoolVector boolVector; - ReadBoolVector2(db.Files.Size(), boolVector); + ReadBoolVector2(numFiles, boolVector); db.ThereAreAltStreams = false; for (i = 0; i < numFiles; i++) @@ -1264,14 +1283,9 @@ HRESULT CInArchive::ReadHeader( case NID::kEmptyStream: { ReadBoolVector(numFiles, emptyStreamVector); - numEmptyStreams = 0; - for (CNum i = 0; i < (CNum)emptyStreamVector.Size(); i++) - if (emptyStreamVector[i]) - numEmptyStreams++; - - BoolVector_Fill_False(emptyFileVector, numEmptyStreams); - BoolVector_Fill_False(antiFileVector, numEmptyStreams); - + numEmptyStreams = BoolVector_CountSum(emptyStreamVector); + emptyFileVector.Clear(); + antiFileVector.Clear(); break; } case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break; @@ -1314,7 +1328,7 @@ HRESULT CInArchive::ReadHeader( ReadBytes(db.SecureBuf + offset, db.SecureOffsets[i + 1] - offset); } db.SecureIDs.Clear(); - for (unsigned i = 0; i < db.Files.Size(); i++) + for (unsigned i = 0; i < numFiles; i++) { db.SecureIDs.Add(ReadNum()); // db.SecureIDs.Add(ReadUInt32()); @@ -1359,22 +1373,21 @@ HRESULT CInArchive::ReadHeader( CNum emptyFileIndex = 0; CNum sizeIndex = 0; - CNum numAntiItems = 0; + const CNum numAntiItems = BoolVector_CountSum(antiFileVector); - CNum i; + if (numAntiItems != 0) + db.IsAnti.ClearAndSetSize(numFiles); - for (i = 0; i < numEmptyStreams; i++) - if (antiFileVector[i]) - numAntiItems++; + db.Files.ClearAndSetSize(numFiles); - for (i = 0; i < numFiles; i++) + for (CNum i = 0; i < numFiles; i++) { CFileItem &file = db.Files[i]; bool isAnti; - file.HasStream = !emptyStreamVector[i]; file.Crc = 0; - if (file.HasStream) + if (!BoolVector_Item_IsValidAndTrue(emptyStreamVector, i)) { + file.HasStream = true; file.IsDir = false; isAnti = false; file.Size = unpackSizes[sizeIndex]; @@ -1385,26 +1398,31 @@ HRESULT CInArchive::ReadHeader( } else { - file.IsDir = !emptyFileVector[emptyFileIndex]; - isAnti = antiFileVector[emptyFileIndex]; + file.HasStream = false; + file.IsDir = !BoolVector_Item_IsValidAndTrue(emptyFileVector, emptyFileIndex); + isAnti = BoolVector_Item_IsValidAndTrue(antiFileVector, emptyFileIndex); emptyFileIndex++; file.Size = 0; file.CrcDefined = false; } if (numAntiItems != 0) - db.IsAnti.Add(isAnti); + db.IsAnti[i] = isAnti; } + } + db.FillLinks(); - /* - if (type != NID::kEnd) - ThrowIncorrect(); - if (_inByteBack->GetRem() != 0) - ThrowIncorrect(); - */ + + if (type != NID::kEnd || _inByteBack->GetRem() != 0) + { + db.UnsupportedFeatureWarning = true; + // ThrowIncorrect(); + } + return S_OK; } + void CDbEx::FillLinks() { FolderStartFileIndex.Alloc(NumFolders); @@ -1466,6 +1484,7 @@ void CDbEx::FillLinks() } } + HRESULT CInArchive::ReadDatabase2( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db @@ -1610,6 +1629,7 @@ HRESULT CInArchive::ReadDatabase2( ); } + HRESULT CInArchive::ReadDatabase( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db diff --git a/CPP/7zip/Archive/7z/7zIn.h b/CPP/7zip/Archive/7z/7zIn.h index 3592e99b..2d5fbb79 100644 --- a/CPP/7zip/Archive/7z/7zIn.h +++ b/CPP/7zip/Archive/7z/7zIn.h @@ -115,6 +115,7 @@ struct CDatabase: public CFolders CUInt64DefVector ATime; CUInt64DefVector MTime; CUInt64DefVector StartPos; + CUInt32DefVector Attrib; CBoolVector IsAnti; /* CBoolVector IsAux; @@ -146,6 +147,7 @@ struct CDatabase: public CFolders ATime.Clear(); MTime.Clear(); StartPos.Clear(); + Attrib.Clear(); IsAnti.Clear(); // IsAux.Clear(); } @@ -369,6 +371,8 @@ class CInArchive void SkipData() { _inByteBack->SkipData(); } void WaitId(UInt64 id); + void Read_UInt32_Vector(CUInt32DefVector &v); + void ReadArchiveProperties(CInArchiveInfo &archiveInfo); void ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs); diff --git a/CPP/7zip/Archive/7z/7zItem.h b/CPP/7zip/Archive/7z/7zItem.h index 5e2b58f2..ee4aed3f 100644 --- a/CPP/7zip/Archive/7z/7zItem.h +++ b/CPP/7zip/Archive/7z/7zItem.h @@ -26,12 +26,14 @@ struct CCoderInfo bool IsSimpleCoder() const { return NumStreams == 1; } }; + struct CBond { UInt32 PackIndex; UInt32 UnpackIndex; }; + struct CFolder { CLASS_NO_COPY(CFolder) @@ -87,6 +89,7 @@ public: } }; + struct CUInt32DefVector { CBoolVector Defs; @@ -110,9 +113,25 @@ struct CUInt32DefVector Vals.ReserveDown(); } + bool GetItem(unsigned index, UInt32 &value) const + { + if (index < Defs.Size() && Defs[index]) + { + value = Vals[index]; + return true; + } + value = 0; + return false; + } + bool ValidAndDefined(unsigned i) const { return i < Defs.Size() && Defs[i]; } + + bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; } + + void SetItem(unsigned index, bool defined, UInt32 value); }; + struct CUInt64DefVector { CBoolVector Defs; @@ -141,15 +160,15 @@ struct CUInt64DefVector return false; } - void SetItem(unsigned index, bool defined, UInt64 value); - bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; } + + void SetItem(unsigned index, bool defined, UInt64 value); }; + struct CFileItem { UInt64 Size; - UInt32 Attrib; UInt32 Crc; /* int Parent; @@ -159,23 +178,23 @@ struct CFileItem // stream in some folder. It can be empty stream bool IsDir; bool CrcDefined; - bool AttribDefined; + + /* + void Clear() + { + HasStream = true; + IsDir = false; + CrcDefined = false; + } CFileItem(): - /* - Parent(-1), - IsAltStream(false), - */ + // Parent(-1), + // IsAltStream(false), HasStream(true), IsDir(false), CrcDefined(false), - AttribDefined(false) {} - void SetAttrib(UInt32 attrib) - { - AttribDefined = true; - Attrib = attrib; - } + */ }; }} diff --git a/CPP/7zip/Archive/7z/7zOut.cpp b/CPP/7zip/Archive/7z/7zOut.cpp index 3e70f466..904e32c5 100644 --- a/CPP/7zip/Archive/7z/7zOut.cpp +++ b/CPP/7zip/Archive/7z/7zOut.cpp @@ -330,13 +330,11 @@ void COutArchive::WritePropBoolVector(Byte id, const CBoolVector &boolVector) WriteBoolVector(boolVector); } +unsigned BoolVector_CountSum(const CBoolVector &v); + void COutArchive::WriteHashDigests(const CUInt32DefVector &digests) { - unsigned numDefined = 0; - unsigned i; - for (i = 0; i < digests.Defs.Size(); i++) - if (digests.Defs[i]) - numDefined++; + const unsigned numDefined = BoolVector_CountSum(digests.Defs); if (numDefined == 0) return; @@ -348,7 +346,8 @@ void COutArchive::WriteHashDigests(const CUInt32DefVector &digests) WriteByte(0); WriteBoolVector(digests.Defs); } - for (i = 0; i < digests.Defs.Size(); i++) + + for (unsigned i = 0; i < digests.Defs.Size(); i++) if (digests.Defs[i]) WriteUInt32(digests.Vals[i]); } @@ -453,10 +452,12 @@ void COutArchive::WriteSubStreamsInfo(const CObjectVector<CFolder> &folders, // 7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field. -void COutArchive::SkipAlign(unsigned pos, unsigned alignSize) +void COutArchive::SkipToAligned(unsigned pos, unsigned alignShifts) { if (!_useAlign) return; + + const unsigned alignSize = (unsigned)1 << alignShifts; pos += (unsigned)GetPos(); pos &= (alignSize - 1); if (pos == 0) @@ -471,11 +472,11 @@ void COutArchive::SkipAlign(unsigned pos, unsigned alignSize) WriteByte(0); } -void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize) +void COutArchive::WriteAlignedBools(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSizeShifts) { const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v); - const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2; - SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize); + const UInt64 dataSize = ((UInt64)numDefined << itemSizeShifts) + bvSize + 2; + SkipToAligned(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSizeShifts); WriteByte(type); WriteNumber(dataSize); @@ -486,24 +487,18 @@ void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefin WriteByte(0); WriteBoolVector(v); } - WriteByte(0); + WriteByte(0); // 0 means no switching to external stream } void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type) { - unsigned numDefined = 0; - - unsigned i; - for (i = 0; i < v.Defs.Size(); i++) - if (v.Defs[i]) - numDefined++; - + const unsigned numDefined = BoolVector_CountSum(v.Defs); if (numDefined == 0) return; - WriteAlignedBoolHeader(v.Defs, numDefined, type, 8); + WriteAlignedBools(v.Defs, numDefined, type, 3); - for (i = 0; i < v.Defs.Size(); i++) + for (unsigned i = 0; i < v.Defs.Size(); i++) if (v.Defs[i]) WriteUInt64(v.Vals[i]); } @@ -648,7 +643,7 @@ void COutArchive::WriteHeader( if (numDefined > 0) { namesDataSize++; - SkipAlign(2 + GetBigNumberSize(namesDataSize), 16); + SkipToAligned(2 + GetBigNumberSize(namesDataSize), 4); WriteByte(NID::kName); WriteNumber(namesDataSize); @@ -673,28 +668,15 @@ void COutArchive::WriteHeader( { /* ---------- Write Attrib ---------- */ - CBoolVector boolVector; - boolVector.ClearAndSetSize(db.Files.Size()); - unsigned numDefined = 0; - - { - FOR_VECTOR (i, db.Files) - { - bool defined = db.Files[i].AttribDefined; - boolVector[i] = defined; - if (defined) - numDefined++; - } - } + const unsigned numDefined = BoolVector_CountSum(db.Attrib.Defs); if (numDefined != 0) { - WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttrib, 4); - FOR_VECTOR (i, db.Files) + WriteAlignedBools(db.Attrib.Defs, numDefined, NID::kWinAttrib, 2); + FOR_VECTOR (i, db.Attrib.Defs) { - const CFileItem &file = db.Files[i]; - if (file.AttribDefined) - WriteUInt32(file.Attrib); + if (db.Attrib.Defs[i]) + WriteUInt32(db.Attrib.Vals[i]); } } } @@ -702,18 +684,8 @@ void COutArchive::WriteHeader( /* { // ---------- Write IsAux ---------- - unsigned numAux = 0; - const CBoolVector &isAux = db.IsAux; - for (i = 0; i < isAux.Size(); i++) - if (isAux[i]) - numAux++; - if (numAux > 0) - { - const unsigned bvSize = Bv_GetSizeInBytes(isAux); - WriteByte(NID::kIsAux); - WriteNumber(bvSize); - WriteBoolVector(isAux); - } + if (BoolVector_CountSum(db.IsAux) != 0) + WritePropBoolVector(NID::kIsAux, db.IsAux); } { @@ -734,10 +706,10 @@ void COutArchive::WriteHeader( } if (numParentLinks > 0) { - // WriteAlignedBoolHeader(boolVector, numDefined, NID::kParent, 4); + // WriteAlignedBools(boolVector, numDefined, NID::kParent, 2); const unsigned bvSize = (numIsDir == boolVector.Size()) ? 0 : Bv_GetSizeInBytes(boolVector); const UInt64 dataSize = (UInt64)db.Files.Size() * 4 + bvSize + 1; - SkipAlign(2 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), 4); + SkipToAligned(2 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), 2); WriteByte(NID::kParent); WriteNumber(dataSize); @@ -765,7 +737,7 @@ void COutArchive::WriteHeader( // secureDataSize += db.SecureIDs.Size() * 4; for (i = 0; i < db.SecureIDs.Size(); i++) secureDataSize += GetBigNumberSize(db.SecureIDs[i]); - SkipAlign(2 + GetBigNumberSize(secureDataSize), 4); + SkipToAligned(2 + GetBigNumberSize(secureDataSize), 2); WriteByte(NID::kNtSecure); WriteNumber(secureDataSize); WriteByte(0); @@ -888,6 +860,18 @@ HRESULT COutArchive::WriteDatabase( } } +void CUInt32DefVector::SetItem(unsigned index, bool defined, UInt32 value) +{ + while (index >= Defs.Size()) + Defs.Add(false); + Defs[index] = defined; + if (!defined) + return; + while (index >= Vals.Size()) + Vals.Add(0); + Vals[index] = value; +} + void CUInt64DefVector::SetItem(unsigned index, bool defined, UInt64 value) { while (index >= Defs.Size()) @@ -907,6 +891,7 @@ void CArchiveDatabaseOut::AddFile(const CFileItem &file, const CFileItem2 &file2 ATime.SetItem(index, file2.ATimeDefined, file2.ATime); MTime.SetItem(index, file2.MTimeDefined, file2.MTime); StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos); + Attrib.SetItem(index, file2.AttribDefined, file2.Attrib); SetItem_Anti(index, file2.IsAnti); // SetItem_Aux(index, file2.IsAux); Names.Add(name); diff --git a/CPP/7zip/Archive/7z/7zOut.h b/CPP/7zip/Archive/7z/7zOut.h index 6c902668..1ebad56d 100644 --- a/CPP/7zip/Archive/7z/7zOut.h +++ b/CPP/7zip/Archive/7z/7zOut.h @@ -45,6 +45,7 @@ public: size_t GetPos() const { return _pos; } }; + struct CHeaderOptions { bool CompressMainHeader; @@ -71,24 +72,31 @@ struct CFileItem2 UInt64 ATime; UInt64 MTime; UInt64 StartPos; + UInt32 Attrib; + bool CTimeDefined; bool ATimeDefined; bool MTimeDefined; bool StartPosDefined; + bool AttribDefined; bool IsAnti; // bool IsAux; + /* void Init() { CTimeDefined = false; ATimeDefined = false; MTimeDefined = false; StartPosDefined = false; + AttribDefined = false; IsAnti = false; // IsAux = false; } + */ }; + struct COutFolders { CUInt32DefVector FolderUnpackCRCs; // Now we use it for headers only. @@ -111,6 +119,7 @@ struct COutFolders } }; + struct CArchiveDatabaseOut: public COutFolders { CRecordVector<UInt64> PackSizes; @@ -123,10 +132,11 @@ struct CArchiveDatabaseOut: public COutFolders CUInt64DefVector ATime; CUInt64DefVector MTime; CUInt64DefVector StartPos; - CRecordVector<bool> IsAnti; + CUInt32DefVector Attrib; + CBoolVector IsAnti; /* - CRecordVector<bool> IsAux; + CBoolVector IsAux; CByteBuffer SecureBuf; CRecordVector<UInt32> SecureSizes; @@ -154,6 +164,7 @@ struct CArchiveDatabaseOut: public COutFolders ATime.Clear(); MTime.Clear(); StartPos.Clear(); + Attrib.Clear(); IsAnti.Clear(); /* @@ -176,6 +187,7 @@ struct CArchiveDatabaseOut: public COutFolders ATime.ReserveDown(); MTime.ReserveDown(); StartPos.ReserveDown(); + Attrib.ReserveDown(); IsAnti.ReserveDown(); /* @@ -196,11 +208,12 @@ struct CArchiveDatabaseOut: public COutFolders { unsigned size = Files.Size(); return ( - CTime.CheckSize(size) && - ATime.CheckSize(size) && - MTime.CheckSize(size) && - StartPos.CheckSize(size) && - (size == IsAnti.Size() || IsAnti.Size() == 0)); + CTime.CheckSize(size) + && ATime.CheckSize(size) + && MTime.CheckSize(size) + && StartPos.CheckSize(size) + && Attrib.CheckSize(size) + && (size == IsAnti.Size() || IsAnti.Size() == 0)); } bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); } @@ -224,6 +237,7 @@ struct CArchiveDatabaseOut: public COutFolders void AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name); }; + class COutArchive { UInt64 _prefixHeaderPos; @@ -261,8 +275,8 @@ class COutArchive const CRecordVector<UInt64> &unpackSizes, const CUInt32DefVector &digests); - void SkipAlign(unsigned pos, unsigned alignSize); - void WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize); + void SkipToAligned(unsigned pos, unsigned alignShifts); + void WriteAlignedBools(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSizeShifts); void WriteUInt64DefVector(const CUInt64DefVector &v, Byte type); HRESULT EncodeStream( diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp index 68e57f09..e0740e46 100644 --- a/CPP/7zip/Archive/7z/7zUpdate.cpp +++ b/CPP/7zip/Archive/7z/7zUpdate.cpp @@ -1088,18 +1088,23 @@ static HRESULT MakeExeMethod(CCompressionMethodMode &mode, } -static void FromUpdateItemToFileItem(const CUpdateItem &ui, - CFileItem &file, CFileItem2 &file2) +static void UpdateItem_To_FileItem2(const CUpdateItem &ui, CFileItem2 &file2) { - if (ui.AttribDefined) - file.SetAttrib(ui.Attrib); - + file2.Attrib = ui.Attrib; file2.AttribDefined = ui.AttribDefined; file2.CTime = ui.CTime; file2.CTimeDefined = ui.CTimeDefined; file2.ATime = ui.ATime; file2.ATimeDefined = ui.ATimeDefined; file2.MTime = ui.MTime; file2.MTimeDefined = ui.MTimeDefined; file2.IsAnti = ui.IsAnti; // file2.IsAux = false; file2.StartPosDefined = false; + // file2.StartPos = 0; +} + + +static void UpdateItem_To_FileItem(const CUpdateItem &ui, + CFileItem &file, CFileItem2 &file2) +{ + UpdateItem_To_FileItem2(ui, file2); file.Size = ui.Size; file.IsDir = ui.IsDir; @@ -1107,6 +1112,8 @@ static void FromUpdateItemToFileItem(const CUpdateItem &ui, // file.IsAltStream = ui.IsAltStream; } + + class CRepackInStreamWithSizes: public ISequentialInStream, public ICompressGetSubStreamSize, @@ -1437,6 +1444,7 @@ public: #ifndef _7ZIP_ST + bool dataAfterEnd_Error; HRESULT Result; CMyComPtr<IInStream> InStream; @@ -1479,7 +1487,9 @@ void CThreadDecoder::Execute() bool passwordIsDefined = false; UString password; #endif - + + dataAfterEnd_Error = false; + Result = Decoder.Decode( EXTERNAL_CODECS_LOC_VARS InStream, @@ -1491,12 +1501,15 @@ void CThreadDecoder::Execute() Fos, NULL, // compressProgress + NULL // *inStreamMainRes + , dataAfterEnd_Error _7Z_DECODER_CRYPRO_VARS #ifndef _7ZIP_ST , MtMode, NumThreads #endif + ); } catch(...) @@ -1541,6 +1554,7 @@ static void GetFile(const CDatabase &inDb, unsigned index, CFileItem &file, CFil file2.ATimeDefined = inDb.ATime.GetItem(index, file2.ATime); file2.MTimeDefined = inDb.MTime.GetItem(index, file2.MTime); file2.StartPosDefined = inDb.StartPos.GetItem(index, file2.StartPos); + file2.AttribDefined = inDb.Attrib.GetItem(index, file2.Attrib); file2.IsAnti = inDb.IsItemAnti(index); // file2.IsAux = inDb.IsItemAux(index); } @@ -1837,7 +1851,7 @@ HRESULT Update( continue; secureID = ui.SecureIndex; if (ui.NewProps) - FromUpdateItemToFileItem(ui, file, file2); + UpdateItem_To_FileItem(ui, file, file2); else GetFile(*db, ui.IndexInArchive, file, file2); } @@ -1887,7 +1901,8 @@ HRESULT Update( UString name; if (ui.NewProps) { - FromUpdateItemToFileItem(ui, file, file2); + UpdateItem_To_FileItem(ui, file, file2); + file.CrcDefined = false; name = ui.Name; } else @@ -2107,6 +2122,8 @@ HRESULT Update( #endif CMyComPtr<ISequentialInStream> decodedStream; + bool dataAfterEnd_Error = false; + HRESULT res = threadDecoder.Decoder.Decode( EXTERNAL_CODECS_LOC_VARS inStream, @@ -2117,13 +2134,16 @@ HRESULT Update( NULL, // *outStream NULL, // *compressProgress + &decodedStream + , dataAfterEnd_Error _7Z_DECODER_CRYPRO_VARS #ifndef _7ZIP_ST , false // mtMode , 1 // numThreads #endif + ); RINOK(res); @@ -2175,16 +2195,19 @@ HRESULT Update( HRESULT decodeRes = threadDecoder.Result; // if (res == k_My_HRESULT_CRC_ERROR) - if (decodeRes == S_FALSE) + if (decodeRes == S_FALSE || threadDecoder.dataAfterEnd_Error) { if (extractCallback) { RINOK(extractCallback->ReportExtractResult( NEventIndexType::kInArcIndex, db->FolderStartFileIndex[folderIndex], // NEventIndexType::kBlockIndex, (UInt32)folderIndex, - NExtract::NOperationResult::kDataError)); + (decodeRes != S_OK ? + NExtract::NOperationResult::kDataError : + NExtract::NOperationResult::kDataAfterEnd))); } - return E_FAIL; + if (decodeRes != S_OK) + return E_FAIL; } RINOK(decodeRes); if (encodeRes == S_OK) @@ -2224,12 +2247,7 @@ HRESULT Update( CNum indexInFolder = 0; for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) { - CFileItem file; - CFileItem2 file2; - GetFile(*db, fi, file, file2); - UString name; - db->GetPath(fi, name); - if (file.HasStream) + if (db->Files[fi].HasStream) { indexInFolder++; int updateIndex = fileIndexToUpdateIndexMap[fi]; @@ -2238,17 +2256,21 @@ HRESULT Update( const CUpdateItem &ui = updateItems[updateIndex]; if (ui.NewData) continue; + + UString name; + CFileItem file; + CFileItem2 file2; + GetFile(*db, fi, file, file2); + if (ui.NewProps) { - CFileItem uf; - FromUpdateItemToFileItem(ui, uf, file2); - uf.Size = file.Size; - uf.Crc = file.Crc; - uf.CrcDefined = file.CrcDefined; - uf.HasStream = file.HasStream; - file = uf; + UpdateItem_To_FileItem2(ui, file2); + file.IsDir = ui.IsDir; name = ui.Name; } + else + db->GetPath(fi, name); + /* file.Parent = ui.ParentFolderIndex; if (ui.TreeFolderIndex >= 0) @@ -2292,7 +2314,7 @@ HRESULT Update( const CUpdateItem &ui = updateItems[index]; CFileItem file; if (ui.NewProps) - FromUpdateItemToFileItem(ui, file); + UpdateItem_To_FileItem(ui, file); else file = db.Files[ui.IndexInArchive]; if (file.IsAnti || file.IsDir) @@ -2367,7 +2389,7 @@ HRESULT Update( UString name; if (ui.NewProps) { - FromUpdateItemToFileItem(ui, file, file2); + UpdateItem_To_FileItem(ui, file, file2); name = ui.Name; } else @@ -2386,7 +2408,7 @@ HRESULT Update( { skippedSize += ui.Size; continue; - // file.Name.AddAscii(".locked"); + // file.Name += ".locked"; } file.Crc = inStreamSpec->CRCs[subIndex]; diff --git a/CPP/7zip/Archive/ApmHandler.cpp b/CPP/7zip/Archive/ApmHandler.cpp index 51719d53..4d3f2728 100644 --- a/CPP/7zip/Archive/ApmHandler.cpp +++ b/CPP/7zip/Archive/ApmHandler.cpp @@ -6,7 +6,6 @@ #include "../../Common/ComTry.h" #include "../../Common/Defs.h" -#include "../../Common/IntToString.h" #include "../../Windows/PropVariant.h" @@ -232,7 +231,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) int mainIndex = -1; FOR_VECTOR (i, _items) { - AString s = GetString(_items[i].Type); + AString s (GetString(_items[i].Type)); if (s != "Apple_Free" && s != "Apple_partition_map") { @@ -279,14 +278,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { case kpidPath: { - AString s = GetString(item.Name); + AString s (GetString(item.Name)); if (s.IsEmpty()) - { - char s2[32]; - ConvertUInt32ToString(index, s2); - s = s2; - } - AString type = GetString(item.Type); + s.Add_UInt32(index); + AString type (GetString(item.Type)); if (type == "Apple_HFS") type = "hfs"; if (!type.IsEmpty()) diff --git a/CPP/7zip/Archive/ArHandler.cpp b/CPP/7zip/Archive/ArHandler.cpp index 83ed5a02..816a84e4 100644 --- a/CPP/7zip/Archive/ArHandler.cpp +++ b/CPP/7zip/Archive/ArHandler.cpp @@ -688,7 +688,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidShortComment: case kpidSubType: { - AString s = k_TypeExtionsions[(unsigned)_type]; + AString s (k_TypeExtionsions[(unsigned)_type]); if (_subType == kSubType_BSD) s += ":BSD"; prop = s; @@ -720,7 +720,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (item.TextFileIndex >= 0) prop = (item.TextFileIndex == 0) ? "1.txt" : "2.txt"; else - prop = (const wchar_t *)NItemName::GetOSName2(MultiByteToUnicodeString(item.Name, CP_OEMCP)); + prop = (const wchar_t *)NItemName::GetOsPath_Remove_TailSlash(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break; case kpidSize: case kpidPackSize: diff --git a/CPP/7zip/Archive/ArjHandler.cpp b/CPP/7zip/Archive/ArjHandler.cpp index 90819753..fb9e3e7a 100644 --- a/CPP/7zip/Archive/ArjHandler.cpp +++ b/CPP/7zip/Archive/ArjHandler.cpp @@ -5,10 +5,10 @@ #include "../../../C/CpuArch.h" #include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" #include "../../Common/StringConvert.h" #include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" #include "../../Windows/TimeUtils.h" #include "../Common/LimitedStreams.h" @@ -642,16 +642,7 @@ static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop) static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop) { - char temp[16]; - const char *s = NULL; - if (hostOS < ARRAY_SIZE(kHostOS)) - s = kHostOS[hostOS]; - else - { - ConvertUInt32ToString(hostOS, temp); - s = temp; - } - prop = s; + TYPE_TO_PROP(kHostOS, hostOS, prop); } static void SetUnicodeString(const AString &s, NCOM::CPropVariant &prop) @@ -703,7 +694,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val const CItem &item = _items[index]; switch (propID) { - case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break; + case kpidPath: prop = NItemName::GetOsPath(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break; case kpidIsDir: prop = item.IsDir(); break; case kpidSize: prop = item.Size; break; case kpidPackSize: prop = item.PackSize; break; diff --git a/CPP/7zip/Archive/Bz2Handler.cpp b/CPP/7zip/Archive/Bz2Handler.cpp index d1d5f727..98428430 100644 --- a/CPP/7zip/Archive/Bz2Handler.cpp +++ b/CPP/7zip/Archive/Bz2Handler.cpp @@ -179,6 +179,7 @@ STDMETHODIMP CHandler::Close() return S_OK; } + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { @@ -191,8 +192,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (_packSize_Defined) extractCallback->SetTotal(_packSize); - // RINOK(extractCallback->SetCompleted(&packSize)); - CMyComPtr<ISequentialOutStream> realOutStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : @@ -203,7 +202,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, extractCallback->PrepareOperation(askMode); - if (_needSeekToStart) { if (!_stream) @@ -213,14 +211,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, else _needSeekToStart = true; - Int32 opRes; - - try - { + // try { NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder; CMyComPtr<ICompressCoder> decoder = decoderSpec; - decoderSpec->SetInStream(_seqStream); #ifndef _7ZIP_ST RINOK(decoderSpec->SetNumberOfThreads(_props._numThreads)); @@ -237,74 +231,43 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, true); - UInt64 packSize = 0; - UInt64 unpackedSize = 0; - UInt64 numStreams = 0; - - decoderSpec->InitNumBlocks(); + decoderSpec->FinishMode = true; + decoderSpec->Base.DecodeAllStreams = true; - HRESULT result = S_OK; + _dataAfterEnd = false; + _needMoreInput = false; - for (;;) + lps->InSize = 0; + lps->OutSize = 0; + + HRESULT result = decoderSpec->Code(_seqStream, outStream, NULL, NULL, progress); + + if (result != S_FALSE && result != S_OK) + return result; + + if (decoderSpec->Base.NumStreams == 0) { - lps->InSize = packSize; - lps->OutSize = unpackedSize; - - RINOK(lps->SetCur()); - - result = decoderSpec->CodeResume(outStream, progress); - - if (result != S_FALSE && result != S_OK) - return result; - - if (decoderSpec->IsBz) - numStreams++; - else if (numStreams == 0) - { - _isArc = false; - result = S_FALSE; - break; - } - - unpackedSize = outStreamSpec->GetSize(); - UInt64 streamSize = decoderSpec->GetStreamSize(); + _isArc = false; + result = S_FALSE; + } + else + { + const UInt64 inProcessedSize = decoderSpec->GetInputProcessedSize(); + UInt64 packSize = inProcessedSize; - if (streamSize == packSize) - { - // no new bytes in input stream, So it's good end of archive. - result = S_OK; - break; - } + if (decoderSpec->Base.NeedMoreInput) + _needMoreInput = true; - if (!decoderSpec->IsBz) + if (!decoderSpec->Base.IsBz) { - _dataAfterEnd = true; - result = S_FALSE; - break; + packSize = decoderSpec->Base.FinishedPackSize; + if (packSize != inProcessedSize) + _dataAfterEnd = true; } - if (decoderSpec->Base.BitDecoder.ExtraBitsWereRead()) - { - _needMoreInput = true; - packSize = streamSize; - result = S_FALSE; - break; - } - - packSize = decoderSpec->GetInputProcessedSize(); - - if (packSize > streamSize) - return E_FAIL; - - if (result != S_OK) - break; - } - - if (numStreams != 0) - { _packSize = packSize; - _unpackSize = unpackedSize; - _numStreams = numStreams; + _unpackSize = decoderSpec->GetOutProcessedSize(); + _numStreams = decoderSpec->Base.NumStreams; _numBlocks = decoderSpec->GetNumBlocks(); _packSize_Defined = true; @@ -313,32 +276,36 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, _numBlocks_Defined = true; } - decoderSpec->ReleaseInStream(); outStream.Release(); + Int32 opRes; + if (!_isArc) opRes = NExtract::NOperationResult::kIsNotArc; else if (_needMoreInput) opRes = NExtract::NOperationResult::kUnexpectedEnd; - else if (decoderSpec->CrcError) + else if (decoderSpec->GetCrcError()) opRes = NExtract::NOperationResult::kCRCError; else if (_dataAfterEnd) opRes = NExtract::NOperationResult::kDataAfterEnd; else if (result == S_FALSE) opRes = NExtract::NOperationResult::kDataError; + else if (decoderSpec->Base.MinorError) + opRes = NExtract::NOperationResult::kDataError; else if (result == S_OK) opRes = NExtract::NOperationResult::kOK; else return result; - } - catch(const CInBufferException &e) { return e.ErrorCode; } - return extractCallback->SetOperationResult(opRes); + // } catch(...) { return E_FAIL; } + COM_TRY_END } + + static HRESULT UpdateArchive( UInt64 unpackSize, ISequentialOutStream *outStream, diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp index 18f58b3d..c62efbd8 100644 --- a/CPP/7zip/Archive/Cab/CabHandler.cpp +++ b/CPP/7zip/Archive/Cab/CabHandler.cpp @@ -226,12 +226,9 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) if (ai.SetID != 0) { AString s; - char temp[32]; - ConvertUInt32ToString(ai.SetID, temp); - s += temp; - ConvertUInt32ToString(ai.CabinetNumber + 1, temp); + s.Add_UInt32(ai.SetID); s += '_'; - s += temp; + s.Add_UInt32(ai.CabinetNumber + 1); s += ".cab"; prop = s; } @@ -288,7 +285,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val ConvertUTF8ToUnicode(item.Name, unicodeName); else unicodeName = MultiByteToUnicodeString(item.Name, CP_ACP); - prop = (const wchar_t *)NItemName::WinNameToOSName(unicodeName); + prop = (const wchar_t *)NItemName::WinPathToOsPath(unicodeName); break; } @@ -491,7 +488,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, if (!_errorMessage.IsEmpty()) _errorMessage.Add_LF(); - _errorMessage.AddAscii("Can't open volume: "); + _errorMessage += "Can't open volume: "; _errorMessage += fullName; if (prevChecked) diff --git a/CPP/7zip/Archive/Chm/ChmHandler.cpp b/CPP/7zip/Archive/Chm/ChmHandler.cpp index b890d8ff..7ffdafe0 100644 --- a/CPP/7zip/Archive/Chm/ChmHandler.cpp +++ b/CPP/7zip/Archive/Chm/ChmHandler.cpp @@ -135,7 +135,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (us.Len() > 1 && us[0] == L'/') us.Delete(0); } - NItemName::ConvertToOSName2(us); + NItemName::ReplaceToOsSlashes_Remove_TailSlash(us); prop = us; } break; diff --git a/CPP/7zip/Archive/Chm/ChmIn.cpp b/CPP/7zip/Archive/Chm/ChmIn.cpp index 02ecfadd..7e3f155b 100644 --- a/CPP/7zip/Archive/Chm/ChmIn.cpp +++ b/CPP/7zip/Archive/Chm/ChmIn.cpp @@ -38,20 +38,13 @@ struct CHeaderErrorException {}; // define CHM_LOW, if you want to see low level items // #define CHM_LOW -static const GUID kChmLzxGuid = { 0x7FC28940, 0x9D31, 0x11D0, { 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C } }; -static const GUID kHelp2LzxGuid = { 0x0A9007C6, 0x4076, 0x11D3, { 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 } }; -static const GUID kDesGuid = { 0x67F6E4A2, 0x60BF, 0x11D3, { 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF } }; +static const Byte kChmLzxGuid[16] = { 0x40, 0x89, 0xC2, 0x7F, 0x31, 0x9D, 0xD0, 0x11, 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C }; +static const Byte kHelp2LzxGuid[16] = { 0xC6, 0x07, 0x90, 0x0A, 0x76, 0x40, 0xD3, 0x11, 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 }; +static const Byte kDesGuid[16] = { 0xA2, 0xE4, 0xF6, 0x67, 0xBF, 0x60, 0xD3, 0x11, 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF }; -static bool AreGuidsEqual(REFGUID g1, REFGUID g2) +static bool inline AreGuidsEqual(const Byte *g1, const Byte *g2) { - if (g1.Data1 != g2.Data1 || - g1.Data2 != g2.Data2 || - g1.Data3 != g2.Data3) - return false; - for (int i = 0; i < 8; i++) - if (g1.Data4[i] != g2.Data4[i]) - return false; - return true; + return memcmp(g1, g2, 16) == 0; } static char GetHex(unsigned v) @@ -65,35 +58,12 @@ static void PrintByte(Byte b, AString &s) s += GetHex(b & 0xF); } -static void PrintUInt16(UInt16 v, AString &s) -{ - PrintByte((Byte)(v >> 8), s); - PrintByte((Byte)v, s); -} - -static void PrintUInt32(UInt32 v, AString &s) -{ - PrintUInt16((UInt16)(v >> 16), s); - PrintUInt16((UInt16)v, s); -} - AString CMethodInfo::GetGuidString() const { - AString s; - s += '{'; - PrintUInt32(Guid.Data1, s); - s += '-'; - PrintUInt16(Guid.Data2, s); - s += '-'; - PrintUInt16(Guid.Data3, s); - s += '-'; - PrintByte(Guid.Data4[0], s); - PrintByte(Guid.Data4[1], s); - s += '-'; - for (int i = 2; i < 8; i++) - PrintByte(Guid.Data4[i], s); - s += '}'; - return s; + char s[48]; + RawLeGuidToString_Braced(Guid, s); + // MyStringUpper_Ascii(s); + return (AString)s; } bool CMethodInfo::IsLzx() const @@ -108,32 +78,28 @@ bool CMethodInfo::IsDes() const return AreGuidsEqual(Guid, kDesGuid); } -UString CMethodInfo::GetName() const +AString CMethodInfo::GetName() const { - UString s; + AString s; if (IsLzx()) { - s.SetFromAscii("LZX:"); - char temp[16]; - ConvertUInt32ToString(LzxInfo.GetNumDictBits(), temp); - s.AddAscii(temp); + s = "LZX:"; + s.Add_UInt32(LzxInfo.GetNumDictBits()); } else { - AString s2; if (IsDes()) - s2 = "DES"; + s = "DES"; else { - s2 = GetGuidString(); + s = GetGuidString(); if (ControlData.Size() > 0) { - s2 += ':'; + s += ':'; for (size_t i = 0; i < ControlData.Size(); i++) - PrintByte(ControlData[i], s2); + PrintByte(ControlData[i], s); } } - ConvertUTF8ToUnicode(s2, s); } return s; } @@ -153,7 +119,7 @@ UString CSectionInfo::GetMethodName() const UString temp; if (ConvertUTF8ToUnicode(Name, temp)) s += temp; - s.AddAscii(": "); + s += ": "; } FOR_VECTOR (i, Methods) { @@ -220,12 +186,9 @@ UInt64 CInArchive::ReadEncInt() throw CHeaderErrorException(); } -void CInArchive::ReadGUID(GUID &g) +void CInArchive::ReadGUID(Byte *g) { - g.Data1 = ReadUInt32(); - g.Data2 = ReadUInt16(); - g.Data3 = ReadUInt16(); - ReadBytes(g.Data4, 8); + ReadBytes(g, 16); } void CInArchive::ReadString(unsigned size, AString &s) @@ -299,7 +262,7 @@ HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database) // The third and fourth bytes may contain even more fractional bits. // The 4 least significant bits in the last byte are constant. /* UInt32 lang = */ ReadUInt32(); - GUID g; + Byte g[16]; ReadGUID(g); // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC} ReadGUID(g); // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC} const unsigned kNumSections = 2; @@ -422,7 +385,7 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) IsArc = true; ReadUInt32(); // Len of post-header table - GUID g; + Byte g[16]; ReadGUID(g); // {0A9007C1-4076-11D3-8789-0000F8105754} // header section table @@ -637,18 +600,18 @@ HRESULT CInArchive::DecompressStream(IInStream *inStream, const CDatabase &datab #define DATA_SPACE "::DataSpace/" -static const char *kNameList = DATA_SPACE "NameList"; -static const char *kStorage = DATA_SPACE "Storage/"; -static const char *kContent = "Content"; -static const char *kControlData = "ControlData"; -static const char *kSpanInfo = "SpanInfo"; -static const char *kTransform = "Transform/"; -static const char *kResetTable = "/InstanceData/ResetTable"; -static const char *kTransformList = "List"; +#define kNameList DATA_SPACE "NameList" +#define kStorage DATA_SPACE "Storage/" +#define kContent "Content" +#define kControlData "ControlData" +#define kSpanInfo "SpanInfo" +#define kTransform "Transform/" +#define kResetTable "/InstanceData/ResetTable" +#define kTransformList "List" static AString GetSectionPrefix(const AString &name) { - AString s = kStorage; + AString s (kStorage); s += name; s += '/'; return s; @@ -743,7 +706,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) { { // The NameList file - RINOK(DecompressStream(inStream, database, kNameList)); + RINOK(DecompressStream(inStream, database, (AString)kNameList)); /* UInt16 length = */ ReadUInt16(); UInt16 numSections = ReadUInt16(); for (unsigned i = 0; i < numSections; i++) @@ -764,7 +727,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) for (si = 1; si < database.Sections.Size(); si++) { CSectionInfo §ion = database.Sections[si]; - AString sectionPrefix = GetSectionPrefix(section.Name); + AString sectionPrefix (GetSectionPrefix(section.Name)); { // Content int index = database.FindItem(sectionPrefix + kContent); @@ -774,7 +737,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) section.Offset = item.Offset; section.CompressedSize = item.Size; } - AString transformPrefix = sectionPrefix + kTransform; + AString transformPrefix (sectionPrefix + kTransform); if (database.Help2Format) { // Transform List @@ -794,7 +757,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) else { CMethodInfo method; - method.Guid = kChmLzxGuid; + memcpy(method.Guid, kChmLzxGuid, 16); section.Methods.Add(method); } diff --git a/CPP/7zip/Archive/Chm/ChmIn.h b/CPP/7zip/Archive/Chm/ChmIn.h index bf51616f..f7b75d81 100644 --- a/CPP/7zip/Archive/Chm/ChmIn.h +++ b/CPP/7zip/Archive/Chm/ChmIn.h @@ -149,14 +149,14 @@ struct CLzxInfo struct CMethodInfo { - GUID Guid; + Byte Guid[16]; CByteBuffer ControlData; CLzxInfo LzxInfo; bool IsLzx() const; bool IsDes() const; AString GetGuidString() const; - UString GetName() const; + AString GetName() const; }; @@ -243,7 +243,7 @@ class CInArchive UInt64 ReadEncInt(); void ReadString(unsigned size, AString &s); void ReadUString(unsigned size, UString &s); - void ReadGUID(GUID &g); + void ReadGUID(Byte *g); HRESULT ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size); diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp index c6d2bd25..d2dc6c5f 100644 --- a/CPP/7zip/Archive/ComHandler.cpp +++ b/CPP/7zip/Archive/ComHandler.cpp @@ -239,9 +239,6 @@ HRESULT CDatabase::AddNode(int parent, UInt32 did) return S_OK; } -static const wchar_t kCharOpenBracket = L'['; -static const wchar_t kCharCloseBracket = L']'; - static UString CompoundNameToFileName(const UString &s) { UString res; @@ -250,11 +247,9 @@ static UString CompoundNameToFileName(const UString &s) wchar_t c = s[i]; if (c < 0x20) { - res += kCharOpenBracket; - wchar_t buf[32]; - ConvertUInt32ToString(c, buf); - res += buf; - res += kCharCloseBracket; + res += '['; + res.Add_UInt32(c); + res += ']'; } else res += c; @@ -265,8 +260,8 @@ static UString CompoundNameToFileName(const UString &s) static const char k_Msi_Chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._"; -// static const char *k_Msi_ID = ""; // "{msi}"; -static const wchar_t k_Msi_SpecChar = L'!'; +// static const char * const k_Msi_ID = ""; // "{msi}"; +static const char k_Msi_SpecChar = '!'; static const unsigned k_Msi_NumBits = 6; static const unsigned k_Msi_NumChars = 1 << k_Msi_NumBits; @@ -316,10 +311,10 @@ static bool CompoundMsiNameToFileName(const UString &name, UString &res) if (c1 <= k_Msi_NumChars) { - res += (wchar_t)(Byte)k_Msi_Chars[c0]; + res += k_Msi_Chars[c0]; if (c1 == k_Msi_NumChars) break; - res += (wchar_t)(Byte)k_Msi_Chars[c1]; + res += k_Msi_Chars[c1]; } else res += k_Msi_SpecChar; diff --git a/CPP/7zip/Archive/Common/CoderMixer2.cpp b/CPP/7zip/Archive/Common/CoderMixer2.cpp index 41b5805c..7834c605 100644 --- a/CPP/7zip/Archive/Common/CoderMixer2.cpp +++ b/CPP/7zip/Archive/Common/CoderMixer2.cpp @@ -60,6 +60,62 @@ static void BoolVector_Fill_False(CBoolVector &v, unsigned size) p[i] = false; } + +HRESULT CCoder::CheckDataAfterEnd(bool &dataAfterEnd_Error /* , bool &InternalPackSizeError */) const +{ + if (Coder) + { + if (PackSizePointers.IsEmpty() || !PackSizePointers[0]) + return S_OK; + CMyComPtr<ICompressGetInStreamProcessedSize> getInStreamProcessedSize; + Coder.QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize); + // if (!getInStreamProcessedSize) return E_FAIL; + if (getInStreamProcessedSize) + { + UInt64 processed; + RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed)); + if (processed != (UInt64)(Int64)-1) + { + const UInt64 size = PackSizes[0]; + if (processed < size && Finish) + dataAfterEnd_Error = true; + if (processed > size) + { + // InternalPackSizeError = true; + // return S_FALSE; + } + } + } + } + else if (Coder2) + { + CMyComPtr<ICompressGetInStreamProcessedSize2> getInStreamProcessedSize2; + Coder2.QueryInterface(IID_ICompressGetInStreamProcessedSize2, (void **)&getInStreamProcessedSize2); + FOR_VECTOR (i, PackSizePointers) + { + if (!PackSizePointers[i]) + continue; + UInt64 processed; + RINOK(getInStreamProcessedSize2->GetInStreamProcessedSize2(i, &processed)); + if (processed != (UInt64)(Int64)-1) + { + const UInt64 size = PackSizes[i]; + if (processed < size && Finish) + dataAfterEnd_Error = true; + else if (processed > size) + { + // InternalPackSizeError = true; + // return S_FALSE; + } + } + } + } + + return S_OK; +} + + + class CBondsChecks { CBoolVector _coderUsed; @@ -151,8 +207,10 @@ bool CBindInfo::CalcMapsAndCheck() } -void CCoder::SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes) +void CCoder::SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) { + Finish = finish; + if (unpackSize) { UnpackSize = *unpackSize; @@ -640,8 +698,12 @@ void CMixerST::SelectMainCoder(bool useFirst) HRESULT CMixerST::Code( ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress) + ICompressProgressInfo *progress, + bool &dataAfterEnd_Error) { + // InternalPackSizeError = false; + dataAfterEnd_Error = false; + _binderStreams.Clear(); unsigned ci = MainCoderIndex; @@ -742,7 +804,16 @@ HRESULT CMixerST::Code( if (res == k_My_HRESULT_WritingWasCut) res = S_OK; - return res; + + if (res != S_OK) + return res; + + for (i = 0; i < _coders.Size(); i++) + { + RINOK(_coders[i].CheckDataAfterEnd(dataAfterEnd_Error /*, InternalPackSizeError */)); + } + + return S_OK; } @@ -988,8 +1059,12 @@ HRESULT CMixerMT::ReturnIfError(HRESULT code) HRESULT CMixerMT::Code( ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress) + ICompressProgressInfo *progress, + bool &dataAfterEnd_Error) { + // InternalPackSizeError = false; + dataAfterEnd_Error = false; + Init(inStreams, outStreams); unsigned i; @@ -1031,6 +1106,11 @@ HRESULT CMixerMT::Code( return result; } + for (i = 0; i < _coders.Size(); i++) + { + RINOK(_coders[i].CheckDataAfterEnd(dataAfterEnd_Error /* , InternalPackSizeError */)); + } + return S_OK; } diff --git a/CPP/7zip/Archive/Common/CoderMixer2.h b/CPP/7zip/Archive/Common/CoderMixer2.h index e63f2ff0..798411ab 100644 --- a/CPP/7zip/Archive/Common/CoderMixer2.h +++ b/CPP/7zip/Archive/Common/CoderMixer2.h @@ -201,9 +201,13 @@ public: CRecordVector<UInt64> PackSizes; CRecordVector<const UInt64 *> PackSizePointers; - CCoder() {} + bool Finish; - void SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes); + CCoder(): Finish(false) {} + + void SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish); + + HRESULT CheckDataAfterEnd(bool &dataAfterEnd_Error /* , bool &InternalPackSizeError */) const; IUnknown *GetUnknown() const { @@ -239,9 +243,12 @@ protected: public: unsigned MainCoderIndex; + // bool InternalPackSizeError; + CMixer(bool encodeMode): EncodeMode(encodeMode), MainCoderIndex(0) + // , InternalPackSizeError(false) {} /* @@ -273,11 +280,12 @@ public: virtual CCoder &GetCoder(unsigned index) = 0; virtual void SelectMainCoder(bool useFirst) = 0; virtual void ReInit() = 0; - virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes) = 0; + virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) = 0; virtual HRESULT Code( ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress) = 0; + ICompressProgressInfo *progress, + bool &dataAfterEnd_Error) = 0; virtual UInt64 GetBondStreamSize(unsigned bondIndex) const = 0; bool Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex); @@ -338,12 +346,13 @@ public: virtual CCoder &GetCoder(unsigned index); virtual void SelectMainCoder(bool useFirst); virtual void ReInit(); - virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes) - { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes); } + virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) + { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); } virtual HRESULT Code( ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress); + ICompressProgressInfo *progress, + bool &dataAfterEnd_Error); virtual UInt64 GetBondStreamSize(unsigned bondIndex) const; HRESULT GetMainUnpackStream( @@ -419,12 +428,13 @@ public: virtual CCoder &GetCoder(unsigned index); virtual void SelectMainCoder(bool useFirst); virtual void ReInit(); - virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes) - { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes); } + virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) + { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); } virtual HRESULT Code( ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress); + ICompressProgressInfo *progress, + bool &dataAfterEnd_Error); virtual UInt64 GetBondStreamSize(unsigned bondIndex) const; CMixerMT(bool encodeMode): CMixer(encodeMode) {} diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp index 30ca73bd..ea320e66 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.cpp +++ b/CPP/7zip/Archive/Common/HandlerOut.cpp @@ -20,20 +20,19 @@ static void SetMethodProp32(COneMethodInfo &m, PROPID propID, UInt32 value) m.AddProp32(propID, value); } -void CMultiMethodProps::SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo - #ifndef _7ZIP_ST - , UInt32 numThreads - #endif - ) +void CMultiMethodProps::SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const { UInt32 level = _level; if (level != (UInt32)(Int32)-1) SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level); - - #ifndef _7ZIP_ST +} + +#ifndef _7ZIP_ST +void CMultiMethodProps::SetMethodThreadsTo(COneMethodInfo &oneMethodInfo, UInt32 numThreads) +{ SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); - #endif } +#endif void CMultiMethodProps::Init() { @@ -73,7 +72,7 @@ HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIAN return S_OK; } - if (name.IsEqualTo("crc")) + if (name.IsPrefixedBy_Ascii_NoCase("crc")) { name.Delete(0, 3); _crcSize = 4; diff --git a/CPP/7zip/Archive/Common/HandlerOut.h b/CPP/7zip/Archive/Common/HandlerOut.h index 5a18d980..e24686da 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.h +++ b/CPP/7zip/Archive/Common/HandlerOut.h @@ -22,11 +22,13 @@ public: COneMethodInfo _filterMethod; bool _autoFilter; - void SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo - #ifndef _7ZIP_ST - , UInt32 numThreads - #endif - ); + + void SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const; + + #ifndef _7ZIP_ST + static void SetMethodThreadsTo(COneMethodInfo &oneMethodInfo, UInt32 numThreads); + #endif + unsigned GetNumEmptyMethods() const { diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/CPP/7zip/Archive/Common/ItemNameUtils.cpp index 7cd3037b..d5093a24 100644 --- a/CPP/7zip/Archive/Common/ItemNameUtils.cpp +++ b/CPP/7zip/Archive/Common/ItemNameUtils.cpp @@ -7,58 +7,57 @@ namespace NArchive { namespace NItemName { -static const wchar_t kOSDirDelimiter = WCHAR_PATH_SEPARATOR; -static const wchar_t kDirDelimiter = L'/'; +static const wchar_t kOsPathSepar = WCHAR_PATH_SEPARATOR; +static const wchar_t kUnixPathSepar = L'/'; -void ReplaceToOsPathSeparator(wchar_t *s) -{ - #ifdef _WIN32 - for (;;) +void ReplaceSlashes_OsToUnix +#if WCHAR_PATH_SEPARATOR != L'/' + (UString &name) { - wchar_t c = *s; - if (c == 0) - break; - if (c == kDirDelimiter) - *s = kOSDirDelimiter; - s++; + name.Replace(kOsPathSepar, kUnixPathSepar); } - #endif -} +#else + (UString &) {} +#endif -UString MakeLegalName(const UString &name) -{ - UString zipName = name; - zipName.Replace(kOSDirDelimiter, kDirDelimiter); - return zipName; -} -UString GetOSName(const UString &name) +UString GetOsPath(const UString &name) { - UString newName = name; - newName.Replace(kDirDelimiter, kOSDirDelimiter); - return newName; + #if WCHAR_PATH_SEPARATOR != L'/' + UString newName = name; + newName.Replace(kUnixPathSepar, kOsPathSepar); + return newName; + #else + return name; + #endif } -UString GetOSName2(const UString &name) + +UString GetOsPath_Remove_TailSlash(const UString &name) { if (name.IsEmpty()) return UString(); - UString newName = GetOSName(name); - if (newName.Back() == kOSDirDelimiter) + UString newName = GetOsPath(name); + if (newName.Back() == kOsPathSepar) newName.DeleteBack(); return newName; } -void ConvertToOSName2(UString &name) + +void ReplaceToOsSlashes_Remove_TailSlash(UString &name) { if (!name.IsEmpty()) { - name.Replace(kDirDelimiter, kOSDirDelimiter); - if (name.Back() == kOSDirDelimiter) + #if WCHAR_PATH_SEPARATOR != L'/' + name.Replace(kUnixPathSepar, kOsPathSepar); + #endif + + if (name.Back() == kOsPathSepar) name.DeleteBack(); } } + bool HasTailSlash(const AString &name, UINT #if defined(_WIN32) && !defined(UNDER_CE) codePage @@ -67,20 +66,21 @@ bool HasTailSlash(const AString &name, UINT { if (name.IsEmpty()) return false; - LPCSTR prev = - #if defined(_WIN32) && !defined(UNDER_CE) - CharPrevExA((WORD)codePage, name, &name[name.Len()], 0); - #else - (LPCSTR)(name) + (name.Len() - 1); - #endif - return (*prev == '/'); + char c = + #if defined(_WIN32) && !defined(UNDER_CE) + *CharPrevExA((WORD)codePage, name, name.Ptr(name.Len()), 0); + #else + name.Back(); + #endif + return (c == '/'); } + #ifndef _WIN32 -UString WinNameToOSName(const UString &name) +UString WinPathToOsPath(const UString &name) { UString newName = name; - newName.Replace(L'\\', kOSDirDelimiter); + newName.Replace(L'\\', WCHAR_PATH_SEPARATOR); return newName; } #endif diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.h b/CPP/7zip/Archive/Common/ItemNameUtils.h index d0dc76a4..31150864 100644 --- a/CPP/7zip/Archive/Common/ItemNameUtils.h +++ b/CPP/7zip/Archive/Common/ItemNameUtils.h @@ -8,19 +8,20 @@ namespace NArchive { namespace NItemName { - void ReplaceToOsPathSeparator(wchar_t *s); - - UString MakeLegalName(const UString &name); - UString GetOSName(const UString &name); - UString GetOSName2(const UString &name); - void ConvertToOSName2(UString &name); - bool HasTailSlash(const AString &name, UINT codePage); - - #ifdef _WIN32 - inline UString WinNameToOSName(const UString &name) { return name; } - #else - UString WinNameToOSName(const UString &name); - #endif +void ReplaceSlashes_OsToUnix(UString &name); + +UString GetOsPath(const UString &name); +UString GetOsPath_Remove_TailSlash(const UString &name); + +void ReplaceToOsSlashes_Remove_TailSlash(UString &name); + +bool HasTailSlash(const AString &name, UINT codePage); + +#ifdef _WIN32 + inline UString WinPathToOsPath(const UString &name) { return name; } +#else + UString WinPathToOsPath(const UString &name); +#endif }} diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp index e8898cac..b8fb530f 100644 --- a/CPP/7zip/Archive/CpioHandler.cpp +++ b/CPP/7zip/Archive/CpioHandler.cpp @@ -36,7 +36,7 @@ static const Byte kMagicHex = '1'; // New ASCII Format static const Byte kMagicHexCrc = '2'; // New CRC Format static const Byte kMagicOct = '7'; // Portable ASCII Format -static const char *kName_TRAILER = "TRAILER!!!"; +static const char * const kName_TRAILER = "TRAILER!!!"; static const unsigned k_BinRecord_Size = 2 + 8 * 2 + 2 * 4; static const unsigned k_OctRecord_Size = 6 + 8 * 6 + 2 * 11; @@ -627,7 +627,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val #endif if (needConvert) res = MultiByteToUnicodeString(item.Name, CP_OEMCP); - prop = NItemName::GetOSName(res); + prop = NItemName::GetOsPath(res); break; } case kpidIsDir: prop = item.IsDir(); break; diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp index 09952ac8..8acbcea6 100644 --- a/CPP/7zip/Archive/DmgHandler.cpp +++ b/CPP/7zip/Archive/DmgHandler.cpp @@ -183,6 +183,30 @@ struct CExtraFile }; #endif + +struct CForkPair +{ + UInt64 Offset; + UInt64 Len; + + void Parse(const Byte *p) + { + Offset = Get64(p); + Len = Get64(p + 8); + } + + bool UpdateTop(UInt64 limit, UInt64 &top) + { + if (Offset > limit || Len > limit - Offset) + return false; + UInt64 top2 = Offset + Len; + if (top <= top2) + top = top2; + return true; + } +}; + + class CHandler: public IInArchive, public IInArchiveGetStream, @@ -191,14 +215,19 @@ class CHandler: CMyComPtr<IInStream> _inStream; CObjectVector<CFile> _files; bool _masterCrcError; + bool _headersError; UInt64 _startPos; UInt64 _phySize; + + AString _name; #ifdef DMG_SHOW_RAW CObjectVector<CExtraFile> _extras; #endif + HRESULT ReadData(IInStream *stream, const CForkPair &pair, CByteBuffer &buf); + bool ParseBlob(const CByteBuffer &data); HRESULT Open2(IInStream *stream); HRESULT Extract(IInStream *stream); public: @@ -249,24 +278,20 @@ void CMethods::GetString(AString &res) const case METHOD_BZIP2: s = "BZip2"; break; default: ConvertUInt32ToString(type, buf); s = buf; } - res.Add_Space_if_NotEmpty(); - res += s; + res.Add_OptSpaced(s); } for (i = 0; i < ChecksumTypes.Size(); i++) { + res.Add_Space_if_NotEmpty(); UInt32 type = ChecksumTypes[i]; - char buf[32]; - const char *s; switch (type) { - case kCheckSumType_CRC: s = "CRC"; break; + case kCheckSumType_CRC: res += "CRC"; break; default: - ConvertUInt32ToString(type, MyStpCpy(buf, "Check")); - s = buf; + res += "Check"; + res.Add_UInt32(type); } - res.Add_Space_if_NotEmpty(); - res += s; } } @@ -308,7 +333,8 @@ IMP_IInArchive_Props static const Byte kArcProps[] = { kpidMethod, - kpidNumBlocks + kpidNumBlocks, + kpidComment }; STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) @@ -372,9 +398,30 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidWarning: if (_masterCrcError) prop = "Master CRC error"; + + case kpidWarningFlags: + { + UInt32 v = 0; + if (_headersError) v |= kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; break; + } + case kpidOffset: prop = _startPos; break; case kpidPhySize: prop = _phySize; break; + + case kpidComment: + if (!_name.IsEmpty() && _name.Len() < 256) + prop = _name; + break; + + case kpidName: + if (!_name.IsEmpty() && _name.Len() < 256) + { + prop = _name + ".dmg"; + } + break; } prop.Detach(value); return S_OK; @@ -461,7 +508,7 @@ HRESULT CFile::Parse(const Byte *p, UInt32 size) return S_OK; } -static int FindKeyPair(const CXmlItem &item, const AString &key, const AString &nextTag) +static int FindKeyPair(const CXmlItem &item, const char *key, const char *nextTag) { for (unsigned i = 0; i + 1 < item.SubItems.Size(); i++) { @@ -472,7 +519,7 @@ static int FindKeyPair(const CXmlItem &item, const AString &key, const AString & return -1; } -static const AString *GetStringFromKeyPair(const CXmlItem &item, const AString &key, const AString &nextTag) +static const AString *GetStringFromKeyPair(const CXmlItem &item, const char *key, const char *nextTag) { int index = FindKeyPair(item, key, nextTag); if (index >= 0) @@ -498,6 +545,83 @@ static inline bool IsKoly(const Byte *p) */ } + +HRESULT CHandler::ReadData(IInStream *stream, const CForkPair &pair, CByteBuffer &buf) +{ + size_t size = (size_t)pair.Len; + if (size != pair.Len) + return E_OUTOFMEMORY; + buf.Alloc(size); + RINOK(stream->Seek(_startPos + pair.Offset, STREAM_SEEK_SET, NULL)); + return ReadStream_FALSE(stream, buf, size); +} + + +bool CHandler::ParseBlob(const CByteBuffer &data) +{ + if (data.Size() < 12) + return false; + const Byte *p = (const Byte *)data; + if (Get32(p) != 0xFADE0CC0) + return true; + const UInt32 size = Get32(p + 4); + if (size != data.Size()) + return false; + const UInt32 num = Get32(p + 8); + if (num > (size - 12) / 8) + return false; + + for (UInt32 i = 0; i < num; i++) + { + // UInt32 type = Get32(p + i * 8 + 12); + UInt32 offset = Get32(p + i * 8 + 12 + 4); + if (size - offset < 8) + return false; + const Byte *p2 = (const Byte *)data + offset; + const UInt32 magic = Get32(p2); + const UInt32 len = Get32(p2 + 4); + if (size - offset < len || len < 8) + return false; + + #ifdef DMG_SHOW_RAW + CExtraFile &extra = _extras.AddNew(); + extra.Name = "_blob_"; + extra.Data.CopyFrom(p2, len); + #endif + + if (magic == 0xFADE0C02) + { + #ifdef DMG_SHOW_RAW + extra.Name += "codedir"; + #endif + + if (len < 11 * 4) + return false; + UInt32 idOffset = Get32(p2 + 0x14); + if (idOffset >= len) + return false; + UInt32 len2 = len - idOffset; + if (len2 < (1 << 10)) + _name.SetFrom_CalcLen((const char *)(p2 + idOffset), len2); + } + #ifdef DMG_SHOW_RAW + else if (magic == 0xFADE0C01) + extra.Name += "requirements"; + else if (magic == 0xFADE0B01) + extra.Name += "signed"; + else + { + char temp[16]; + ConvertUInt32ToHex8Digits(magic, temp); + extra.Name += temp; + } + #endif + } + + return true; +} + + HRESULT CHandler::Open2(IInStream *stream) { RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPos)); @@ -522,35 +646,69 @@ HRESULT CHandler::Open2(IInStream *stream) // UInt32 flags = Get32(buf + 12); // UInt64 runningDataForkOffset = Get64(buf + 0x10); - UInt64 dataForkOffset = Get64(buf + 0x18); - UInt64 dataForkLen = Get64(buf + 0x20); - UInt64 rsrcOffset = Get64(buf + 0x28); - UInt64 rsrcLen = Get64(buf + 0x30); + + CForkPair dataForkPair, rsrcPair, xmlPair, blobPair; + + dataForkPair.Parse(buf + 0x18); + rsrcPair.Parse(buf + 0x28); + xmlPair.Parse(buf + 0xD8); + blobPair.Parse(buf + 0x128); + // UInt32 segmentNumber = Get32(buf + 0x38); // UInt32 segmentCount = Get32(buf + 0x3C); // Byte segmentGUID[16]; // CChecksum dataForkChecksum; // dataForkChecksum.Parse(buf + 0x50); - UInt64 xmlOffset = Get64(buf + 0xD8); - UInt64 xmlLen = Get64(buf + 0xE0); - - if ( headerPos < dataForkOffset - || headerPos - dataForkOffset < dataForkLen - || headerPos < rsrcOffset - || headerPos - rsrcOffset < rsrcLen - || headerPos < xmlOffset - || headerPos - xmlOffset < xmlLen) - return S_FALSE; - UInt64 totalLen = dataForkLen + rsrcLen + xmlLen; - if (totalLen > headerPos) - return S_FALSE; - _startPos = headerPos - totalLen; - _phySize = totalLen + HEADER_SIZE; - headerPos = totalLen; + _startPos = 0; + + UInt64 top = 0; + if (!dataForkPair.UpdateTop(headerPos, top)) return S_FALSE; + if (!xmlPair.UpdateTop(headerPos, top)) return S_FALSE; + if (!rsrcPair.UpdateTop(headerPos, top)) return S_FALSE; + + /* Some old dmg files contain garbage data in blobPair field. + So we need to ignore such garbage case; + And we still need to detect offset of start of archive for "parser" mode. */ + + bool useBlob = blobPair.UpdateTop(headerPos, top); + + _startPos = 0; + _phySize = headerPos + HEADER_SIZE; + + if (top != headerPos) + { + CForkPair xmlPair2 = xmlPair; + const char *sz = "<?xml version"; + const unsigned len = (unsigned)strlen(sz); + if (xmlPair2.Len > len) + xmlPair2.Len = len; + CByteBuffer buf2; + if (ReadData(stream, xmlPair2, buf2) != S_OK + || memcmp(buf2, sz, len) != 0) + { + _startPos = headerPos - top; + _phySize = top + HEADER_SIZE; + } + } // Byte reserved[0x78] + if (useBlob && blobPair.Len != 0) + { + #ifdef DMG_SHOW_RAW + CExtraFile &extra = _extras.AddNew(); + extra.Name = "_blob.bin"; + CByteBuffer &blobBuf = extra.Data; + #else + CByteBuffer blobBuf; + #endif + RINOK(ReadData(stream, blobPair, blobBuf)); + if (!ParseBlob(blobBuf)) + _headersError = true; + } + + CChecksum masterChecksum; masterChecksum.Parse(buf + 0x160); @@ -562,7 +720,7 @@ HRESULT CHandler::Open2(IInStream *stream) // We don't know the size of the field "offset" in rsrc. // We suppose that it uses 24 bits. So we use Rsrc, only if the rsrcLen < (1 << 24). - bool useRsrc = (rsrcLen > RSRC_HEAD_SIZE && rsrcLen < ((UInt32)1 << 24)); + bool useRsrc = (rsrcPair.Len > RSRC_HEAD_SIZE && rsrcPair.Len < ((UInt32)1 << 24)); // useRsrc = false; if (useRsrc) @@ -575,21 +733,18 @@ HRESULT CHandler::Open2(IInStream *stream) CByteBuffer rsrcBuf; #endif - size_t rsrcLenT = (size_t)rsrcLen; - rsrcBuf.Alloc(rsrcLenT); - RINOK(stream->Seek(_startPos + rsrcOffset, STREAM_SEEK_SET, NULL)); - RINOK(ReadStream_FALSE(stream, rsrcBuf, rsrcLenT)); + RINOK(ReadData(stream, rsrcPair, rsrcBuf)); const Byte *p = rsrcBuf; UInt32 headSize = Get32(p + 0); UInt32 footerOffset = Get32(p + 4); UInt32 mainDataSize = Get32(p + 8); UInt32 footerSize = Get32(p + 12); - if (headSize != RSRC_HEAD_SIZE || - footerOffset >= rsrcLenT || - mainDataSize >= rsrcLenT || - footerOffset + footerSize != rsrcLenT || - footerOffset != headSize + mainDataSize) + if (headSize != RSRC_HEAD_SIZE + || footerOffset >= rsrcPair.Len + || mainDataSize >= rsrcPair.Len + || footerOffset + footerSize != rsrcPair.Len + || footerOffset != headSize + mainDataSize) return S_FALSE; if (footerSize < 16) return S_FALSE; @@ -600,7 +755,7 @@ HRESULT CHandler::Open2(IInStream *stream) if ((UInt32)Get16(p + 0x18) != 0x1C) return S_FALSE; - UInt32 namesOffset = Get16(p + 0x1A); + const UInt32 namesOffset = Get16(p + 0x1A); if (namesOffset > footerSize) return S_FALSE; @@ -612,12 +767,15 @@ HRESULT CHandler::Open2(IInStream *stream) { const Byte *p2 = p + 0x1E + i * 8; - UInt32 typeId = Get32(p2); + const UInt32 typeId = Get32(p2); + + #ifndef DMG_SHOW_RAW if (typeId != 0x626C6B78) // blkx continue; + #endif - UInt32 numFiles = (UInt32)Get16(p2 + 4) + 1; - UInt32 offs = Get16(p2 + 6); + const UInt32 numFiles = (UInt32)Get16(p2 + 4) + 1; + const UInt32 offs = Get16(p2 + 6); if (0x1C + offs + 12 * numFiles > namesOffset) return S_FALSE; @@ -625,7 +783,7 @@ HRESULT CHandler::Open2(IInStream *stream) { const Byte *p3 = p + 0x1C + offs + k * 12; // UInt32 id = Get16(p3); - UInt32 namePos = Get16(p3 + 2); + const UInt32 namePos = Get16(p3 + 2); // Byte attributes = p3[4]; // = 0x50 for blkx // we don't know how many bits we can use. So we use 24 bits only UInt32 blockOffset = Get32(p3 + 4); @@ -634,21 +792,12 @@ HRESULT CHandler::Open2(IInStream *stream) if (blockOffset + 4 >= mainDataSize) return S_FALSE; const Byte *pBlock = rsrcBuf + headSize + blockOffset; - UInt32 blockSize = Get32(pBlock); - - #ifdef DMG_SHOW_RAW - { - CExtraFile &extra = _extras.AddNew(); - { - char extraName[16]; - ConvertUInt32ToString(_files.Size(), extraName); - extra.Name = extraName; - } - extra.Data.CopyFrom(pBlock + 4, blockSize); - } - #endif + const UInt32 blockSize = Get32(pBlock); + if (mainDataSize - (blockOffset + 4) < blockSize) + return S_FALSE; + + AString name; - CFile &file = _files.AddNew(); if (namePos != 0xFFFF) { UInt32 namesBlockSize = footerSize - namesOffset; @@ -663,22 +812,56 @@ HRESULT CHandler::Open2(IInStream *stream) Byte c = namePtr[r]; if (c < 0x20 || c >= 0x80) break; - file.Name += (char)c; + name += (char)c; + } + } + + if (typeId == 0x626C6B78) // blkx + { + CFile &file = _files.AddNew(); + file.Name = name; + RINOK(file.Parse(pBlock + 4, blockSize)); + } + + #ifdef DMG_SHOW_RAW + { + AString name2; + + name2.Add_UInt32(i); + name2 += '_'; + + { + char temp[4 + 1] = { 0 }; + memcpy(temp, p2, 4); + name2 += temp; + } + name2.Trim(); + name2 += '_'; + name2.Add_UInt32(k); + + if (!name.IsEmpty()) + { + name2 += '_'; + name2 += name; } + + CExtraFile &extra = _extras.AddNew(); + extra.Name = name2; + extra.Data.CopyFrom(pBlock + 4, blockSize); } - RINOK(file.Parse(pBlock + 4, blockSize)); + #endif } } } else { - if (xmlLen >= kXmlSizeMax || xmlLen == 0) + if (xmlPair.Len >= kXmlSizeMax || xmlPair.Len == 0) return S_FALSE; - size_t size = (size_t)xmlLen; - if (size != xmlLen) + size_t size = (size_t)xmlPair.Len; + if (size != xmlPair.Len) return S_FALSE; - RINOK(stream->Seek(_startPos + dataForkLen, STREAM_SEEK_SET, NULL)); + RINOK(stream->Seek(_startPos + xmlPair.Offset, STREAM_SEEK_SET, NULL)); CXml xml; { @@ -733,16 +916,12 @@ HRESULT CHandler::Open2(IInStream *stream) const Byte *endPtr = Base64ToBin(rawBuf, *dataString); if (!endPtr) return S_FALSE; - destLen = (unsigned)(endPtr - rawBuf); + destLen = (unsigned)(endPtr - (const Byte *)rawBuf); } #ifdef DMG_SHOW_RAW CExtraFile &extra = _extras.AddNew(); - { - char extraName[16]; - ConvertUInt32ToString(_files.Size(), extraName); - extra.Name = extraName; - } + extra.Name.Add_UInt32(_files.Size()); extra.Data.CopyFrom(rawBuf, destLen); #endif } @@ -800,6 +979,8 @@ STDMETHODIMP CHandler::Close() _inStream.Release(); _files.Clear(); _masterCrcError = false; + _headersError = false; + _name.Empty(); #ifdef DMG_SHOW_RAW _extras.Clear(); #endif @@ -867,9 +1048,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidPath: { UString name; - wchar_t s[16]; - ConvertUInt32ToString(index, s); - name = s; + name.Add_UInt32(index); unsigned num = 10; unsigned numDigits; for (numDigits = 1; num < _files.Size(); numDigits++) @@ -908,7 +1087,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } UString name2; ConvertUTF8ToUnicode(subName, name2); - name += L'.'; + name += '.'; name += name2; } else @@ -916,7 +1095,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val UString name2; ConvertUTF8ToUnicode(item.Name, name2); if (!name2.IsEmpty()) - name.AddAscii(" - "); + name += "_"; name += name2; } prop = name; diff --git a/CPP/7zip/Archive/ElfHandler.cpp b/CPP/7zip/Archive/ElfHandler.cpp index 4543b067..62674774 100644 --- a/CPP/7zip/Archive/ElfHandler.cpp +++ b/CPP/7zip/Archive/ElfHandler.cpp @@ -158,21 +158,21 @@ bool CHeader::Parse(const Byte *p) static const char * const g_SegnmentTypes[] = { - "Unused", - "Loadable segment", - "Dynamic linking tables", - "Program interpreter path name", - "Note section", - "SHLIB", - "Program header table", - "TLS" + "Unused" + , "Loadable segment" + , "Dynamic linking tables" + , "Program interpreter path name" + , "Note section" + , "SHLIB" + , "Program header table" + , "TLS" }; -static const CUInt32PCharPair g_SegmentFlags[] = +static const char * const g_SegmentFlags[] = { - { 0, "Execute" }, - { 1, "Write" }, - { 2, "Read" } + "Execute" + , "Write" + , "Read" }; struct CSegment @@ -359,173 +359,215 @@ bool CSection::Parse(const Byte *p, bool mode64, bool be) return true; } -static const CUInt32PCharPair g_Machines[] = + +static const char * const g_Machines[] = { - { 0, "None" }, - { 1, "AT&T WE 32100" }, - { 2, "SPARC" }, - { 3, "Intel 386" }, - { 4, "Motorola 68000" }, - { 5, "Motorola 88000" }, - { 6, "Intel 486" }, - { 7, "Intel i860" }, - { 8, "MIPS" }, - { 9, "IBM S/370" }, - { 10, "MIPS RS3000 LE" }, - { 11, "RS6000" }, - - { 15, "PA-RISC" }, - { 16, "nCUBE" }, - { 17, "Fujitsu VPP500" }, - { 18, "SPARC 32+" }, - { 19, "Intel i960" }, - { 20, "PowerPC" }, - { 21, "PowerPC 64-bit" }, - { 22, "IBM S/390" }, - { 23, "SPU" }, - - { 36, "NEX v800" }, - { 37, "Fujitsu FR20" }, - { 38, "TRW RH-32" }, - { 39, "Motorola RCE" }, - { 40, "ARM" }, - { 41, "Alpha" }, - { 42, "Hitachi SH" }, - { 43, "SPARC-V9" }, - { 44, "Siemens Tricore" }, - { 45, "ARC" }, - { 46, "H8/300" }, - { 47, "H8/300H" }, - { 48, "H8S" }, - { 49, "H8/500" }, - { 50, "IA-64" }, - { 51, "Stanford MIPS-X" }, - { 52, "Motorola ColdFire" }, - { 53, "M68HC12" }, - { 54, "Fujitsu MMA" }, - { 55, "Siemens PCP" }, - { 56, "Sony nCPU" }, - { 57, "Denso NDR1" }, - { 58, "Motorola StarCore" }, - { 59, "Toyota ME16" }, - { 60, "ST100" }, - { 61, "Advanced Logic TinyJ" }, - { 62, "AMD64" }, - { 63, "Sony DSP" }, - - - { 66, "Siemens FX66" }, - { 67, "ST9+" }, - { 68, "ST7" }, - { 69, "MC68HC16" }, - { 70, "MC68HC11" }, - { 71, "MC68HC08" }, - { 72, "MC68HC05" }, - { 73, "Silicon Graphics SVx" }, - { 74, "ST19" }, - { 75, "Digital VAX" }, - { 76, "Axis CRIS" }, - { 77, "Infineon JAVELIN" }, - { 78, "Element 14 FirePath" }, - { 79, "LSI ZSP" }, - { 80, "MMIX" }, - { 81, "HUANY" }, - { 82, "SiTera Prism" }, - { 83, "Atmel AVR" }, - { 84, "Fujitsu FR30" }, - { 85, "Mitsubishi D10V" }, - { 86, "Mitsubishi D30V" }, - { 87, "NEC v850" }, - { 88, "Mitsubishi M32R" }, - { 89, "Matsushita MN10300" }, - { 90, "Matsushita MN10200" }, - { 91, "picoJava" }, - { 92, "OpenRISC" }, - { 93, "ARC Tangent-A5" }, - { 94, "Tensilica Xtensa" }, - { 95, "Alphamosaic VideoCore" }, - { 96, "Thompson MM GPP" }, - { 97, "National Semiconductor 32K" }, - { 98, "Tenor Network TPC" }, - { 99, "Trebia SNP 1000" }, - { 100, "ST200" }, - { 101, "Ubicom IP2xxx" }, - { 102, "MAX" }, - { 103, "NS CompactRISC" }, - { 104, "Fujitsu F2MC16" }, - { 105, "TI msp430" }, - { 106, "Blackfin (DSP)" }, - { 107, "SE S1C33" }, - { 108, "Sharp embedded" }, - { 109, "Arca RISC" }, - { 110, "Unicore" }, - { 111, "eXcess" }, - { 112, "DXP" }, - { 113, "Altera Nios II" }, - { 114, "NS CRX" }, - { 115, "Motorola XGATE" }, - { 116, "Infineon C16x/XC16x" }, - { 117, "Renesas M16C" }, - { 118, "Microchip Technology dsPIC30F" }, - { 119, "Freescale CE" }, - { 120, "Renesas M32C" }, - - { 131, "Altium TSK3000" }, - { 132, "Freescale RS08" }, - { 133, "Analog Devices SHARC" }, - { 134, "Cyan Technology eCOG2" }, - { 135, "Sunplus S+core7 RISC" }, - { 136, "NJR 24-bit DSP" }, - { 137, "Broadcom VideoCore III" }, - { 138, "Lattice FPGA" }, - { 139, "SE C17" }, - { 140, "TI TMS320C6000" }, - { 141, "TI TMS320C2000" }, - { 142, "TI TMS320C55x" }, - - { 160, "STM 64bit VLIW Data Signal" }, - { 161, "Cypress M8C" }, - { 162, "Renesas R32C" }, - { 163, "NXP TriMedia" }, - { 164, "Qualcomm Hexagon" }, - { 165, "Intel 8051" }, - { 166, "STMicroelectronics STxP7x" }, - { 167, "Andes" }, - { 168, "Cyan Technology eCOG1X" }, - { 169, "Dallas Semiconductor MAXQ30" }, - { 170, "NJR 16-bit DSP" }, - { 171, "M2000" }, - { 172, "Cray NV2" }, - { 173, "Renesas RX" }, - { 174, "Imagination Technologies META" }, - { 175, "MCST Elbrus" }, - { 176, "Cyan Technology eCOG16" }, - { 177, "National Semiconductor CR16" }, - { 178, "Freescale ETPUnit" }, - { 179, "Infineon SLE9X" }, - { 180, "Intel L10M" }, - { 181, "Intel K10M" }, - - { 183, "ARM64" }, - - { 185, "Atmel AVR32" }, - { 186, "STM8" }, - { 187, "Tilera TILE64" }, - { 188, "Tilera TILEPro" }, - { 189, "Xilinx MicroBlaze" }, - { 190, "NVIDIA CUDA" }, - { 191, "Tilera TILE-Gx" }, - { 192, "CloudShield" }, - { 193, "KIPO-KAIST Core-A 1st" }, - { 194, "KIPO-KAIST Core-A 2nd" }, - { 195, "Synopsys ARCompact V2" }, - { 196, "Open8" }, - { 197, "Renesas RL78" }, - { 198, "Broadcom VideoCore V" }, - { 199, "Renesas 78KOR" }, - { 200, "Freescale 56800EX" }, - - { 47787, "Xilinx MicroBlaze" }, + "None" + , "AT&T WE 32100" + , "SPARC" + , "Intel 386" + , "Motorola 68000" + , "Motorola 88000" + , "Intel 486" + , "Intel i860" + , "MIPS" + , "IBM S/370" + , "MIPS RS3000 LE" + , "RS6000" + , NULL + , NULL + , NULL + , "PA-RISC" + , "nCUBE" + , "Fujitsu VPP500" + , "SPARC 32+" + , "Intel i960" + , "PowerPC" + , "PowerPC 64-bit" + , "IBM S/390" + , "SPU" + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , "NEX v800" + , "Fujitsu FR20" + , "TRW RH-32" + , "Motorola RCE" + , "ARM" + , "Alpha" + , "Hitachi SH" + , "SPARC-V9" + , "Siemens Tricore" + , "ARC" + , "H8/300" + , "H8/300H" + , "H8S" + , "H8/500" + , "IA-64" + , "Stanford MIPS-X" + , "Motorola ColdFire" + , "M68HC12" + , "Fujitsu MMA" + , "Siemens PCP" + , "Sony nCPU" + , "Denso NDR1" + , "Motorola StarCore" + , "Toyota ME16" + , "ST100" + , "Advanced Logic TinyJ" + , "AMD64" + , "Sony DSP" + , NULL + , NULL + , "Siemens FX66" + , "ST9+" + , "ST7" + , "MC68HC16" + , "MC68HC11" + , "MC68HC08" + , "MC68HC05" + , "Silicon Graphics SVx" + , "ST19" + , "Digital VAX" + , "Axis CRIS" + , "Infineon JAVELIN" + , "Element 14 FirePath" + , "LSI ZSP" + , "MMIX" + , "HUANY" + , "SiTera Prism" + , "Atmel AVR" + , "Fujitsu FR30" + , "Mitsubishi D10V" + , "Mitsubishi D30V" + , "NEC v850" + , "Mitsubishi M32R" + , "Matsushita MN10300" + , "Matsushita MN10200" + , "picoJava" + , "OpenRISC" + , "ARC Tangent-A5" + , "Tensilica Xtensa" + , "Alphamosaic VideoCore" + , "Thompson MM GPP" + , "National Semiconductor 32K" + , "Tenor Network TPC" + , "Trebia SNP 1000" + , "ST200" + , "Ubicom IP2xxx" + , "MAX" + , "NS CompactRISC" + , "Fujitsu F2MC16" + , "TI msp430" + , "Blackfin (DSP)" + , "SE S1C33" + , "Sharp embedded" + , "Arca RISC" + , "Unicore" + , "eXcess" + , "DXP" + , "Altera Nios II" + , "NS CRX" + , "Motorola XGATE" + , "Infineon C16x/XC16x" + , "Renesas M16C" + , "Microchip Technology dsPIC30F" + , "Freescale CE" + , "Renesas M32C" + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , "Altium TSK3000" + , "Freescale RS08" + , "Analog Devices SHARC" + , "Cyan Technology eCOG2" + , "Sunplus S+core7 RISC" + , "NJR 24-bit DSP" + , "Broadcom VideoCore III" + , "Lattice FPGA" + , "SE C17" + , "TI TMS320C6000" + , "TI TMS320C2000" + , "TI TMS320C55x" + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , "STM 64bit VLIW Data Signal" + , "Cypress M8C" + , "Renesas R32C" + , "NXP TriMedia" + , "Qualcomm Hexagon" + , "Intel 8051" + , "STMicroelectronics STxP7x" + , "Andes" + , "Cyan Technology eCOG1X" + , "Dallas Semiconductor MAXQ30" + , "NJR 16-bit DSP" + , "M2000" + , "Cray NV2" + , "Renesas RX" + , "Imagination Technologies META" + , "MCST Elbrus" + , "Cyan Technology eCOG16" + , "National Semiconductor CR16" + , "Freescale ETPUnit" + , "Infineon SLE9X" + , "Intel L10M" + , "Intel K10M" + , NULL + , "ARM64" + , NULL + , "Atmel AVR32" + , "STM8" + , "Tilera TILE64" + , "Tilera TILEPro" + , "Xilinx MicroBlaze" + , "NVIDIA CUDA" + , "Tilera TILE-Gx" + , "CloudShield" + , "KIPO-KAIST Core-A 1st" + , "KIPO-KAIST Core-A 2nd" + , "Synopsys ARCompact V2" + , "Open8" + , "Renesas RL78" + , "Broadcom VideoCore V" + , "Renesas 78KOR" + , "Freescale 56800EX" // 200 +}; + +static const CUInt32PCharPair g_MachinePairs[] = +{ + { 47787, "Xilinx MicroBlaze" } // { 0x9026, "Alpha" } }; @@ -554,6 +596,7 @@ static const CUInt32PCharPair g_OS[] = { 255, "Standalone" } }; +#define k_Machine_MIPS 8 #define k_Machine_ARM 40 /* @@ -566,12 +609,29 @@ static const CUInt32PCharPair g_OS[] = static const CUInt32PCharPair g_ARM_Flags[] = { + { 1, "HasEntry" }, { 9, "SF" }, { 10, "HF" }, { 23, "BE8" } }; +static const CUInt32PCharPair g_MIPS_Flags[] = +{ + { 0, "NOREORDER" }, + { 1, "PIC" }, + { 2, "CPIC" }, + { 3, "XGOT" }, + { 4, "64BIT_WHIRL" }, + { 5, "ABI2" }, + { 6, "ABI_ON32" }, + { 10, "NAN2008" }, + { 25, "MicroMIPS" }, + { 26, "M16" }, + { 27, "MDMX" } +}; + + #define ET_NONE 0 #define ET_REL 1 #define ET_EXEC 2 @@ -580,11 +640,11 @@ static const CUInt32PCharPair g_ARM_Flags[] = static const char * const g_Types[] = { - "None", - "Relocatable file", - "Executable file", - "Shared object file", - "Core file" + "None" + , "Relocatable file" + , "Executable file" + , "Shared object file" + , "Core file" }; @@ -643,8 +703,7 @@ static const Byte kArcProps[] = kpidBigEndian, kpidHostOS, kpidCharacts, - kpidHeadersSize, - kpidName + kpidHeadersSize }; enum @@ -683,21 +742,49 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidCpu: { - AString s = TypePairToString(g_Machines, ARRAY_SIZE(g_Machines), _header.Machine); + AString s; + if (_header.Machine < ARRAY_SIZE(g_Machines)) + { + const char *name = g_Machines[_header.Machine]; + if (name) + s = name; + } + if (s.IsEmpty()) + s = TypePairToString(g_MachinePairs, ARRAY_SIZE(g_MachinePairs), _header.Machine); UInt32 flags = _header.Flags; if (flags != 0) { - char sz[16]; s.Add_Space(); if (_header.Machine == k_Machine_ARM) { s += FlagsToString(g_ARM_Flags, ARRAY_SIZE(g_ARM_Flags), flags & (((UInt32)1 << 24) - 1)); s += " ABI:"; - ConvertUInt32ToString(flags >> 24, sz); + s.Add_UInt32(flags >> 24); + } + else if (_header.Machine == k_Machine_MIPS) + { + UInt32 ver = flags >> 28; + s += "v"; + s.Add_UInt32(ver); + flags &= (((UInt32)1 << 28) - 1); + + UInt32 abi = (flags >> 12) & 7; + if (abi != 0) + { + s += " ABI:"; + s.Add_UInt32(abi); + } + flags &= ~((UInt32)7 << 12); + + s.Add_Space(); + s += FlagsToString(g_MIPS_Flags, ARRAY_SIZE(g_MIPS_Flags), flags); } else + { + char sz[16]; ConvertUInt32ToHex(flags, sz); - s += sz; + s += sz; + } } prop = s; break; diff --git a/CPP/7zip/Archive/ExtHandler.cpp b/CPP/7zip/Archive/ExtHandler.cpp index 6c2cd726..3b690d07 100644 --- a/CPP/7zip/Archive/ExtHandler.cpp +++ b/CPP/7zip/Archive/ExtHandler.cpp @@ -20,7 +20,6 @@ #include "../../../C/CpuArch.h" #include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" #include "../../Common/MyLinux.h" #include "../../Common/StringConvert.h" #include "../../Common/UTFConvert.h" @@ -37,6 +36,8 @@ using namespace NWindows; +UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size); + namespace NArchive { namespace NExt { @@ -87,33 +88,9 @@ static UInt32 Crc32C_Calc(Byte const *data, size_t size) */ -// CRC-16-ANSI. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) -static UInt16 g_Crc16Table[256]; - -static struct CInitCrc16 -{ - CInitCrc16() - { - for (unsigned i = 0; i < 256; i++) - { - UInt32 r = i; - unsigned j; - for (j = 0; j < 8; j++) - r = (r >> 1) ^ (0xA001 & ~((r & 1) - 1)); - g_Crc16Table[i] = (UInt16)r; - } - } -} g_InitCrc16; - -#define CRC16_UPDATE_BYTE(crc, b) (g_Crc16Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) #define CRC16_INIT_VAL 0xFFFF -static UInt32 Crc16Update(UInt32 crc, Byte const *data, size_t size) -{ - for (size_t i = 0; i < size; i++) - crc = CRC16_UPDATE_BYTE(crc, data[i]); - return crc; -} +#define Crc16Update(crc, data, size) LzhCrc16Update(crc, data, size) static UInt32 Crc16Calc(Byte const *data, size_t size) { @@ -161,64 +138,64 @@ static const char * const kHostOS[] = , "Lites" }; -static const CUInt32PCharPair g_FeatureCompat_Flags[] = -{ - { 0, "DIR_PREALLOC" }, - { 1, "IMAGIC_INODES" }, - { 2, "HAS_JOURNAL" }, - { 3, "EXT_ATTR" }, - { 4, "RESIZE_INODE" }, - { 5, "DIR_INDEX" }, - { 6, "LAZY_BG" }, // not in Linux - // { 7, "EXCLUDE_INODE" }, // not used - // { 8, "EXCLUDE_BITMAP" }, // not in kernel - { 9, "SPARSE_SUPER2" } +static const char * const g_FeatureCompat_Flags[] = +{ + "DIR_PREALLOC" + , "IMAGIC_INODES" + , "HAS_JOURNAL" + , "EXT_ATTR" + , "RESIZE_INODE" + , "DIR_INDEX" + , "LAZY_BG" // not in Linux + , NULL // { 7, "EXCLUDE_INODE" // not used + , NULL // { 8, "EXCLUDE_BITMAP" // not in kernel + , "SPARSE_SUPER2" }; #define EXT4_FEATURE_INCOMPAT_FILETYPE (1 << 1) #define EXT4_FEATURE_INCOMPAT_64BIT (1 << 7) -static const CUInt32PCharPair g_FeatureIncompat_Flags[] = -{ - { 0, "COMPRESSION" }, - { 1, "FILETYPE" }, - { 2, "RECOVER" }, /* Needs recovery */ - { 3, "JOURNAL_DEV" }, /* Journal device */ - { 4, "META_BG" }, - - { 6, "EXTENTS" }, /* extents support */ - { 7, "64BIT" }, - { 8, "MMP" }, - { 9, "FLEX_BG" }, - { 10, "EA_INODE" }, /* EA in inode */ - - { 12, "DIRDATA" }, /* data in dirent */ - { 13, "BG_USE_META_CSUM" }, /* use crc32c for bg */ - { 14, "LARGEDIR" }, /* >2GB or 3-lvl htree */ - { 15, "INLINE_DATA" }, /* data in inode */ - { 16, "ENCRYPT" } +static const char * const g_FeatureIncompat_Flags[] = +{ + "COMPRESSION" + , "FILETYPE" + , "RECOVER" /* Needs recovery */ + , "JOURNAL_DEV" /* Journal device */ + , "META_BG" + , NULL + , "EXTENTS" /* extents support */ + , "64BIT" + , "MMP" + , "FLEX_BG" + , "EA_INODE" /* EA in inode */ + , NULL + , "DIRDATA" /* data in dirent */ + , "BG_USE_META_CSUM" /* use crc32c for bg */ + , "LARGEDIR" /* >2GB or 3-lvl htree */ + , "INLINE_DATA" /* data in inode */ + , "ENCRYPT" // 16 }; static const UInt32 RO_COMPAT_GDT_CSUM = 1 << 4; static const UInt32 RO_COMPAT_METADATA_CSUM = 1 << 10; -static const CUInt32PCharPair g_FeatureRoCompat_Flags[] = -{ - { 0, "SPARSE_SUPER" }, - { 1, "LARGE_FILE" }, - { 2, "BTREE_DIR" }, - { 3, "HUGE_FILE" }, - { 4, "GDT_CSUM" }, - { 5, "DIR_NLINK" }, - { 6, "EXTRA_ISIZE" }, - { 7, "HAS_SNAPSHOT" }, - { 8, "QUOTA" }, - { 9, "BIGALLOC" }, - { 10, "METADATA_CSUM" }, - { 11, "REPLICA" }, - { 12, "READONLY" } +static const char * const g_FeatureRoCompat_Flags[] = +{ + "SPARSE_SUPER" + , "LARGE_FILE" + , "BTREE_DIR" + , "HUGE_FILE" + , "GDT_CSUM" + , "DIR_NLINK" + , "EXTRA_ISIZE" + , "HAS_SNAPSHOT" + , "QUOTA" + , "BIGALLOC" + , "METADATA_CSUM" + , "REPLICA" + , "READONLY" // 12 }; @@ -227,33 +204,37 @@ static const UInt32 k_NodeFlags_HUGE = (UInt32)1 << 18; static const UInt32 k_NodeFlags_EXTENTS = (UInt32)1 << 19; -static const CUInt32PCharPair g_NodeFlags[] = -{ - { 0, "SECRM" }, - { 1, "UNRM" }, - { 2, "COMPR" }, - { 3, "SYNC" }, - { 4, "IMMUTABLE" }, - { 5, "APPEND" }, - { 6, "NODUMP" }, - { 7, "NOATIME" }, - { 8, "DIRTY" }, - { 9, "COMPRBLK" }, - { 10, "NOCOMPR" }, - { 11, "ENCRYPT" }, - { 12, "INDEX" }, - { 13, "IMAGIC" }, - { 14, "JOURNAL_DATA" }, - { 15, "NOTAIL" }, - { 16, "DIRSYNC" }, - { 17, "TOPDIR" }, - { 18, "HUGE_FILE" }, - { 19, "EXTENTS" }, - - { 21, "EA_INODE" }, - { 22, "EOFBLOCKS" }, - - { 28, "INLINE_DATA" } +static const char * const g_NodeFlags[] = +{ + "SECRM" + , "UNRM" + , "COMPR" + , "SYNC" + , "IMMUTABLE" + , "APPEND" + , "NODUMP" + , "NOATIME" + , "DIRTY" + , "COMPRBLK" + , "NOCOMPR" + , "ENCRYPT" + , "INDEX" + , "IMAGIC" + , "JOURNAL_DATA" + , "NOTAIL" + , "DIRSYNC" + , "TOPDIR" + , "HUGE_FILE" + , "EXTENTS" + , NULL + , "EA_INODE" + , "EOFBLOCKS" + , NULL + , NULL + , NULL + , NULL + , NULL + , "INLINE_DATA" // 28 }; @@ -1540,20 +1521,16 @@ HRESULT CHandler::Open2(IInStream *inStream) useUnknown = true; if (item.Name.IsEmpty()) - { - char temp[16]; - ConvertUInt32ToString(item.Node, temp); - item.Name = temp; - } + item.Name.Add_UInt32(item.Node); _items.Add(item); } } if (useSys) - _auxSysIndex = _auxItems.Add("[SYS]"); + _auxSysIndex = _auxItems.Add((AString)"[SYS]"); if (useUnknown) - _auxUnknownIndex = _auxItems.Add("[UNKNOWN]"); + _auxUnknownIndex = _auxItems.Add((AString)"[UNKNOWN]"); } return S_OK; @@ -1834,16 +1811,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidHostOS: { - char temp[16]; - const char *s = NULL; - if (_h.CreatorOs < ARRAY_SIZE(kHostOS)) - s = kHostOS[_h.CreatorOs]; - else - { - ConvertUInt32ToString(_h.CreatorOs, temp); - s = temp; - } - prop = s; + TYPE_TO_PROP(kHostOS, _h.CreatorOs, prop); break; } @@ -1995,39 +1963,34 @@ STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop) { - /* - UInt32 nano = 0; - if (t.Extra != 0) - { - UInt32 mask = t.Extra & 3; - if (mask != 0) - return; - nano = t.Extra >> 2; - } - UInt64 v; - if (t.Val == 0 && nano == 0) + if (t.Val == 0 && t.Extra == 0) return; - if (!NTime::UnixTime_to_FileTime64(t.Val, v)) - return; - if (nano != 0) - v += nano / 100; FILETIME ft; - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); - prop = ft; - */ - if (t.Val == 0) - return; - if (t.Extra != 0) + // if (t.Extra != 0) { - UInt32 mask = t.Extra & 3; - if (mask != 0) - return; + // 1901-2446 : + Int64 v = (Int64)(Int32)t.Val; + v += (UInt64)(t.Extra & 3) << 32; // 2 low bits are offset for main timestamp + UInt64 ft64 = NTime::UnixTime64ToFileTime64(v); + const UInt32 ns = (t.Extra >> 2); + if (ns < 1000000000) + ft64 += ns / 100; + ft.dwLowDateTime = (DWORD)ft64; + ft.dwHighDateTime = (DWORD)(ft64 >> 32); } - FILETIME ft; - if (NTime::UnixTime64ToFileTime(t.Val, ft)) - prop = ft; + /* + else + { + // 1901-2038 : that code is good for ext4 and compatibility with Extra + NTime::UnixTime64ToFileTime((Int32)t.Val, ft); // for + + // 1970-2106 : that code is good if timestamp is used as unsigned 32-bit + // are there such systems? + // NTime::UnixTimeToFileTime(t.Val, ft); // for + } + */ + prop = ft; } @@ -2043,8 +2006,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidPath: case kpidName: { - AString s = _auxItems[index - _items.Size()]; - prop = s; + prop = _auxItems[index - _items.Size()]; break; } case kpidIsDir: prop = true; break; diff --git a/CPP/7zip/Archive/GptHandler.cpp b/CPP/7zip/Archive/GptHandler.cpp index 52c7aab9..a86ad37c 100644 --- a/CPP/7zip/Archive/GptHandler.cpp +++ b/CPP/7zip/Archive/GptHandler.cpp @@ -123,33 +123,11 @@ static int FindPartType(const Byte *guid) return -1; } -static inline char GetHex(unsigned t) { return (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); } -static void PrintHex(unsigned v, char *s) +static void RawLeGuidToString_Upper(const Byte *g, char *s) { - s[0] = GetHex((v >> 4) & 0xF); - s[1] = GetHex(v & 0xF); -} - -static void ConvertUInt16ToHex4Digits(UInt32 val, char *s) throw() -{ - PrintHex(val >> 8, s); - PrintHex(val & 0xFF, s + 2); -} - -static void GuidToString(const Byte *g, char *s) -{ - ConvertUInt32ToHex8Digits(Get32(g ), s); s += 8; *s++ = '-'; - ConvertUInt16ToHex4Digits(Get16(g + 4), s); s += 4; *s++ = '-'; - ConvertUInt16ToHex4Digits(Get16(g + 6), s); s += 4; *s++ = '-'; - for (unsigned i = 0; i < 8; i++) - { - if (i == 2) - *s++ = '-'; - PrintHex(g[8 + i], s); - s += 2; - } - *s = 0; + RawLeGuidToString(g, s); + // MyStringUpper_Ascii(s); } @@ -328,7 +306,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidId: { char s[48]; - GuidToString(Guid, s); + RawLeGuidToString_Upper(Guid, s); prop = s; break; } @@ -364,18 +342,16 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val s += c; } if (s.IsEmpty()) + s.Add_UInt32(index); { - char temp[16]; - ConvertUInt32ToString(index, temp); - s.AddAscii(temp); - } - { + s += '.'; + const char *ext = NULL; int typeIndex = FindPartType(item.Type); - s += L'.'; - const char *ext = "img"; - if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Ext) + if (typeIndex >= 0) ext = kPartTypes[(unsigned)typeIndex].Ext; - s.AddAscii(ext); + if (!ext) + ext = "img"; + s += ext; } prop = s; break; @@ -394,7 +370,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val res = kPartTypes[(unsigned)typeIndex].Type; else { - GuidToString(item.Type, s); + RawLeGuidToString_Upper(item.Type, s); res = s; } prop = res; @@ -404,7 +380,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidId: { char s[48]; - GuidToString(item.Id, s); + RawLeGuidToString_Upper(item.Id, s); prop = s; break; } diff --git a/CPP/7zip/Archive/GzHandler.cpp b/CPP/7zip/Archive/GzHandler.cpp index d8979ada..130f8b35 100644 --- a/CPP/7zip/Archive/GzHandler.cpp +++ b/CPP/7zip/Archive/GzHandler.cpp @@ -11,6 +11,7 @@ #include "../../Common/StringConvert.h" #include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" #include "../../Windows/TimeUtils.h" #include "../Common/ProgressUtils.h" @@ -109,7 +110,6 @@ static const char * const kHostOSes[] = , "OS/X" }; -static const char *kUnknownOS = "Unknown"; class CItem { @@ -537,7 +537,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) if (_item.NameIsPresent()) { UString s = MultiByteToUnicodeString(_item.Name, CP_ACP); - s.AddAscii(".gz"); + s += ".gz"; prop = s; } break; @@ -587,8 +587,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN prop = _packSize; break; } - case kpidHostOS: prop = (_item.HostOS < ARRAY_SIZE(kHostOSes)) ? - kHostOSes[_item.HostOS] : kUnknownOS; break; + case kpidHostOS: TYPE_TO_PROP(kHostOSes, _item.HostOS, prop); break; case kpidCRC: if (_stream) prop = _item.Crc; break; } prop.Detach(value); @@ -1035,7 +1034,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR static const Byte k_Signature[] = { kSignature_0, kSignature_1, kSignature_2 }; REGISTER_ARC_IO( - "gzip", "gz gzip tgz tpz", "* * .tar .tar", 0xEF, + "gzip", "gz gzip tgz tpz apk", "* * .tar .tar .tar", 0xEF, k_Signature, 0, NArcInfoFlags::kKeepName, diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp index 185df7f0..d02f0725 100644 --- a/CPP/7zip/Archive/HfsHandler.cpp +++ b/CPP/7zip/Archive/HfsHandler.cpp @@ -28,7 +28,7 @@ namespace NArchive { namespace NHfs { -static const char *kResFileName = "rsrc"; // "com.apple.ResourceFork"; +static const char * const kResFileName = "rsrc"; // "com.apple.ResourceFork"; struct CExtent { @@ -497,11 +497,14 @@ struct CHeaderRec // UInt32 Attributes; // UInt32 Reserved3[16]; - HRESULT Parse(const Byte *p); + HRESULT Parse2(const CByteBuffer &buf); }; -HRESULT CHeaderRec::Parse(const Byte *p) +HRESULT CHeaderRec::Parse2(const CByteBuffer &buf) { + if (buf.Size() < kNodeDescriptor_Size + 0x2A + 16 * 4) + return S_FALSE; + const Byte * p = (const Byte *)buf + kNodeDescriptor_Size; // TreeDepth = Get16(p); // RootNode = Get32(p + 2); // LeafRecords = Get32(p + 6); @@ -527,6 +530,10 @@ HRESULT CHeaderRec::Parse(const Byte *p) for (int i = 0; i < 16; i++) Reserved3[i] = Get32(p + 0x2A + i * 4); */ + + if ((buf.Size() >> NodeSizeLog) < TotalNodes) + return S_FALSE; + return S_OK; } @@ -553,10 +560,7 @@ HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjec // CNodeDescriptor nodeDesc; // nodeDesc.Parse(p); CHeaderRec hr; - RINOK(hr.Parse(p + kNodeDescriptor_Size)); - - if ((buf.Size() >> hr.NodeSizeLog) < hr.TotalNodes) - return S_FALSE; + RINOK(hr.Parse2(buf)); UInt32 node = hr.FirstLeafNode; if (node == 0) @@ -695,13 +699,10 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe // CNodeDescriptor nodeDesc; // nodeDesc.Parse(p); CHeaderRec hr; - RINOK(hr.Parse(p + kNodeDescriptor_Size)); + RINOK(hr.Parse2(AttrBuf)); // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC); - if ((AttrBuf.Size() >> hr.NodeSizeLog) < hr.TotalNodes) - return S_FALSE; - UInt32 node = hr.FirstLeafNode; if (node == 0) return S_OK; @@ -876,13 +877,10 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents // CNodeDescriptor nodeDesc; // nodeDesc.Parse(p); CHeaderRec hr; - RINOK(hr.Parse(p + kNodeDescriptor_Size)); + RINOK(hr.Parse2(buf)); // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC); - if ((buf.Size() >> hr.NodeSizeLog) < hr.TotalNodes) - return S_FALSE; - CByteBuffer usedBuf(hr.TotalNodes); memset(usedBuf, 0, hr.TotalNodes); @@ -966,13 +964,13 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents IsNameEqualTo(name + 8, "HFS+ Private Data")) { // it's folder for "Hard Links" files - item.Name.SetFromAscii("[HFS+ Private Data]"); + item.Name = "[HFS+ Private Data]"; } } // Some dmg files have ' ' folder item. if (item.Name.IsEmpty() || item.Name[0] == L' ') - item.Name.SetFromAscii("[]"); + item.Name = "[]"; } } @@ -1228,7 +1226,7 @@ HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress) return S_FALSE; */ - ResFileName.SetFromAscii(kResFileName); + ResFileName = kResFileName; CFork extentsFork, catalogFork, attrFork; // allocationFork.Parse(p + 0x70 + 0x50 * 0); diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp index 5a19516c..2230cd23 100644 --- a/CPP/7zip/Archive/Iso/IsoHandler.cpp +++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp @@ -3,7 +3,6 @@ #include "StdAfx.h" #include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/PropVariant.h" @@ -176,12 +175,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { case kpidPath: { - AString s = "[BOOT]" STRING_PATH_SEPARATOR; + AString s ("[BOOT]" STRING_PATH_SEPARATOR); if (_archive.BootEntries.Size() != 1) { - char temp[16]; - ConvertUInt32ToString(index + 1, temp); - s += temp; + s.Add_UInt32(index + 1); s += '-'; } s += be.GetName(); @@ -216,7 +213,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (!s.IsEmpty() && s.Back() == L'.') s.DeleteBack(); - NItemName::ConvertToOSName2(s); + NItemName::ReplaceToOsSlashes_Remove_TailSlash(s); prop = s; } break; diff --git a/CPP/7zip/Archive/Iso/IsoHeader.cpp b/CPP/7zip/Archive/Iso/IsoHeader.cpp index 59c283c1..3b59060a 100644 --- a/CPP/7zip/Archive/Iso/IsoHeader.cpp +++ b/CPP/7zip/Archive/Iso/IsoHeader.cpp @@ -7,6 +7,6 @@ namespace NArchive { namespace NIso { -const char *kElToritoSpec = "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0"; +const char * const kElToritoSpec = "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0"; }} diff --git a/CPP/7zip/Archive/Iso/IsoHeader.h b/CPP/7zip/Archive/Iso/IsoHeader.h index db0b1df9..e6a4d327 100644 --- a/CPP/7zip/Archive/Iso/IsoHeader.h +++ b/CPP/7zip/Archive/Iso/IsoHeader.h @@ -25,7 +25,7 @@ namespace NFileFlags const Byte kNonFinalExtent = 1 << 7; } -extern const char *kElToritoSpec; +extern const char * const kElToritoSpec; const UInt32 kStartPos = 0x8000; diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp index 8530a25e..65be1146 100644 --- a/CPP/7zip/Archive/Iso/IsoIn.cpp +++ b/CPP/7zip/Archive/Iso/IsoIn.cpp @@ -47,17 +47,13 @@ bool CBootInitialEntry::Parse(const Byte *p) AString CBootInitialEntry::GetName() const { - AString s = (Bootable ? "Boot" : "NotBoot"); + AString s (Bootable ? "Boot" : "NotBoot"); s += '-'; if (BootMediaType < ARRAY_SIZE(kMediaTypes)) s += kMediaTypes[BootMediaType]; else - { - char name[16]; - ConvertUInt32ToString(BootMediaType, name); - s += name; - } + s.Add_UInt32(BootMediaType); if (VendorSpec[0] == 1) { diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h index 4000fc92..347f9e9b 100644 --- a/CPP/7zip/Archive/Iso/IsoIn.h +++ b/CPP/7zip/Archive/Iso/IsoIn.h @@ -3,7 +3,6 @@ #ifndef __ARCHIVE_ISO_IN_H #define __ARCHIVE_ISO_IN_H -#include "../../../Common/IntToString.h" #include "../../../Common/MyCom.h" #include "../../IStream.h" diff --git a/CPP/7zip/Archive/Iso/IsoItem.h b/CPP/7zip/Archive/Iso/IsoItem.h index c4950e60..5ae13a60 100644 --- a/CPP/7zip/Archive/Iso/IsoItem.h +++ b/CPP/7zip/Archive/Iso/IsoItem.h @@ -223,6 +223,7 @@ struct CDirRecord const bool GetPx(int skipSize, unsigned pxType, UInt32 &val) const { + val = 0; const Byte *p = NULL; unsigned len = 0; p = FindSuspRecord(skipSize, 'P', 'X', len); diff --git a/CPP/7zip/Archive/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp index c8d3ff6d..53d69db7 100644 --- a/CPP/7zip/Archive/LzhHandler.cpp +++ b/CPP/7zip/Archive/LzhHandler.cpp @@ -9,6 +9,7 @@ #include "../../Common/StringConvert.h" #include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" #include "../../Windows/TimeUtils.h" #include "../ICoder.h" @@ -31,10 +32,44 @@ using namespace NTime; #define Get16(p) GetUi16(p) #define Get32(p) GetUi32(p) + +// CRC-16 (-IBM, -ANSI). The poly is 0x8005 (x^16 + x^15 + x^2 + 1) + +static const UInt16 kCrc16Poly = 0xA001; + +static UInt16 g_LzhCrc16Table[256]; + +#define CRC16_UPDATE_BYTE(crc, b) (g_LzhCrc16Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size) +{ + const Byte *p = (const Byte *)data; + const Byte *pEnd = p + size; + for (; p != pEnd; p++) + crc = CRC16_UPDATE_BYTE(crc, *p); + return crc; +} + +static class CLzhCrc16TableInit +{ +public: + CLzhCrc16TableInit() + { + for (UInt32 i = 0; i < 256; i++) + { + UInt32 r = i; + for (unsigned j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrc16Poly & ((UInt32)0 - (r & 1))); + g_LzhCrc16Table[i] = (UInt16)r; + } + } +} g_LzhCrc16TableInit; + + namespace NArchive { namespace NLzh{ -const int kMethodIdSize = 5; +const unsigned kMethodIdSize = 5; const Byte kExtIdFileName = 0x01; const Byte kExtIdDirName = 0x02; @@ -125,7 +160,7 @@ struct CItem return false; } - int GetNumDictBits() const + unsigned GetNumDictBits() const { if (!IsLhMethod()) return 0; @@ -185,7 +220,7 @@ struct CItem AString GetName() const { - AString dirName = GetDirName(); + AString dirName (GetDirName()); const char kDirSeparator = '\\'; // check kDirSeparator in Linux dirName.Replace((char)(unsigned char)0xFF, kDirSeparator); @@ -310,13 +345,8 @@ static HRESULT GetNextItem(ISequentialInStream *stream, bool &filled, CItem &ite return S_OK; } -struct COsPair -{ - Byte Id; - const char *Name; -}; -static const COsPair g_OsPairs[] = +static const CUInt32PCharPair g_OsPairs[] = { { 0, "MS-DOS" }, { 'M', "MS-DOS" }, @@ -337,15 +367,6 @@ static const COsPair g_OsPairs[] = { 'J', "Java VM" } }; -static const char *kUnknownOS = "Unknown"; - -static const char *GetOS(Byte osId) -{ - for (unsigned i = 0; i < ARRAY_SIZE(g_OsPairs); i++) - if (g_OsPairs[i].Id == osId) - return g_OsPairs[i].Name; - return kUnknownOS; -} static const Byte kProps[] = { @@ -360,52 +381,6 @@ static const Byte kProps[] = kpidHostOS }; -class CCRC -{ - UInt16 _value; -public: - static UInt16 Table[256]; - static void InitTable(); - - CCRC(): _value(0) {} - void Init() { _value = 0; } - void Update(const void *data, size_t size); - UInt16 GetDigest() const { return _value; } -}; - -static const UInt16 kCRCPoly = 0xA001; - -UInt16 CCRC::Table[256]; - -void CCRC::InitTable() -{ - for (UInt32 i = 0; i < 256; i++) - { - UInt32 r = i; - for (int j = 0; j < 8; j++) - if (r & 1) - r = (r >> 1) ^ kCRCPoly; - else - r >>= 1; - CCRC::Table[i] = (UInt16)r; - } -} - -class CCRCTableInit -{ -public: - CCRCTableInit() { CCRC::InitTable(); } -} g_CRCTableInit; - -void CCRC::Update(const void *data, size_t size) -{ - UInt16 v = _value; - const Byte *p = (const Byte *)data; - for (; size > 0; size--, p++) - v = (UInt16)(Table[((Byte)(v)) ^ *p] ^ (v >> 8)); - _value = v; -} - class COutStreamWithCRC: public ISequentialOutStream, @@ -416,41 +391,36 @@ public: STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); private: - CCRC _crc; + UInt32 _crc; CMyComPtr<ISequentialOutStream> _stream; public: void Init(ISequentialOutStream *stream) { _stream = stream; - _crc.Init(); + _crc = 0; } void ReleaseStream() { _stream.Release(); } - UInt32 GetCRC() const { return _crc.GetDigest(); } - void InitCRC() { _crc.Init(); } + UInt32 GetCRC() const { return _crc; } }; STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize) { - UInt32 realProcessedSize; - HRESULT result; - if (!_stream) - { - realProcessedSize = size; - result = S_OK; - } - else - result = _stream->Write(data, size, &realProcessedSize); - _crc.Update(data, realProcessedSize); - if (processedSize != NULL) - *processedSize = realProcessedSize; - return result; + HRESULT res = S_OK; + if (_stream) + res = _stream->Write(data, size, &size); + _crc = LzhCrc16Update(_crc, data, size); + if (processedSize) + *processedSize = size; + return res; } + struct CItemEx: public CItem { UInt64 DataPosition; }; + class CHandler: public IInArchive, public CMyUnknownImp @@ -503,7 +473,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { case kpidPath: { - UString s = NItemName::WinNameToOSName(MultiByteToUnicodeString(item.GetName(), CP_OEMCP)); + UString s = NItemName::WinPathToOsPath(MultiByteToUnicodeString(item.GetName(), CP_OEMCP)); if (!s.IsEmpty()) { if (s.Back() == WCHAR_PATH_SEPARATOR) @@ -516,7 +486,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidSize: prop = item.Size; break; case kpidPackSize: prop = item.PackSize; break; case kpidCRC: prop = (UInt32)item.CRC; break; - case kpidHostOS: prop = GetOS(item.OsId); break; + case kpidHostOS: PAIR_TO_PROP(g_OsPairs, item.OsId, prop); break; case kpidMTime: { FILETIME utc; @@ -571,15 +541,15 @@ STDMETHODIMP CHandler::Open(IInStream *stream, { CItemEx item; bool filled; - HRESULT result = GetNextItem(stream, filled, item); + HRESULT res = GetNextItem(stream, filled, item); RINOK(stream->Seek(0, STREAM_SEEK_CUR, &item.DataPosition)); - if (result == S_FALSE) + if (res == S_FALSE) { _errorFlags = kpv_ErrorFlags_HeadersError; break; } - if (result != S_OK) + if (res != S_OK) return S_FALSE; _phySize = item.DataPosition; if (!filled) @@ -720,14 +690,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, streamSpec->Init(item.PackSize); - HRESULT result = S_OK; + HRESULT res = S_OK; Int32 opRes = NExtract::NOperationResult::kOK; if (item.IsCopyMethod()) { - result = copyCoder->Code(inStream, outStream, NULL, NULL, progress); - if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize) - result = S_FALSE; + res = copyCoder->Code(inStream, outStream, NULL, NULL, progress); + if (res == S_OK && copyCoderSpec->TotalSize != item.PackSize) + res = S_FALSE; } else if (item.IsLh4GroupMethod()) { @@ -738,9 +708,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } lzhDecoderSpec->FinishMode = true; lzhDecoderSpec->SetDictSize(1 << item.GetNumDictBits()); - result = lzhDecoder->Code(inStream, outStream, NULL, ¤tItemUnPacked, progress); - if (result == S_OK && lzhDecoderSpec->GetInputProcessedSize() != item.PackSize) - result = S_FALSE; + res = lzhDecoder->Code(inStream, outStream, NULL, ¤tItemUnPacked, progress); + if (res == S_OK && lzhDecoderSpec->GetInputProcessedSize() != item.PackSize) + res = S_FALSE; } /* else if (item.IsLh1GroupMethod()) @@ -751,7 +721,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, lzh1Decoder = lzh1DecoderSpec; } lzh1DecoderSpec->SetDictionary(item.GetNumDictBits()); - result = lzh1Decoder->Code(inStream, outStream, NULL, ¤tItemUnPacked, progress); + res = lzh1Decoder->Code(inStream, outStream, NULL, ¤tItemUnPacked, progress); } */ else @@ -759,11 +729,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (opRes == NExtract::NOperationResult::kOK) { - if (result == S_FALSE) + if (res == S_FALSE) opRes = NExtract::NOperationResult::kDataError; else { - RINOK(result); + RINOK(res); if (outStreamSpec->GetCRC() != item.CRC) opRes = NExtract::NOperationResult::kCRCError; } diff --git a/CPP/7zip/Archive/LzmaHandler.cpp b/CPP/7zip/Archive/LzmaHandler.cpp index 121cd67c..afdc2bfa 100644 --- a/CPP/7zip/Archive/LzmaHandler.cpp +++ b/CPP/7zip/Archive/LzmaHandler.cpp @@ -44,7 +44,8 @@ static const Byte kProps[] = static const Byte kArcProps[] = { - kpidNumStreams + kpidNumStreams, + kpidMethod }; struct CHeader @@ -53,6 +54,7 @@ struct CHeader Byte FilterID; Byte LzmaProps[5]; + Byte GetProp() const { return LzmaProps[0]; } UInt32 GetDicSize() const { return GetUi32(LzmaProps + 1); } bool HasSize() const { return (Size != (UInt64)(Int64)-1); } bool Parse(const Byte *buf, bool isThereFilter); @@ -197,6 +199,8 @@ class CHandler: UInt64 _unpackSize; UInt64 _numStreams; + void GetMethod(NCOM::CPropVariant &prop); + public: MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq) @@ -220,6 +224,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break; case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break; + case kpidMethod: GetMethod(prop); break; case kpidErrorFlags: { UInt32 v = 0; @@ -229,6 +234,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; if (_dataError) v |= kpv_ErrorFlags_DataError; prop = v; + break; } } prop.Detach(value); @@ -241,23 +247,60 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -static void DictSizeToString(UInt32 value, char *s) + +static void DictSizeToString(UInt32 val, char *s) { - for (int i = 0; i <= 31; i++) - if (((UInt32)1 << i) == value) + for (unsigned i = 0; i <= 31; i++) + if (((UInt32)1 << i) == val) { ::ConvertUInt32ToString(i, s); return; } char c = 'b'; - if ((value & ((1 << 20) - 1)) == 0) { value >>= 20; c = 'm'; } - else if ((value & ((1 << 10) - 1)) == 0) { value >>= 10; c = 'k'; } - ::ConvertUInt32ToString(value, s); + if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } + else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } + ::ConvertUInt32ToString(val, s); s += MyStringLen(s); *s++ = c; *s = 0; } +static char *AddProp32(char *s, const char *name, UInt32 v) +{ + *s++ = ':'; + s = MyStpCpy(s, name); + ::ConvertUInt32ToString(v, s); + return s + MyStringLen(s); +} + +void CHandler::GetMethod(NCOM::CPropVariant &prop) +{ + if (!_stream) + return; + + char sz[64]; + char *s = sz; + if (_header.FilterID != 0) + s = MyStpCpy(s, "BCJ "); + s = MyStpCpy(s, "LZMA:"); + DictSizeToString(_header.GetDicSize(), s); + s += strlen(s); + + UInt32 d = _header.GetProp(); + // if (d != 0x5D) + { + UInt32 lc = d % 9; + d /= 9; + UInt32 pb = d / 5; + UInt32 lp = d % 5; + if (lc != 3) s = AddProp32(s, "lc", lc); + if (lp != 0) s = AddProp32(s, "lp", lp); + if (pb != 2) s = AddProp32(s, "pb", pb); + } + prop = sz; +} + + STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; @@ -265,18 +308,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN { case kpidSize: if (_stream && _header.HasSize()) prop = _header.Size; break; case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; - case kpidMethod: - if (_stream) - { - char sz[64]; - char *s = sz; - if (_header.FilterID != 0) - s = MyStpCpy(s, "BCJ "); - s = MyStpCpy(s, "LZMA:"); - DictSizeToString(_header.GetDicSize(), s); - prop = sz; - } - break; + case kpidMethod: GetMethod(prop); break; } prop.Detach(value); return S_OK; @@ -396,9 +428,9 @@ STDMETHODIMP CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const { if (Callback) { - UInt64 files = 0; - UInt64 value = Offset + *inSize; - return Callback->SetCompleted(&files, &value); + const UInt64 files = 0; + const UInt64 val = Offset + *inSize; + return Callback->SetCompleted(&files, &val); } return S_OK; } @@ -510,7 +542,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { if (dataAfterEnd) _dataAfterEnd = true; - else if (decoder._lzmaDecoderSpec->NeedMoreInput) + else if (decoder._lzmaDecoderSpec->NeedsMoreInput()) _needMoreInput = true; _packSize = packSize; diff --git a/CPP/7zip/Archive/MachoHandler.cpp b/CPP/7zip/Archive/MachoHandler.cpp index 26260686..1f65574d 100644 --- a/CPP/7zip/Archive/MachoHandler.cpp +++ b/CPP/7zip/Archive/MachoHandler.cpp @@ -37,6 +37,7 @@ namespace NMacho { #define CPU_TYPE_PPC64 (CPU_ARCH_ABI64 | CPU_TYPE_PPC) #define CPU_TYPE_AMD64 (CPU_ARCH_ABI64 | CPU_TYPE_386) +#define CPU_TYPE_ARM64 (CPU_ARCH_ABI64 | CPU_TYPE_ARM) #define CPU_SUBTYPE_LIB64 (1 << 31) @@ -60,6 +61,8 @@ static const char * const k_PowerPc_SubTypes[] = static const CUInt32PCharPair g_CpuPairs[] = { + { CPU_TYPE_AMD64, "x64" }, + { CPU_TYPE_ARM64, "ARM64" }, { CPU_TYPE_386, "x86" }, { CPU_TYPE_ARM, "ARM" }, { CPU_TYPE_SPARC, "SPARC" }, @@ -168,7 +171,7 @@ static const CUInt32PCharPair g_Flags[] = { 8, "LOC_RELOC" } }; -static const int kNameSize = 16; +static const unsigned kNameSize = 16; struct CSegment { @@ -255,16 +258,16 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) AString s; char temp[16]; UInt32 cpu = _cpuType & ~(UInt32)CPU_ARCH_ABI64; - if (_cpuType == CPU_TYPE_AMD64) - s = "x64"; - else + UInt32 flag64 = _cpuType & (UInt32)CPU_ARCH_ABI64; { const char *n = NULL; for (unsigned i = 0; i < ARRAY_SIZE(g_CpuPairs); i++) { const CUInt32PCharPair &pair = g_CpuPairs[i]; - if (pair.Value == cpu) + if (pair.Value == cpu || pair.Value == _cpuType) { + if (pair.Value == _cpuType) + flag64 = 0; n = pair.Name; break; } @@ -276,10 +279,10 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } s = n; - if (_cpuType & CPU_ARCH_ABI64) + if (flag64 != 0) s += " 64-bit"; - else if (_cpuSubType & CPU_SUBTYPE_LIB64) - s += " 64-bit lib"; + else if ((_cpuSubType & CPU_SUBTYPE_LIB64) && _cpuType != CPU_TYPE_AMD64) + s += " 64-bit-lib"; } UInt32 t = _cpuSubType & ~(UInt32)CPU_SUBTYPE_LIB64; if (t != 0 && (t != CPU_SUBTYPE_I386_ALL || cpu != CPU_TYPE_386)) @@ -306,8 +309,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidCharacts: { // TYPE_TO_PROP(g_FileTypes, _type, prop); break; - AString res = TypeToString(g_FileTypes, ARRAY_SIZE(g_FileTypes), _type); - AString s = FlagsToString(g_ArcFlags, ARRAY_SIZE(g_ArcFlags), _flags); + AString res (TypeToString(g_FileTypes, ARRAY_SIZE(g_FileTypes), _type)); + AString s (FlagsToString(g_ArcFlags, ARRAY_SIZE(g_ArcFlags), _flags)); if (!s.IsEmpty()) { res.Add_Space(); @@ -345,20 +348,9 @@ static AString GetName(const char *name) char res[kNameSize + 1]; memcpy(res, name, kNameSize); res[kNameSize] = 0; - return res; + return (AString)res; } -static AString SectFlagsToString(UInt32 flags) -{ - AString res = TypeToString(g_SectTypes, ARRAY_SIZE(g_SectTypes), flags & SECT_TYPE_MASK); - AString s = FlagsToString(g_Flags, ARRAY_SIZE(g_Flags), flags & SECT_ATTR_MASK); - if (!s.IsEmpty()) - { - res.Add_Space(); - res += s; - } - return res; -} STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { @@ -369,7 +361,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { case kpidPath: { - AString s = GetName(_segments[item.SegmentIndex].Name); + AString s (GetName(_segments[item.SegmentIndex].Name)); if (!item.IsDummy) s += GetName(item.Name); prop = MultiByteToUnicodeString(s); @@ -377,7 +369,19 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } case kpidSize: /* prop = (UInt64)item.VSize; break; */ case kpidPackSize: prop = (UInt64)item.GetPackSize(); break; - case kpidCharacts: if (!item.IsDummy) prop = SectFlagsToString(item.Flags); break; + case kpidCharacts: + if (!item.IsDummy) + { + AString res (TypeToString(g_SectTypes, ARRAY_SIZE(g_SectTypes), item.Flags & SECT_TYPE_MASK)); + AString s (FlagsToString(g_Flags, ARRAY_SIZE(g_Flags), item.Flags & SECT_ATTR_MASK)); + if (!s.IsEmpty()) + { + res.Add_Space(); + res += s; + } + prop = res; + } + break; case kpidOffset: prop = item.Pa; break; case kpidVa: prop = item.Va; break; } @@ -386,6 +390,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_END } + HRESULT CHandler::Open2(ISequentialInStream *stream) { const UInt32 kStartHeaderSize = 7 * 4; @@ -402,6 +407,9 @@ HRESULT CHandler::Open2(ISequentialInStream *stream) default: return S_FALSE; } + _mode64 = mode64; + _be = be; + UInt32 numCommands = Get32(header + 0x10, be); UInt32 commandsSize = Get32(header + 0x14, be); diff --git a/CPP/7zip/Archive/MbrHandler.cpp b/CPP/7zip/Archive/MbrHandler.cpp index b92755ae..14a1224c 100644 --- a/CPP/7zip/Archive/MbrHandler.cpp +++ b/CPP/7zip/Archive/MbrHandler.cpp @@ -63,21 +63,14 @@ static int CompareChs(const CChs &c1, const CChs &c2) } */ -static void AddUIntToString(UInt32 val, AString &res) -{ - char s[16]; - ConvertUInt32ToString(val, s); - res += s; -} - void CChs::ToString(NCOM::CPropVariant &prop) const { AString s; - AddUIntToString(GetCyl(), s); + s.Add_UInt32(GetCyl()); s += '-'; - AddUIntToString(Head, s); + s.Add_UInt32(Head); s += '-'; - AddUIntToString(GetSector(), s); + s.Add_UInt32(GetSector()); prop = s; } @@ -137,7 +130,7 @@ struct CPartType const char *Name; }; -static const char *kFat = "fat"; +#define kFat "fat" static const CPartType kPartTypes[] = { @@ -156,6 +149,7 @@ static const CPartType kPartTypes[] = { 0x1B, kFat, "FAT32-Hidden" }, { 0x1C, kFat, "FAT32-LBA-Hidden" }, { 0x1E, kFat, "FAT16-LBA-WIN95-Hidden" }, + { 0x27, "ntfs", "NTFS-WinRE" }, { 0x82, 0, "Solaris x86 / Linux swap" }, { 0x83, 0, "Linux" }, { 0x8E, "lvm", "Linux LVM" }, @@ -399,14 +393,16 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidPath: { AString s; - AddUIntToString(index, s); + s.Add_UInt32(index); if (item.IsReal) { - int typeIndex = FindPartType(part.Type); s += '.'; - const char *ext = "img"; - if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Ext) + const char *ext = NULL; + int typeIndex = FindPartType(part.Type); + if (typeIndex >= 0) ext = kPartTypes[(unsigned)typeIndex].Ext; + if (!ext) + ext = "img"; s += ext; } prop = s; diff --git a/CPP/7zip/Archive/MslzHandler.cpp b/CPP/7zip/Archive/MslzHandler.cpp index ec375733..6f9057a6 100644 --- a/CPP/7zip/Archive/MslzHandler.cpp +++ b/CPP/7zip/Archive/MslzHandler.cpp @@ -159,7 +159,7 @@ void CHandler::ParseName(Byte replaceByte, IArchiveOpenCallback *callback) } if (replaceByte >= 0x20 && replaceByte < 0x80) - _name += (wchar_t)replaceByte; + _name += (char)replaceByte; } STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, diff --git a/CPP/7zip/Archive/MubHandler.cpp b/CPP/7zip/Archive/MubHandler.cpp index 56b8aa32..6d054356 100644 --- a/CPP/7zip/Archive/MubHandler.cpp +++ b/CPP/7zip/Archive/MubHandler.cpp @@ -31,6 +31,7 @@ namespace NMub { #define MACH_CPU_TYPE_PPC64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_PPC) #define MACH_CPU_TYPE_AMD64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_386) +#define MACH_CPU_TYPE_ARM64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_ARM) #define MACH_CPU_SUBTYPE_LIB64 (1 << 31) @@ -105,17 +106,20 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val const char *ext = 0; switch (item.Type) { - case MACH_CPU_TYPE_386: ext = "x86"; break; + case MACH_CPU_TYPE_386: ext = "x86"; break; case MACH_CPU_TYPE_ARM: ext = "arm"; break; case MACH_CPU_TYPE_SPARC: ext = "sparc"; break; case MACH_CPU_TYPE_PPC: ext = "ppc"; break; - case MACH_CPU_TYPE_PPC64: ext = "ppc64"; break; case MACH_CPU_TYPE_AMD64: ext = "x64"; break; + case MACH_CPU_TYPE_ARM64: ext = "arm64"; break; + case MACH_CPU_TYPE_PPC64: ext = "ppc64"; break; default: temp[0] = 'c'; temp[1] = 'p'; temp[2] = 'u'; - ConvertUInt32ToString(item.Type, temp + 3); + ConvertUInt32ToString(item.Type & ~MACH_CPU_ARCH_ABI64, temp + 3); + if (item.Type & MACH_CPU_ARCH_ABI64) + MyStringCopy(temp + MyStringLen(temp), "_64"); break; } if (ext) diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.cpp b/CPP/7zip/Archive/Nsis/NsisDecode.cpp index daf3df6e..e2822184 100644 --- a/CPP/7zip/Archive/Nsis/NsisDecode.cpp +++ b/CPP/7zip/Archive/Nsis/NsisDecode.cpp @@ -11,13 +11,24 @@ #include "../../Common/MethodId.h" #include "../../Compress/BcjCoder.h" -#include "../../Compress/BZip2Decoder.h" #define Get32(p) GetUi32(p) namespace NArchive { namespace NNsis { +UInt64 CDecoder::GetInputProcessedSize() const +{ + if (_lzmaDecoder) + return _lzmaDecoder->GetInputProcessedSize(); + if (_deflateDecoder) + return _deflateDecoder->GetInputProcessedSize(); + if (_bzDecoder) + return _bzDecoder->GetInputProcessedSize(); + return 0; +} + + HRESULT CDecoder::Init(ISequentialInStream *inStream, bool &useFilter) { useFilter = false; @@ -36,7 +47,10 @@ HRESULT CDecoder::Init(ISequentialInStream *inStream, bool &useFilter) _deflateDecoder = new NCompress::NDeflate::NDecoder::CCOMCoder(); _codecInStream = _deflateDecoder; break; - case NMethodType::kBZip2: _codecInStream = new NCompress::NBZip2::CNsisDecoder(); break; + case NMethodType::kBZip2: + _bzDecoder = new NCompress::NBZip2::CNsisDecoder(); + _codecInStream = _bzDecoder; + break; case NMethodType::kLZMA: _lzmaDecoder = new NCompress::NLzma::CDecoder(); _codecInStream = _lzmaDecoder; @@ -103,15 +117,15 @@ HRESULT CDecoder::Init(ISequentialInStream *inStream, bool &useFilter) return S_OK; } + static const UInt32 kMask_IsCompressed = (UInt32)1 << 31; + HRESULT CDecoder::SetToPos(UInt64 pos, ICompressProgressInfo *progress) { if (StreamPos > pos) return E_FAIL; - UInt64 inSizeStart = 0; - if (_lzmaDecoder) - inSizeStart = _lzmaDecoder->GetInputProcessedSize(); + const UInt64 inSizeStart = GetInputProcessedSize(); UInt64 offset = 0; while (StreamPos < pos) { @@ -122,14 +136,13 @@ HRESULT CDecoder::SetToPos(UInt64 pos, ICompressProgressInfo *progress) StreamPos += size; offset += size; - UInt64 inSize = 0; - if (_lzmaDecoder) - inSize = _lzmaDecoder->GetInputProcessedSize() - inSizeStart; + const UInt64 inSize = GetInputProcessedSize() - inSizeStart; RINOK(progress->SetRatioInfo(&inSize, &offset)); } return S_OK; } + HRESULT CDecoder::Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize, ISequentialOutStream *realOutStream, ICompressProgressInfo *progress, UInt32 &packSizeRes, UInt32 &unpackSizeRes) @@ -144,9 +157,9 @@ HRESULT CDecoder::Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unp Byte temp[4]; size_t processedSize = 4; RINOK(Read(temp, &processedSize)); + StreamPos += processedSize; if (processedSize != 4) return S_FALSE; - StreamPos += processedSize; UInt32 size = Get32(temp); if (unpackSizeDefined && size != unpackSize) return S_FALSE; @@ -156,8 +169,13 @@ HRESULT CDecoder::Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unp else { Byte temp[4]; - RINOK(ReadStream_FALSE(InputStream, temp, 4)); - StreamPos += 4; + { + size_t processedSize = 4; + RINOK(ReadStream(InputStream, temp, &processedSize)); + StreamPos += processedSize; + if (processedSize != 4) + return S_FALSE; + } UInt32 size = Get32(temp); if ((size & kMask_IsCompressed) == 0) @@ -209,9 +227,7 @@ HRESULT CDecoder::Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unp outBuf->Alloc(unpackSize); } - UInt64 inSizeStart = 0; - if (_lzmaDecoder) - inSizeStart = _lzmaDecoder->GetInputProcessedSize(); + const UInt64 inSizeStart = GetInputProcessedSize(); // we don't allow files larger than 4 GB; if (!unpackSizeDefined) @@ -254,9 +270,8 @@ HRESULT CDecoder::Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unp StreamPos += size; offset += (UInt32)size; - UInt64 inSize = 0; // it can be improved: we need inSize for Deflate and BZip2 too. - if (_lzmaDecoder) - inSize = _lzmaDecoder->GetInputProcessedSize() - inSizeStart; + const UInt64 inSize = GetInputProcessedSize() - inSizeStart; + if (Solid) packSizeRes = (UInt32)inSize; unpackSizeRes += (UInt32)size; diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.h b/CPP/7zip/Archive/Nsis/NsisDecode.h index ec713d05..2153d785 100644 --- a/CPP/7zip/Archive/Nsis/NsisDecode.h +++ b/CPP/7zip/Archive/Nsis/NsisDecode.h @@ -8,6 +8,7 @@ #include "../../Common/FilterCoder.h" #include "../../Common/StreamUtils.h" +#include "../../Compress/BZip2Decoder.h" #include "../../Compress/DeflateDecoder.h" #include "../../Compress/LzmaDecoder.h" @@ -38,6 +39,7 @@ class CDecoder CMyComPtr<ISequentialInStream> _codecInStream; CMyComPtr<ISequentialInStream> _decoderInStream; + NCompress::NBZip2::CNsisDecoder *_bzDecoder; NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoder; NCompress::NLzma::CDecoder *_lzmaDecoder; @@ -50,13 +52,17 @@ public: bool Solid; bool IsNsisDeflate; - CByteBuffer Buffer; // temp buf. + CByteBuffer Buffer; // temp buf CDecoder(): FilterFlag(false), Solid(true), IsNsisDeflate(true) - {} + { + _bzDecoder = NULL; + _deflateDecoder = NULL; + _lzmaDecoder = NULL; + } void Release() { @@ -64,10 +70,16 @@ public: _codecInStream.Release(); _decoderInStream.Release(); InputStream.Release(); + + _bzDecoder = NULL; + _deflateDecoder = NULL; _lzmaDecoder = NULL; } + + UInt64 GetInputProcessedSize() const; HRESULT Init(ISequentialInStream *inStream, bool &useFilter); + HRESULT Read(void *data, size_t *processedSize) { return ReadStream(_decoderInStream, data, processedSize);; diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.cpp b/CPP/7zip/Archive/Nsis/NsisHandler.cpp index 971c8464..095105fe 100644 --- a/CPP/7zip/Archive/Nsis/NsisHandler.cpp +++ b/CPP/7zip/Archive/Nsis/NsisHandler.cpp @@ -23,8 +23,8 @@ using namespace NWindows; namespace NArchive { namespace NNsis { -static const char *kBcjMethod = "BCJ"; -static const char *kUnknownMethod = "Unknown"; +#define kBcjMethod "BCJ" +#define kUnknownMethod "Unknown" static const char * const kMethods[] = { @@ -64,7 +64,7 @@ static AString UInt32ToString(UInt32 val) { char s[16]; ConvertUInt32ToString(val, s); - return s; + return (AString)s; } static AString GetStringForSizeValue(UInt32 val) @@ -123,7 +123,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) // case kpidCodePage: if (_archive.IsUnicode) prop = "UTF-16"; break; case kpidSubType: { - AString s = _archive.GetFormatDescription(); + AString s (_archive.GetFormatDescription()); if (!_archive.IsInstaller) { s.Add_Space_if_NotEmpty(); @@ -308,7 +308,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidOffset: prop = item.Pos; break; case kpidPath: { - UString s = NItemName::WinNameToOSName(_archive.GetReducedName(index)); + UString s = NItemName::WinPathToOsPath(_archive.GetReducedName(index)); if (!s.IsEmpty()) prop = (const wchar_t *)s; break; @@ -481,7 +481,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; - UInt32 index = allFilesMode ? i : indices[i]; + const UInt32 index = allFilesMode ? i : indices[i]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); @@ -647,6 +647,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { UInt32 curPacked2 = 0; UInt32 curUnpacked2 = 0; + + if (!_archive.IsSolid) + { + RINOK(_archive.SeekTo(_archive.GetPosOfNonSolidItem(index) + 4 + curPacked )); + } + HRESULT res = _archive.Decoder.Decode( writeToTemp ? &tempBuf2 : NULL, false, 0, diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp index a3bfcaec..f739b0ff 100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.cpp +++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp @@ -398,11 +398,9 @@ static const char * const kShellStrings[] = }; -static void UIntToString(AString &s, UInt32 v) +static inline void UIntToString(AString &s, UInt32 v) { - char sz[16]; - ConvertUInt32ToString(v, sz); - s += sz; + s.Add_UInt32(v); } #ifdef NSIS_SCRIPT @@ -461,7 +459,7 @@ void CInArchive::AddLicense(UInt32 param, Int32 langID) } } } - AString fileName = "[LICENSE]"; + AString fileName ("[LICENSE]"); if (langID >= 0) { fileName += "\\license-"; @@ -940,7 +938,7 @@ void CInArchive::GetNsisString_Unicode_Raw(const Byte *p) break; if (c < 0x80) { - Raw_UString += (wchar_t)c; + Raw_UString += (char)c; continue; } @@ -963,7 +961,7 @@ void CInArchive::GetNsisString_Unicode_Raw(const Byte *p) else // if (c == PARK_CODE_LANG) Add_LangStr(Raw_AString, n); } - Raw_UString.AddAscii(Raw_AString); + Raw_UString += Raw_AString.Ptr(); // check it ! continue; } c = n; @@ -1009,7 +1007,7 @@ void CInArchive::GetNsisString_Unicode_Raw(const Byte *p) else // if (c == NS_3_CODE_LANG) Add_LangStr(Raw_AString, n); } - Raw_UString.AddAscii(Raw_AString); + Raw_UString += Raw_AString.Ptr(); } } @@ -1145,7 +1143,7 @@ void CInArchive::ReadString2_Raw(UInt32 pos) GetNsisString_Raw(_data + _stringsPos + pos); return; } - Raw_UString.SetFromAscii(Raw_AString); + Raw_UString = Raw_AString.Ptr(); } bool CInArchive::IsGoodString(UInt32 param) const @@ -2309,7 +2307,7 @@ static void AddString(AString &dest, const char *src) AString CInArchive::GetFormatDescription() const { - AString s = "NSIS-"; + AString s ("NSIS-"); char c; if (IsPark()) { @@ -3185,8 +3183,8 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) UString spec_outdir_U; AString spec_outdir_A; - UPrefixes.Add(L"$INSTDIR"); - APrefixes.Add("$INSTDIR"); + UPrefixes.Add(UString("$INSTDIR")); + APrefixes.Add(AString("$INSTDIR")); p = _data + bh.Offset; @@ -4021,7 +4019,7 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) case EW_INTOP: { AddParam_Var(params[0]); - const char *kOps = "+-*/|&^!|&%<>"; // NSIS 2.01+ + const char * const kOps = "+-*/|&^!|&%<>"; // NSIS 2.01+ // "+-*/|&^!|&%"; // NSIS 2.0b4+ // "+-*/|&^~!|&%"; // NSIS old UInt32 opIndex = params[3]; @@ -4857,11 +4855,11 @@ static int CompareItems(void *const *p1, void *const *p2, void *param) { if (i1.Prefix < 0) return -1; if (i2.Prefix < 0) return 1; - RINOZ(wcscmp( - inArchive->UPrefixes[i1.Prefix], + RINOZ( + inArchive->UPrefixes[i1.Prefix].Compare( inArchive->UPrefixes[i2.Prefix])); } - RINOZ(wcscmp(i1.NameU, i2.NameU)); + RINOZ(i1.NameU.Compare(i2.NameU)); } else { @@ -4934,7 +4932,7 @@ HRESULT CInArchive::SortItems() for (i = 0; i < Items.Size(); i++) { CItem &item = Items[i]; - RINOK(_stream->Seek(GetPosOfNonSolidItem(i), STREAM_SEEK_SET, NULL)); + RINOK(SeekToNonSolidItem(i)); const UInt32 kSigSize = 4 + 1 + 1 + 4; // size,[flag],prop,dict BYTE sig[kSigSize]; size_t processedSize = kSigSize; @@ -4997,6 +4995,9 @@ HRESULT CInArchive::Parse() // ???? offset == FirstHeader.HeaderSize const Byte *p = _data; + if (_size < 4 + 8 * 8) + return S_FALSE; + CBlockHeader bhEntries, bhStrings, bhLangTables; bhEntries.Parse(p + 4 + 8 * 2); bhStrings.Parse(p + 4 + 8 * 3); @@ -5014,12 +5015,14 @@ HRESULT CInArchive::Parse() #endif _stringsPos = bhStrings.Offset; - if (_stringsPos > _size) + if (_stringsPos > _size + || bhLangTables.Offset > _size + || bhEntries.Offset > _size) return S_FALSE; { if (bhLangTables.Offset < bhStrings.Offset) return S_FALSE; - UInt32 stringTableSize = bhLangTables.Offset - bhStrings.Offset; + const UInt32 stringTableSize = bhLangTables.Offset - bhStrings.Offset; if (stringTableSize < 2) return S_FALSE; const Byte *strData = _data + _stringsPos; @@ -5035,13 +5038,10 @@ HRESULT CInArchive::Parse() if (strData[stringTableSize - 2] != 0) return S_FALSE; } - } if (bhEntries.Num > (1 << 25)) return S_FALSE; - if (bhEntries.Offset > _size) - return S_FALSE; if (bhEntries.Num * kCmdSize > _size - bhEntries.Offset) return S_FALSE; @@ -5595,16 +5595,19 @@ HRESULT CInArchive::Open2(const Byte *sig, size_t size) if (IsSolid) { - RINOK(_stream->Seek(DataStreamOffset, STREAM_SEEK_SET, NULL)); + RINOK(SeekTo_DataStreamOffset()); } else { _headerIsCompressed = ((compressedHeaderSize & kMask_IsCompressed) != 0); compressedHeaderSize &= ~kMask_IsCompressed; _nonSolidStartOffset = compressedHeaderSize; - RINOK(_stream->Seek(DataStreamOffset + 4, STREAM_SEEK_SET, NULL)); + RINOK(SeekTo(DataStreamOffset + 4)); } + if (FirstHeader.HeaderSize == 0) + return S_FALSE; + _data.Alloc(FirstHeader.HeaderSize); _size = (size_t)FirstHeader.HeaderSize; diff --git a/CPP/7zip/Archive/Nsis/NsisIn.h b/CPP/7zip/Archive/Nsis/NsisIn.h index d8e6808b..028e4a5d 100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.h +++ b/CPP/7zip/Archive/Nsis/NsisIn.h @@ -350,14 +350,19 @@ public: return Decoder.Init(_stream, useFilter); } + HRESULT SeekTo(UInt64 pos) + { + return _stream->Seek(pos, STREAM_SEEK_SET, NULL); + } + HRESULT SeekTo_DataStreamOffset() { - return _stream->Seek(DataStreamOffset, STREAM_SEEK_SET, NULL); + return SeekTo(DataStreamOffset); } HRESULT SeekToNonSolidItem(unsigned index) { - return _stream->Seek(GetPosOfNonSolidItem(index), STREAM_SEEK_SET, NULL); + return SeekTo(GetPosOfNonSolidItem(index)); } void Clear(); @@ -403,23 +408,23 @@ public: s = MultiByteToUnicodeString(APrefixes[item.Prefix]); if (s.Len() > 0) if (s.Back() != L'\\') - s += L'\\'; + s += '\\'; } if (IsUnicode) { s += item.NameU; if (item.NameU.IsEmpty()) - s += L"file"; + s += "file"; } else { s += MultiByteToUnicodeString(item.NameA); if (item.NameA.IsEmpty()) - s += L"file"; + s += "file"; } - const char *kRemoveStr = "$INSTDIR\\"; + const char * const kRemoveStr = "$INSTDIR\\"; if (s.IsPrefixedBy_Ascii_NoCase(kRemoveStr)) { s.Delete(0, MyStringLen(kRemoveStr)); @@ -427,7 +432,7 @@ public: s.DeleteFrontal(1); } if (item.IsUninstaller && ExeStub.Size() == 0) - s += L".nsis"; + s += ".nsis"; return s; } diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp index a6350944..dff7701d 100644 --- a/CPP/7zip/Archive/NtfsHandler.cpp +++ b/CPP/7zip/Archive/NtfsHandler.cpp @@ -56,9 +56,9 @@ using namespace NWindows; namespace NArchive { namespace Ntfs { -static const wchar_t *kVirtualFolder_System = L"[SYSTEM]"; -static const wchar_t *kVirtualFolder_Lost_Normal = L"[LOST]"; -static const wchar_t *kVirtualFolder_Lost_Deleted = L"[UNKNOWN]"; +static const wchar_t * const kVirtualFolder_System = L"[SYSTEM]"; +static const wchar_t * const kVirtualFolder_Lost_Normal = L"[LOST]"; +static const wchar_t * const kVirtualFolder_Lost_Deleted = L"[UNKNOWN]"; static const unsigned kNumSysRecs = 16; @@ -394,7 +394,7 @@ static int CompareAttr(void *const *elem1, void *const *elem2, void *) return 1; else { - RINOZ(wcscmp(a1.Name.GetRawPtr(), a2.Name.GetRawPtr())); + RINOZ(a1.Name.Compare(a2.Name.GetRawPtr())); } return MyCompare(a1.LowVcn, a2.LowVcn); } @@ -2340,7 +2340,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } case kpidFileSystem: { - AString s = "NTFS"; + AString s ("NTFS"); FOR_VECTOR (i, VolAttrs) { const CAttr &attr = VolAttrs[i]; @@ -2350,12 +2350,9 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) if (attr.ParseVolInfo(vi)) { s.Add_Space(); - char temp[16]; - ConvertUInt32ToString(vi.MajorVer, temp); - s += temp; + s.Add_UInt32(vi.MajorVer); s += '.'; - ConvertUInt32ToString(vi.MinorVer, temp); - s += temp; + s.Add_UInt32(vi.MinorVer); } break; } @@ -2722,18 +2719,14 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR for (UInt32 i = 0; i < numProps; i++) { - UString name = names[i]; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - + const wchar_t *name = names[i]; const PROPVARIANT &prop = values[i]; - if (name.IsEqualTo("ld")) + if (StringsAreEqualNoCase_Ascii(name, "ld")) { RINOK(PROPVARIANT_to_bool(prop, _showDeletedFiles)); } - else if (name.IsEqualTo("ls")) + else if (StringsAreEqualNoCase_Ascii(name, "ls")) { RINOK(PROPVARIANT_to_bool(prop, _showSystemFiles)); } diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp index 7175cef3..30a60843 100644 --- a/CPP/7zip/Archive/PeHandler.cpp +++ b/CPP/7zip/Archive/PeHandler.cpp @@ -85,12 +85,6 @@ static HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 exc return S_OK; } -static AString GetDecString(UInt32 v) -{ - char sz[16]; - ConvertUInt32ToString(v, sz); - return sz; -} struct CVersion { @@ -407,13 +401,16 @@ static const CUInt32PCharPair g_HeaderCharacts[] = static const CUInt32PCharPair g_DllCharacts[] = { + { 5, "HighEntropyVA" }, { 6, "Relocated" }, { 7, "Integrity" }, { 8, "NX-Compatible" }, { 9, "NoIsolation" }, { 10, "NoSEH" }, { 11, "NoBind" }, + { 12, "AppContainer" }, { 13, "WDM" }, + { 14, "GuardCF" }, { 15, "TerminalServerAware" } }; @@ -467,22 +464,30 @@ static const CUInt32PCharPair g_MachinePairs[] = { 0x0EBC, "EFI" }, { 0x8664, "x64" }, { 0x9041, "M32R" }, + { 0xAA64, "ARM64" }, { 0xC0EE, "CEE" } }; -static const CUInt32PCharPair g_SubSystems[] = -{ - { 0, "Unknown" }, - { 1, "Native" }, - { 2, "Windows GUI" }, - { 3, "Windows CUI" }, - { 7, "Posix" }, - { 9, "Windows CE" }, - { 10, "EFI" }, - { 11, "EFI Boot" }, - { 12, "EFI Runtime" }, - { 13, "EFI ROM" }, - { 14, "XBOX" } +static const char * const g_SubSystems[] = +{ + "Unknown" + , "Native" + , "Windows GUI" + , "Windows CUI" + , NULL // "Old Windows CE" + , "OS2" + , NULL + , "Posix" + , "Win9x" + , "Windows CE" + , "EFI" + , "EFI Boot" + , "EFI Runtime" + , "EFI ROM" + , "XBOX" + , NULL + , "Windows Boot" + , "XBOX Catalog" // 17 }; static const char * const g_ResTypes[] = @@ -878,7 +883,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break; case kpidBit64: if (_optHeader.Is64Bit()) prop = true; break; - case kpidSubSystem: PAIR_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break; + case kpidSubSystem: TYPE_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break; case kpidMTime: case kpidCTime: TimeToProp(_header.Time, prop); break; @@ -950,9 +955,7 @@ void CHandler::AddResNameToString(UString &s, UInt32 id) const return; } } - wchar_t sz[16]; - ConvertUInt32ToString(id, sz); - s += sz; + s.Add_UInt32(id); } void CHandler::AddLangPrefix(UString &s, UInt32 lang) const @@ -978,7 +981,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { UString s = _resourcesPrefix; AddLangPrefix(s, item.Lang); - s.AddAscii("string.txt"); + s += "string.txt"; prop = s; break; } @@ -996,7 +999,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { UString s = _resourcesPrefix; AddLangPrefix(s, item.Lang); - s.AddAscii("version.txt"); + s += "version.txt"; prop = s; break; } @@ -1019,7 +1022,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (item.Type < ARRAY_SIZE(g_ResTypes)) p = g_ResTypes[item.Type]; if (p) - s.AddAscii(p); + s += p; else AddResNameToString(s, item.Type); } @@ -1028,9 +1031,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (item.HeaderSize != 0) { if (item.IsBmp()) - s.AddAscii(".bmp"); + s += ".bmp"; else if (item.IsIcon()) - s.AddAscii(".ico"); + s += ".ico"; } prop = s; break; @@ -1112,7 +1115,8 @@ HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection) thereIsSection = true; CSection § = _sections.AddNew(); - sect.Name = ".debug" + GetDecString(i); + sect.Name = ".debug"; + sect.Name.Add_UInt32(i); sect.IsDebug = true; sect.Time = de.Time; sect.Va = de.Va; @@ -1384,11 +1388,9 @@ static void PrintUInt32(CTextFile &f, UInt32 v) f.AddString(s); } -static void PrintUInt32(UString &dest, UInt32 v) +static inline void PrintUInt32(UString &dest, UInt32 v) { - wchar_t s[16]; - ConvertUInt32ToString(v, s); - dest += s; + dest.Add_UInt32(v); } static void PrintHex(CTextFile &f, UInt32 val) @@ -1410,9 +1412,9 @@ static void PrintVersion(CTextFile &f, UInt32 ms, UInt32 ls) static void PrintVersion(UString &s, UInt32 ms, UInt32 ls) { - PrintUInt32(s, HIWORD(ms)); s += L'.'; - PrintUInt32(s, LOWORD(ms)); s += L'.'; - PrintUInt32(s, HIWORD(ls)); s += L'.'; + PrintUInt32(s, HIWORD(ms)); s += '.'; + PrintUInt32(s, LOWORD(ms)); s += '.'; + PrintUInt32(s, HIWORD(ls)); s += '.'; PrintUInt32(s, LOWORD(ls)); } @@ -1694,7 +1696,7 @@ bool CVersionBlock::Parse(const Byte *p, UInt32 size) return false; TotalLen = Get16(p); ValueLen = Get16(p + 2); - if (TotalLen == 0 || TotalLen > size) + if (TotalLen < k_ResoureBlockHeader_Size || TotalLen > size) return false; switch (Get16(p + 4)) { @@ -2114,7 +2116,8 @@ HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchi static inline bool CheckPeOffset(UInt32 pe) { - return (pe >= 0x40 && pe <= 0x1000 && (pe & 7) == 0); + // ((pe & 7) == 0) is for most PE files. But there is unusual EFI-PE file that uses unaligned pe value. + return pe >= 0x40 && pe <= 0x1000 /* && (pe & 7) == 0 */ ; } static const unsigned kStartSize = 0x40; @@ -2290,7 +2293,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) s2.PSize = s2.VSize = s.Pa - limit; s2.IsAdditionalSection = true; s2.Name = '['; - s2.Name += GetDecString(num++); + s2.Name.Add_UInt32(num++); s2.Name += ']'; limit = s.Pa; } @@ -2332,10 +2335,11 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) mixItem.SectionIndex = i; if (_parseResources && sect.Name == ".rsrc" && _items.IsEmpty()) { + const unsigned numMixItems = _mixItems.Size(); HRESULT res = OpenResources(i, stream, callback); if (res == S_OK) { - _resourcesPrefix.SetFromAscii(sect.Name); + _resourcesPrefix = sect.Name.Ptr(); _resourcesPrefix.Add_PathSepar(); FOR_VECTOR (j, _items) { @@ -2387,6 +2391,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) } if (res != S_FALSE) return res; + _mixItems.DeleteFrom(numMixItems); CloseResources(); } if (sect.IsAdditionalSection) @@ -2422,7 +2427,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) _versionFullString.Add_LF(); const CStringKeyValue &k = _versionKeys[i]; _versionFullString += k.Key; - _versionFullString += L": "; + _versionFullString += ": "; _versionFullString += k.Value; } @@ -2702,7 +2707,8 @@ static bool FindValue(const CUInt32PCharPair *pairs, unsigned num, UInt32 value) return false; } -#define MY_FIND_VALUE(pairs, value) FindValue(pairs, ARRAY_SIZE(pairs), value) +#define MY_FIND_VALUE(pairs, val) FindValue(pairs, ARRAY_SIZE(pairs), val) +#define MY_FIND_VALUE_2(strings, val) (val < ARRAY_SIZE(strings) && strings[val]) static const UInt32 kNumSection_MAX = 32; @@ -2751,7 +2757,7 @@ bool CHeader::Parse(const Byte *p) } return MY_FIND_VALUE(NPe::g_MachinePairs, Machine) && - MY_FIND_VALUE(NPe::g_SubSystems, SubSystem); + MY_FIND_VALUE_2(NPe::g_SubSystems, SubSystem); } API_FUNC_static_IsArc IsArc_Te(const Byte *p, size_t size) @@ -2864,7 +2870,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { case kpidPhySize: prop = _totalSize; break; case kpidCpu: PAIR_TO_PROP(NPe::g_MachinePairs, _h.Machine, prop); break; - case kpidSubSystem: PAIR_TO_PROP(NPe::g_SubSystems, _h.SubSystem, prop); break; + case kpidSubSystem: TYPE_TO_PROP(NPe::g_SubSystems, _h.SubSystem, prop); break; /* case kpidImageBase: prop = _h.ImageBase; break; case kpidAddressOfEntryPoint: prop = _h.AddressOfEntryPoint; break; diff --git a/CPP/7zip/Archive/PpmdHandler.cpp b/CPP/7zip/Archive/PpmdHandler.cpp index 528c5ceb..c80400bc 100644 --- a/CPP/7zip/Archive/PpmdHandler.cpp +++ b/CPP/7zip/Archive/PpmdHandler.cpp @@ -12,7 +12,6 @@ This code is based on: #include "../../../C/Ppmd8.h" #include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" #include "../../Common/StringConvert.h" #include "../../Windows/PropVariant.h" @@ -104,6 +103,8 @@ class CHandler: UInt64 _packSize; CMyComPtr<ISequentialInStream> _stream; + void GetVersion(NCOM::CPropVariant &prop); + public: MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq) INTERFACE_IInArchive(;) @@ -118,8 +119,30 @@ static const Byte kProps[] = kpidMethod }; +static const Byte kArcProps[] = +{ + kpidMethod +}; + IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table +IMP_IInArchive_ArcProps + +void CHandler::GetVersion(NCOM::CPropVariant &prop) +{ + AString s ("PPMd"); + s += (char)('A' + _item.Ver); + s += ":o"; + s.Add_UInt32(_item.Order); + s += ":mem"; + s.Add_UInt32(_item.MemInMB); + s += 'm'; + if (_item.Ver >= kNewHeaderVer && _item.Restor != 0) + { + s += ":r"; + s.Add_UInt32(_item.Restor); + } + prop = s; +} STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { @@ -127,6 +150,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) switch (propID) { case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; + case kpidMethod: GetVersion(prop); break; } prop.Detach(value); return S_OK; @@ -139,14 +163,6 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -static void UIntToString(AString &s, const char *prefix, unsigned value) -{ - s += prefix; - char temp[16]; - ::ConvertUInt32ToString((UInt32)value, temp); - s += temp; -} - STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN @@ -164,17 +180,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN } case kpidAttrib: prop = _item.Attrib; break; case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; - case kpidMethod: - { - AString s = "PPMd"; - s += (char)('A' + _item.Ver); - UIntToString(s, ":o", _item.Order); - UIntToString(s, ":mem", _item.MemInMB); - s += 'm'; - if (_item.Ver >= kNewHeaderVer && _item.Restor != 0) - UIntToString(s, ":r", _item.Restor); - prop = s; - } + case kpidMethod: GetVersion(prop); break; } prop.Detach(value); return S_OK; @@ -217,7 +223,7 @@ static const UInt32 kBot = (1 << 15); struct CRangeDecoder { - IPpmd7_RangeDec s; + IPpmd7_RangeDec vt; UInt32 Range; UInt32 Code; UInt32 Low; @@ -251,15 +257,17 @@ public: extern "C" { -static UInt32 Range_GetThreshold(void *pp, UInt32 total) +#define GET_RangeDecoder CRangeDecoder *p = CONTAINER_FROM_VTBL(pp, CRangeDecoder, vt); + +static UInt32 Range_GetThreshold(const IPpmd7_RangeDec *pp, UInt32 total) { - CRangeDecoder *p = (CRangeDecoder *)pp; + GET_RangeDecoder return p->Code / (p->Range /= total); } -static void Range_Decode(void *pp, UInt32 start, UInt32 size) +static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size) { - CRangeDecoder *p = (CRangeDecoder *)pp; + GET_RangeDecoder start *= p->Range; p->Low += start; p->Code -= start; @@ -267,17 +275,17 @@ static void Range_Decode(void *pp, UInt32 start, UInt32 size) p->Normalize(); } -static UInt32 Range_DecodeBit(void *pp, UInt32 size0) +static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *pp, UInt32 size0) { - CRangeDecoder *p = (CRangeDecoder *)pp; + GET_RangeDecoder if (p->Code / (p->Range >>= 14) < size0) { - Range_Decode(p, 0, size0); + Range_Decode(&p->vt, 0, size0); return 0; } else { - Range_Decode(p, size0, (1 << 14) - size0); + Range_Decode(&p->vt, size0, (1 << 14) - size0); return 1; } } @@ -286,9 +294,9 @@ static UInt32 Range_DecodeBit(void *pp, UInt32 size0) CRangeDecoder::CRangeDecoder() { - s.GetThreshold = Range_GetThreshold; - s.Decode = Range_Decode; - s.DecodeBit = Range_DecodeBit; + vt.GetThreshold = Range_GetThreshold; + vt.Decode = Range_Decode; + vt.DecodeBit = Range_DecodeBit; } struct CPpmdCpp @@ -336,7 +344,7 @@ struct CPpmdCpp } else { - _ppmd8.Stream.In = &inStream->p; + _ppmd8.Stream.In = &inStream->vt; return Ppmd8_RangeDec_Init(&_ppmd8) != 0; } } @@ -412,7 +420,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { for (i = 0; i < kBufSize; i++) { - sym = Ppmd7_DecodeSymbol(&ppmd._ppmd7, &ppmd._rc.s); + sym = Ppmd7_DecodeSymbol(&ppmd._ppmd7, &ppmd._rc.vt); if (inBuf.Extra || sym < 0) break; outBuf.Buf[i] = (Byte)sym; diff --git a/CPP/7zip/Archive/QcowHandler.cpp b/CPP/7zip/Archive/QcowHandler.cpp index a84fdc9b..065f59b3 100644 --- a/CPP/7zip/Archive/QcowHandler.cpp +++ b/CPP/7zip/Archive/QcowHandler.cpp @@ -284,11 +284,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) if (_cryptMethod == 1) s += "AES"; else - { - char temp[16]; - ConvertUInt32ToString(_cryptMethod, temp); - s += temp; - } + s.Add_UInt32(_cryptMethod); } if (!s.IsEmpty()) diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/CPP/7zip/Archive/Rar/Rar5Handler.cpp index d70a5686..f166730e 100644 --- a/CPP/7zip/Archive/Rar/Rar5Handler.cpp +++ b/CPP/7zip/Archive/Rar/Rar5Handler.cpp @@ -50,22 +50,59 @@ static const Byte kMarker[kMarkerSize] = SIGNATURE; static const size_t kCommentSize_Max = (size_t)1 << 16; + static const char * const kHostOS[] = { "Windows" , "Unix" }; -static const CUInt32PCharPair k_ArcFlags[] = + +static const char * const k_ArcFlags[] = +{ + "Volume" + , "VolumeField" + , "Solid" + , "Recovery" + , "Lock" // 4 +}; + + +static const char * const k_FileFlags[] = +{ + "Dir" + , "UnixTime" + , "CRC" + , "UnknownSize" +}; + + +static const char * const g_ExtraTypes[] = +{ + "0" + , "Crypto" + , "Hash" + , "Time" + , "Version" + , "Link" + , "UnixOwner" + , "Subdata" +}; + + +static const char * const g_LinkTypes[] = { - { 0, "Volume" }, - { 1, "VolumeField" }, - { 2, "Solid" }, - { 3, "Recovery" }, - { 4, "Lock" } + "0" + , "UnixSymLink" + , "WinSymLink" + , "WinJunction" + , "HardLink" + , "FileCopy" }; +static const char g_ExtraTimeFlags[] = { 'u', 'M', 'C', 'A', 'n' }; + template <unsigned alignMask> struct CAlignedBuffer @@ -106,7 +143,8 @@ static unsigned ReadVarInt(const Byte *p, size_t maxSize, UInt64 *val) { Byte b = p[i]; if (i < 10) - *val |= (UInt64)(b & 0x7F) << (7 * i++); + *val |= (UInt64)(b & 0x7F) << (7 * i); + i++; if ((b & 0x80) == 0) return i; } @@ -114,7 +152,54 @@ static unsigned ReadVarInt(const Byte *p, size_t maxSize, UInt64 *val) } -int CItem::FindExtra(unsigned type, unsigned &recordDataSize) const +bool CLinkInfo::Parse(const Byte *p, unsigned size) +{ + const Byte *pStart = p; + unsigned num = ReadVarInt(p, size, &Type); + if (num == 0) return false; p += num; size -= num; + + num = ReadVarInt(p, size, &Flags); + if (num == 0) return false; p += num; size -= num; + + UInt64 len; + num = ReadVarInt(p, size, &len); + if (num == 0) return false; p += num; size -= num; + + if (size != len) + return false; + + NameLen = (unsigned)len; + NameOffset = (unsigned)(p - pStart); + return true; +} + + +static void AddHex64(AString &s, UInt64 v) +{ + char sz[32]; + sz[0] = '0'; + sz[1] = 'x'; + ConvertUInt64ToHex(v, sz + 2); + s += sz; +} + + +static void PrintType(AString &s, const char * const table[], unsigned num, UInt64 val) +{ + char sz[32]; + const char *p = NULL; + if (val < num) + p = table[(unsigned)val]; + if (!p) + { + ConvertUInt64ToString(val, sz); + p = sz; + } + s += p; +} + + +int CItem::FindExtra(unsigned extraID, unsigned &recordDataSize) const { recordDataSize = 0; size_t offset = 0; @@ -137,8 +222,8 @@ int CItem::FindExtra(unsigned type, unsigned &recordDataSize) const rem = (size_t)size; } { - UInt64 type2; - unsigned num = ReadVarInt(Extra + offset, rem, &type2); + UInt64 id; + unsigned num = ReadVarInt(Extra + offset, rem, &id); if (num == 0) return -1; offset += num; @@ -147,12 +232,12 @@ int CItem::FindExtra(unsigned type, unsigned &recordDataSize) const // There was BUG in RAR 5.21- : it stored (size-1) instead of (size) // for Subdata record in Service header. // That record always was last in bad archives, so we can fix that case. - if (type2 == NExtraRecordType::kSubdata + if (id == NExtraID::kSubdata && RecordType == NHeaderType::kService && rem + 1 == Extra.Size() - offset) rem++; - if (type2 == type) + if (id == extraID) { recordDataSize = (unsigned)rem; return (int)offset; @@ -164,19 +249,118 @@ int CItem::FindExtra(unsigned type, unsigned &recordDataSize) const } +void CItem::PrintInfo(AString &s) const +{ + size_t offset = 0; + + for (;;) + { + size_t rem = Extra.Size() - offset; + if (rem == 0) + return; + + { + UInt64 size; + unsigned num = ReadVarInt(Extra + offset, rem, &size); + if (num == 0) + return; + offset += num; + rem -= num; + if (size > rem) + break; + rem = (size_t)size; + } + { + UInt64 id; + { + unsigned num = ReadVarInt(Extra + offset, rem, &id); + if (num == 0) + break; + offset += num; + rem -= num; + } + + // There was BUG in RAR 5.21- : it stored (size-1) instead of (size) + // for Subdata record in Service header. + // That record always was last in bad archives, so we can fix that case. + if (id == NExtraID::kSubdata + && RecordType == NHeaderType::kService + && rem + 1 == Extra.Size() - offset) + rem++; + + s.Add_Space_if_NotEmpty(); + PrintType(s, g_ExtraTypes, ARRAY_SIZE(g_ExtraTypes), id); + + if (id == NExtraID::kTime) + { + const Byte *p = Extra + offset; + UInt64 flags; + unsigned num = ReadVarInt(p, rem, &flags); + if (num != 0) + { + s += ':'; + for (unsigned i = 0; i < ARRAY_SIZE(g_ExtraTimeFlags); i++) + if ((flags & ((UInt64)1 << i)) != 0) + s += g_ExtraTimeFlags[i]; + flags &= ~(((UInt64)1 << ARRAY_SIZE(g_ExtraTimeFlags)) - 1); + if (flags != 0) + { + s += '_'; + AddHex64(s, flags); + } + } + } + else if (id == NExtraID::kLink) + { + CLinkInfo linkInfo; + if (linkInfo.Parse(Extra + offset, (unsigned)rem)) + { + s += ':'; + PrintType(s, g_LinkTypes, ARRAY_SIZE(g_LinkTypes), linkInfo.Type); + UInt64 flags = linkInfo.Flags; + if (flags != 0) + { + s += ':'; + if (flags & NLinkFlags::kTargetIsDir) + { + s += 'D'; + flags &= ~((UInt64)NLinkFlags::kTargetIsDir); + } + if (flags != 0) + { + s += '_'; + AddHex64(s, flags); + } + } + } + } + + offset += rem; + } + } + + s.Add_OptSpaced("ERROR"); +} + + bool CCryptoInfo::Parse(const Byte *p, size_t size) { + Algo = 0; + Flags = 0; + Cnt = 0; + unsigned num = ReadVarInt(p, size, &Algo); if (num == 0) return false; p += num; size -= num; num = ReadVarInt(p, size, &Flags); if (num == 0) return false; p += num; size -= num; + if (size > 0) + Cnt = p[0]; + if (size != 1 + 16 + 16 + (unsigned)(IsThereCheck() ? 12 : 0)) return false; - Cnt = p[0]; - return true; } @@ -184,7 +368,7 @@ bool CCryptoInfo::Parse(const Byte *p, size_t size) bool CItem::FindExtra_Version(UInt64 &version) const { unsigned size; - int offset = FindExtra(NExtraRecordType::kVersion, size); + int offset = FindExtra(NExtraID::kVersion, size); if (offset < 0) return false; const Byte *p = Extra + (unsigned)offset; @@ -202,26 +386,12 @@ bool CItem::FindExtra_Version(UInt64 &version) const bool CItem::FindExtra_Link(CLinkInfo &link) const { unsigned size; - int offset = FindExtra(NExtraRecordType::kLink, size); + int offset = FindExtra(NExtraID::kLink, size); if (offset < 0) return false; - const Byte *p = Extra + (unsigned)offset; - - unsigned num = ReadVarInt(p, size, &link.Type); - if (num == 0) return false; p += num; size -= num; - - num = ReadVarInt(p, size, &link.Flags); - if (num == 0) return false; p += num; size -= num; - - UInt64 len; - num = ReadVarInt(p, size, &len); - if (num == 0) return false; p += num; size -= num; - - if (size != len) + if (!link.Parse(Extra + (unsigned)offset, size)) return false; - - link.NameLen = (unsigned)len; - link.NameOffset = (unsigned)(p - Extra); + link.NameOffset += offset; return true; } @@ -268,14 +438,14 @@ void CItem::Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) UString unicode; if (ConvertUTF8ToUnicode(s, unicode)) - prop = NItemName::GetOSName(unicode); + prop = NItemName::GetOsPath(unicode); } bool CItem::GetAltStreamName(AString &name) const { name.Empty(); unsigned size; - int offset = FindExtra(NExtraRecordType::kSubdata, size); + int offset = FindExtra(NExtraID::kSubdata, size); if (offset < 0) return false; name.SetFrom_CalcLen((const char *)(Extra + (unsigned)offset), size); @@ -578,7 +748,7 @@ HRESULT CInArchive::ReadBlockHeader(CHeader &h) /* -int CInArcInfo::FindExtra(unsigned type, unsigned &recordDataSize) const +int CInArcInfo::FindExtra(unsigned extraID, unsigned &recordDataSize) const { recordDataSize = 0; size_t offset = 0; @@ -601,14 +771,14 @@ int CInArcInfo::FindExtra(unsigned type, unsigned &recordDataSize) const rem = (size_t)size; } { - UInt64 type2; - unsigned num = ReadVarInt(Extra + offset, rem, &type2); + UInt64 id; + unsigned num = ReadVarInt(Extra + offset, rem, &id); if (num == 0) return -1; offset += num; rem -= num; - if (type2 == type) + if (id == extraID) { recordDataSize = (unsigned)rem; return (int)offset; @@ -929,7 +1099,7 @@ HRESULT CUnpacker::Create(DECL_EXTERNAL_CODECS_LOC_VARS const CItem &item, bool } unsigned cryptoSize = 0; - int cryptoOffset = item.FindExtra(NExtraRecordType::kCrypto, cryptoSize); + int cryptoOffset = item.FindExtra(NExtraID::kCrypto, cryptoSize); if (cryptoOffset >= 0) { @@ -1023,7 +1193,7 @@ HRESULT CUnpacker::Code(const CItem &item, const CItem &lastItem, UInt64 packSiz // if (res == S_OK) { unsigned cryptoSize = 0; - int cryptoOffset = lastItem.FindExtra(NExtraRecordType::kCrypto, cryptoSize); + int cryptoOffset = lastItem.FindExtra(NExtraID::kCrypto, cryptoSize); NCrypto::NRar5::CDecoder *crypto = NULL; if (cryptoOffset >= 0) @@ -1190,7 +1360,7 @@ static const Byte kProps[] = kpidCRC, kpidHostOS, kpidMethod, - + kpidCharacts, kpidSymLink, kpidHardLink, kpidCopyLink, @@ -1308,8 +1478,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { if (/* &_missingVol || */ !_missingVolName.IsEmpty()) { - UString s; - s.SetFromAscii("Missing volume : "); + UString s ("Missing volume : "); s += _missingVolName; prop = s; } @@ -1339,13 +1508,11 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { if (arcInfo->IsVolume()) { - char sz[32]; - ConvertUInt64ToString(arcInfo->GetVolIndex() + 1, sz); - unsigned len = MyStringLen(sz); - AString s = "part"; - for (; len < 2; len++) + AString s ("part"); + UInt32 v = (UInt32)arcInfo->GetVolIndex() + 1; + if (v < 10) s += '0'; - s += sz; + s.Add_UInt32(v); s += ".rar"; prop = s; } @@ -1452,7 +1619,7 @@ STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CPropVariant &prop) { unsigned size; - int offset = item.FindExtra(NExtraRecordType::kTime, size); + int offset = item.FindExtra(NExtraID::kTime, size); if (offset < 0) return; @@ -1470,29 +1637,43 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp return; unsigned numStamps = 0; + unsigned curStamp = 0; unsigned i; for (i = 0; i < 3; i++) if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0) + { + if (i == stampIndex) + curStamp = numStamps; numStamps++; - unsigned stampSizeLog = ((flags & NTimeRecord::NFlags::kUnixTime) != 0) ? 2 : 3; - - if ((numStamps << stampSizeLog) != size) - return; - - numStamps = 0; - for (i = 0; i < stampIndex; i++) - if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0) - numStamps++; - - p += (numStamps << stampSizeLog); + } FILETIME ft; + if ((flags & NTimeRecord::NFlags::kUnixTime) != 0) - NWindows::NTime::UnixTimeToFileTime(Get32(p), ft); + { + curStamp *= 4; + if (curStamp + 4 > size) + return; + const Byte *p2 = p + curStamp; + UInt64 val = NTime::UnixTimeToFileTime64(Get32(p2)); + numStamps *= 4; + if ((flags & NTimeRecord::NFlags::kUnixNs) != 0 && numStamps * 2 <= size) + { + const UInt32 ns = Get32(p2 + numStamps) & 0x3FFFFFFF; + if (ns < 1000000000) + val += ns / 100; + } + ft.dwLowDateTime = (DWORD)val; + ft.dwHighDateTime = (DWORD)(val >> 32); + } else { - ft.dwLowDateTime = Get32(p); - ft.dwHighDateTime = Get32(p + 4); + curStamp *= 8; + if (curStamp + 8 > size) + return; + const Byte *p2 = p + curStamp; + ft.dwLowDateTime = Get32(p2); + ft.dwHighDateTime = Get32(p2 + 4); } prop = ft; @@ -1537,19 +1718,19 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val break; if (item.Version_Defined) { - wchar_t temp[32]; + char temp[32]; // temp[0] = ';'; // ConvertUInt64ToString(item.Version, temp + 1); // unicodeName += temp; ConvertUInt64ToString(item.Version, temp); - UString s2 = L"[VER]" WSTRING_PATH_SEPARATOR; + UString s2 ("[VER]" STRING_PATH_SEPARATOR); s2 += temp; s2.Add_PathSepar(); unicodeName.Insert(0, s2); } } - NItemName::ConvertToOSName2(unicodeName); + NItemName::ReplaceToOsSlashes_Remove_TailSlash(unicodeName); prop = unicodeName; break; @@ -1623,7 +1804,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidMethod: { - char temp[64]; + char temp[128]; unsigned algo = item.GetAlgoVersion(); char *s = temp; if (algo != 0) @@ -1645,16 +1826,28 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } unsigned cryptoSize = 0; - int cryptoOffset = item.FindExtra(NExtraRecordType::kCrypto, cryptoSize); + int cryptoOffset = item.FindExtra(NExtraID::kCrypto, cryptoSize); if (cryptoOffset >= 0) { s = temp + strlen(temp); *s++ = ' '; - strcpy(s, "AES:"); + CCryptoInfo cryptoInfo; - if (cryptoInfo.Parse(item.Extra + (unsigned)cryptoOffset, cryptoSize)) + + bool isOK = cryptoInfo.Parse(item.Extra + (unsigned)cryptoOffset, cryptoSize); + + if (cryptoInfo.Algo == 0) + s = MyStpCpy(s, "AES"); + else { + s = MyStpCpy(s, "Crypto_"); + ConvertUInt64ToString(cryptoInfo.Algo, s); s += strlen(s); + } + + if (isOK) + { + *s++ = ':'; ConvertUInt32ToString(cryptoInfo.Cnt, s); s += strlen(s); *s++ = ':'; @@ -1666,6 +1859,35 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val break; } + case kpidCharacts: + { + AString s; + + if (item.ACL >= 0) + { + s.Add_OptSpaced("ACL"); + } + + UInt32 flags = item.Flags; + // flags &= ~(6); // we don't need compression related bits here. + + if (flags != 0) + { + AString s2 = FlagsToString(k_FileFlags, ARRAY_SIZE(k_FileFlags), flags); + if (!s2.IsEmpty()) + { + s.Add_OptSpaced(s2); + } + } + + item.PrintInfo(s); + + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidHostOS: if (item.HostOS < ARRAY_SIZE(kHostOS)) prop = kHostOS[(size_t)item.HostOS]; @@ -1788,7 +2010,7 @@ void CHandler::FillLinks() const CItem &item = _items[ref.Item]; if (item.IsDir() || item.IsService() || item.PackSize != 0) continue; - CItem::CLinkInfo linkInfo; + CLinkInfo linkInfo; if (!item.FindExtra_Link(linkInfo) || linkInfo.Type != NLinkType::kFileCopy) continue; link.SetFrom_CalcLen((const char *)(item.Extra + linkInfo.NameOffset), linkInfo.NameLen); diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.h b/CPP/7zip/Archive/Rar/Rar5Handler.h index 27e937de..d3e33d7c 100644 --- a/CPP/7zip/Archive/Rar/Rar5Handler.h +++ b/CPP/7zip/Archive/Rar/Rar5Handler.h @@ -85,7 +85,7 @@ enum EHostOS // ---------- Extra ---------- -namespace NExtraRecordType +namespace NExtraID { enum { @@ -99,7 +99,7 @@ namespace NExtraRecordType }; } -// const unsigned kCryptoAlgo_AES = 0; +const unsigned kCryptoAlgo_AES = 0; namespace NCryptoFlags { @@ -133,8 +133,9 @@ namespace NTimeRecord { const unsigned kUnixTime = 1 << 0; const unsigned kMTime = 1 << 1; - // const unsigned kCTime = 1 << 2; - // const unsigned kATime = 1 << 3; + const unsigned kCTime = 1 << 2; + const unsigned kATime = 1 << 3; + const unsigned kUnixNs = 1 << 4; } } @@ -156,6 +157,17 @@ namespace NLinkFlags } +struct CLinkInfo +{ + UInt64 Type; + UInt64 Flags; + unsigned NameOffset; + unsigned NameLen; + + bool Parse(const Byte *p, unsigned size); +}; + + struct CItem { UInt32 CommonFlags; @@ -230,18 +242,20 @@ struct CItem bool Is_ACL() const { return IsService() && Name == "ACL"; } // bool Is_QO() const { return IsService() && Name == "QO"; } - int FindExtra(unsigned type, unsigned &recordDataSize) const; + int FindExtra(unsigned extraID, unsigned &recordDataSize) const; + void PrintInfo(AString &s) const; + bool IsEncrypted() const { unsigned size; - return FindExtra(NExtraRecordType::kCrypto, size) >= 0; + return FindExtra(NExtraID::kCrypto, size) >= 0; } int FindExtra_Blake() const { unsigned size = 0; - int offset = FindExtra(NExtraRecordType::kHash, size); + int offset = FindExtra(NExtraID::kHash, size); if (offset >= 0 && size == BLAKE2S_DIGEST_SIZE + 1 && Extra[(unsigned)offset] == kHashID_Blake2sp) @@ -251,14 +265,6 @@ struct CItem bool FindExtra_Version(UInt64 &version) const; - struct CLinkInfo - { - UInt64 Type; - UInt64 Flags; - unsigned NameOffset; - unsigned NameLen; - }; - bool FindExtra_Link(CLinkInfo &link) const; void Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const; bool Is_CopyLink() const; @@ -313,7 +319,7 @@ struct CInArcInfo bool Is_Recovery() const { return (Flags & NLocatorFlags::kRecovery) != 0; } }; - int FindExtra(unsigned type, unsigned &recordDataSize) const; + int FindExtra(unsigned extraID, unsigned &recordDataSize) const; bool FindExtra_Locator(CLocator &locator) const; */ diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp index e858c1ea..c097b15c 100644 --- a/CPP/7zip/Archive/Rar/RarHandler.cpp +++ b/CPP/7zip/Archive/Rar/RarHandler.cpp @@ -104,20 +104,18 @@ static const char * const kHostOS[] = , "BeOS" }; -static const char *kUnknownOS = "Unknown"; - -static const CUInt32PCharPair k_Flags[] = +static const char * const k_Flags[] = { - { 0, "Volume" }, - { 1, "Comment" }, - { 2, "Lock" }, - { 3, "Solid" }, - { 4, "NewVolName" }, // pack_comment in old versuons - { 5, "Authenticity" }, - { 6, "Recovery" }, - { 7, "BlockEncryption" }, - { 8, "FirstVolume" }, - { 9, "EncryptVer" } + "Volume" + , "Comment" + , "Lock" + , "Solid" + , "NewVolName" // pack_comment in old versuons + , "Authenticity" + , "Recovery" + , "BlockEncryption" + , "FirstVolume" + , "EncryptVer" // 9 }; enum EErrorType @@ -132,13 +130,13 @@ class CInArchive { IInStream *m_Stream; UInt64 m_StreamStartPosition; - CBuffer<wchar_t> _unicodeNameBuffer; + UString _unicodeNameBuffer; CByteBuffer _comment; CByteBuffer m_FileHeaderData; NHeader::NBlock::CBlock m_BlockHeader; NCrypto::NRar3::CDecoder *m_RarAESSpec; CMyComPtr<ICompressFilter> m_RarAES; - CBuffer<Byte> m_DecryptedData; + CByteBuffer m_DecryptedData; Byte *m_DecryptedDataAligned; UInt32 m_DecryptedDataSize; bool m_CryptoMode; @@ -272,14 +270,19 @@ bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size) return processed == size; } -static void DecodeUnicodeFileName(const Byte *name, const Byte *encName, + +static unsigned DecodeUnicodeFileName(const Byte *name, const Byte *encName, unsigned encSize, wchar_t *unicodeName, unsigned maxDecSize) { unsigned encPos = 0; unsigned decPos = 0; unsigned flagBits = 0; Byte flags = 0; - Byte highByte = encName[encPos++]; + + if (encPos >= encSize) + return 0; // error + const unsigned highBits = ((unsigned)encName[encPos++]) << 8; + while (encPos < encSize && decPos < maxDecSize) { if (flagBits == 0) @@ -287,40 +290,46 @@ static void DecodeUnicodeFileName(const Byte *name, const Byte *encName, flags = encName[encPos++]; flagBits = 8; } - switch (flags >> 6) + + if (encPos >= encSize) + break; // error + unsigned len = encName[encPos++]; + + flagBits -= 2; + const unsigned mode = (flags >> flagBits) & 3; + + if (mode != 3) { - case 0: - unicodeName[decPos++] = encName[encPos++]; - break; - case 1: - unicodeName[decPos++] = (wchar_t)(encName[encPos++] + (highByte << 8)); - break; - case 2: - unicodeName[decPos++] = (wchar_t)(encName[encPos] + (encName[encPos + 1] << 8)); - encPos += 2; - break; - case 3: - { - unsigned len = encName[encPos++]; - if (len & 0x80) - { - Byte correction = encName[encPos++]; - for (len = (len & 0x7f) + 2; - len > 0 && decPos < maxDecSize; len--, decPos++) - unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + (highByte << 8)); - } - else - for (len += 2; len > 0 && decPos < maxDecSize; len--, decPos++) - unicodeName[decPos] = name[decPos]; - } - break; + if (mode == 1) + len += highBits; + else if (mode == 2) + { + if (encPos >= encSize) + break; // error + len += ((unsigned)encName[encPos++] << 8); + } + unicodeName[decPos++] = (wchar_t)len; + } + else + { + if (len & 0x80) + { + if (encPos >= encSize) + break; // error + Byte correction = encName[encPos++]; + for (len = (len & 0x7f) + 2; len > 0 && decPos < maxDecSize; len--, decPos++) + unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + highBits); + } + else + for (len += 2; len > 0 && decPos < maxDecSize; len--, decPos++) + unicodeName[decPos] = name[decPos]; } - flags <<= 2; - flagBits -= 2; } - unicodeName[decPos < maxDecSize ? decPos : maxDecSize - 1] = 0; + + return decPos < maxDecSize ? decPos : maxDecSize - 1; } + void CInArchive::ReadName(const Byte *p, unsigned nameSize, CItem &item) { item.UnicodeName.Empty(); @@ -336,8 +345,8 @@ void CInArchive::ReadName(const Byte *p, unsigned nameSize, CItem &item) { i++; unsigned uNameSizeMax = MyMin(nameSize, (unsigned)0x400); - _unicodeNameBuffer.AllocAtLeast(uNameSizeMax + 1); - DecodeUnicodeFileName(p, p + i, nameSize - i, _unicodeNameBuffer, uNameSizeMax); + unsigned len = DecodeUnicodeFileName(p, p + i, nameSize - i, _unicodeNameBuffer.GetBuf(uNameSizeMax), uNameSizeMax); + _unicodeNameBuffer.ReleaseBuf_SetEnd(len); item.UnicodeName = _unicodeNameBuffer; } else if (!ConvertUTF8ToUnicode(item.Name, item.UnicodeName)) @@ -818,7 +827,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidSolid: prop = _arcInfo.IsSolid(); break; case kpidCharacts: { - AString s = FlagsToString(k_Flags, ARRAY_SIZE(k_Flags), _arcInfo.Flags); + AString s (FlagsToString(k_Flags, ARRAY_SIZE(k_Flags), _arcInfo.Flags)); // FLAGS_TO_PROP(k_Flags, _arcInfo.Flags, prop); if (_arcInfo.Is_DataCRC_Defined()) { @@ -871,8 +880,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) if (/* &_missingVol || */ !_missingVolName.IsEmpty()) { - UString s; - s.SetFromAscii("Missing volume : "); + UString s ("Missing volume : "); s += _missingVolName; prop = s; } @@ -900,13 +908,11 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { if (_arcInfo.Is_VolNumber_Defined()) { - char sz[16]; - ConvertUInt32ToString((UInt32)_arcInfo.VolNumber + 1, sz); - unsigned len = MyStringLen(sz); - AString s = "part"; - for (; len < 2; len++) + AString s ("part"); + UInt32 v = (UInt32)_arcInfo.VolNumber + 1; + if (v < 10) s += '0'; - s += sz; + s.Add_UInt32(v); s += ".rar"; prop = s; } @@ -974,7 +980,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val u = mainItem->GetName(); u += item.GetName(); */ - prop = (const wchar_t *)NItemName::WinNameToOSName(item.GetName()); + prop = (const wchar_t *)NItemName::WinPathToOsPath(item.GetName()); break; } case kpidIsDir: prop = item.IsDir(); break; @@ -1015,7 +1021,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = s; break; } - case kpidHostOS: prop = (item.HostOS < ARRAY_SIZE(kHostOS)) ? kHostOS[item.HostOS] : kUnknownOS; break; + case kpidHostOS: + TYPE_TO_PROP(kHostOS, item.HostOS, prop); + break; } prop.Detach(value); return S_OK; @@ -1324,7 +1332,13 @@ STDMETHODIMP CVolsInStream::Read(void *data, UInt32 size, UInt32 *processedSize) if (_curIndex >= _refItem.NumItems) break; const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex]; - IInStream *s = (*_arcs)[_refItem.VolumeIndex + _curIndex].Stream; + unsigned volIndex = _refItem.VolumeIndex + _curIndex; + if (volIndex >= _arcs->Size()) + { + return S_OK; + // return S_FALSE; + } + IInStream *s = (*_arcs)[volIndex].Stream; RINOK(s->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL)); _stream = s; _calcCrc = (CrcIsOK && item.IsSplitAfter()); diff --git a/CPP/7zip/Archive/Rar/RarVol.h b/CPP/7zip/Archive/Rar/RarVol.h index 2d2ce473..310369d4 100644 --- a/CPP/7zip/Archive/Rar/RarVol.h +++ b/CPP/7zip/Archive/Rar/RarVol.h @@ -41,7 +41,7 @@ public: } else if (ext.IsEqualTo_Ascii_NoCase("exe")) { - _after.SetFromAscii(".rar"); + _after = ".rar"; base.DeleteFrom(dotPos); } else if (!newStyle) @@ -76,8 +76,8 @@ public: _after.Empty(); _before = base; - _before += L'.'; - _changed.SetFromAscii("r00"); + _before += '.'; + _changed = "r00"; _needChangeForNext = false; return true; } diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp index 08df1ae7..e0ec28ce 100644 --- a/CPP/7zip/Archive/RpmHandler.cpp +++ b/CPP/7zip/Archive/RpmHandler.cpp @@ -11,6 +11,7 @@ #include "../../Common/UTFConvert.h" #include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" #include "../../Windows/TimeUtils.h" #include "../Common/RegisterArc.h" @@ -167,6 +168,16 @@ struct CEntry } }; + +#ifdef _SHOW_RPM_METADATA +struct CMetaFile +{ + UInt32 Tag; + UInt32 Offset; + UInt32 Size; +}; +#endif + class CHandler: public CHandlerCont { UInt64 _headersSize; // is equal to start offset of payload data @@ -198,6 +209,7 @@ class CHandler: public CHandlerCont #ifdef _SHOW_RPM_METADATA AString _metadata; + CRecordVector<CMetaFile> _metaFiles; #endif void SetTime(NCOM::CPropVariant &prop) const @@ -205,8 +217,8 @@ class CHandler: public CHandlerCont if (_time_Defined && _buildTime != 0) { FILETIME ft; - if (NTime::UnixTime64ToFileTime(_buildTime, ft)) - prop = ft; + NTime::UnixTimeToFileTime(_buildTime, ft); + prop = ft; } } @@ -266,16 +278,10 @@ void CHandler::AddCPU(AString &s) const { if (_lead.Type == kRpmType_Bin) { - char temp[16]; - const char *p; if (_lead.Cpu < ARRAY_SIZE(k_CPUs)) - p = k_CPUs[_lead.Cpu]; + s += k_CPUs[_lead.Cpu]; else - { - ConvertUInt32ToString(_lead.Cpu, temp); - p = temp; - } - s += p; + s.Add_UInt32(_lead.Cpu); } } } @@ -376,29 +382,18 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) SetStringProp(_os, prop); else { - char temp[16]; - const char *p; - if (_lead.Os < ARRAY_SIZE(k_OS)) - p = k_OS[_lead.Os]; - else - { - ConvertUInt32ToString(_lead.Os, temp); - p = temp; - } - prop = p; + TYPE_TO_PROP(k_OS, _lead.Os, prop); } break; } #ifdef _SHOW_RPM_METADATA - case kpidComment: SetStringProp(_metadata, prop); break; + // case kpidComment: SetStringProp(_metadata, prop); break; #endif case kpidName: { - AString s = GetBaseName(); - s += ".rpm"; - SetStringProp(s, prop); + SetStringProp(GetBaseName() + ".rpm", prop); break; } } @@ -408,9 +403,10 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } -STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { NWindows::NCOM::CPropVariant prop; + if (index == 0) switch (propID) { case kpidSize: @@ -425,7 +421,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN case kpidPath: { - AString s = GetBaseName(); + AString s (GetBaseName()); s += '.'; AddSubFileExtension(s); SetStringProp(s, prop); @@ -440,6 +436,37 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN } */ } + #ifdef _SHOW_RPM_METADATA + else + { + index--; + if (index > _metaFiles.Size()) + return E_INVALIDARG; + const CMetaFile &meta = _metaFiles[index]; + switch (propID) + { + case kpidSize: + case kpidPackSize: + prop = meta.Size; + break; + + case kpidMTime: + case kpidCTime: + SetTime(prop); + break; + + case kpidPath: + { + AString s ("[META]"); + s.Add_PathSepar(); + s.Add_UInt32(meta.Tag); + prop = s; + break; + } + } + } + #endif + prop.Detach(value); return S_OK; } @@ -499,10 +526,7 @@ HRESULT CHandler::ReadHeader(ISequentialInStream *stream, bool isMainHeader) { #ifdef _SHOW_RPM_METADATA { - char temp[16]; - ConvertUInt32ToString(entry.Tag, temp); - - _metadata += temp; + _metadata.Add_UInt32(entry.Tag); _metadata += ": "; } #endif @@ -515,7 +539,7 @@ HRESULT CHandler::ReadHeader(ISequentialInStream *stream, bool isMainHeader) for (j = 0; j < rem && p[j] != 0; j++); if (j == rem) return S_FALSE; - AString s = (const char *)p; + AString s((const char *)p); switch (entry.Tag) { case RPMTAG_NAME: _name = s; break; @@ -548,9 +572,7 @@ HRESULT CHandler::ReadHeader(ISequentialInStream *stream, bool isMainHeader) { if (t != 0) _metadata.Add_Space(); - char temp[16]; - ConvertUInt32ToString(Get32(p + t * 4), temp); - _metadata += temp; + _metadata.Add_UInt32(Get32(p + t * 4)); } #endif } @@ -587,9 +609,7 @@ HRESULT CHandler::ReadHeader(ISequentialInStream *stream, bool isMainHeader) { if (t != 0) _metadata.Add_Space(); - char temp[16]; - ConvertUInt32ToString(Get16(p + t * 2), temp); - _metadata += temp; + _metadata.Add_UInt32(Get16(p + t * 2)); } } else if (entry.Type == k_EntryType_BIN) @@ -607,9 +627,18 @@ HRESULT CHandler::ReadHeader(ISequentialInStream *stream, bool isMainHeader) { // p = p; } + _metadata += '\n'; #endif } + + #ifdef _SHOW_RPM_METADATA + CMetaFile meta; + meta.Offset = entry.Offset; + meta.Tag = entry.Tag; + meta.Size = entry.Count; + _metaFiles.Add(meta); + #endif } headerSize += k_HeaderSig_Size; @@ -715,6 +744,7 @@ STDMETHODIMP CHandler::Close() #ifdef _SHOW_RPM_METADATA _metadata.Empty(); + _metaFiles.Size(); #endif _stream.Release(); @@ -723,7 +753,12 @@ STDMETHODIMP CHandler::Close() STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { - *numItems = 1; + *numItems = 1 + #ifdef _SHOW_RPM_METADATA + + _metaFiles.Size() + #endif + ; + return S_OK; } diff --git a/CPP/7zip/Archive/SplitHandler.cpp b/CPP/7zip/Archive/SplitHandler.cpp index 72b52fe7..f4a10b1d 100644 --- a/CPP/7zip/Archive/SplitHandler.cpp +++ b/CPP/7zip/Archive/SplitHandler.cpp @@ -181,7 +181,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) seqName._splitStyle = splitStyle; if (prefix.Len() < 1) - _subName.SetFromAscii("file"); + _subName = "file"; else _subName.SetFrom(prefix, prefix.Len() - 1); diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp index 3bcb2862..29e3bb6c 100644 --- a/CPP/7zip/Archive/SquashfsHandler.cpp +++ b/CPP/7zip/Archive/SquashfsHandler.cpp @@ -11,6 +11,7 @@ #include "../../Common/MyLinux.h" #include "../../Common/IntToString.h" #include "../../Common/StringConvert.h" +#include "../../Common/UTFConvert.h" #include "../../Windows/PropVariantUtils.h" #include "../../Windows/TimeUtils.h" @@ -67,7 +68,7 @@ static const UInt32 kSignature32_LZ = 0x71736873; static const char * const k_Methods[] = { - "Unknown" + "0" , "ZLIB" , "LZMA" , "LZO" @@ -109,16 +110,16 @@ enum kFlag_EXPORT }; -static const CUInt32PCharPair k_Flags[] = +static const char * const k_Flags[] = { - { kFlag_UNC_INODES, "UNCOMPRESSED_INODES" }, - { kFlag_UNC_DATA, "UNCOMPRESSED_DATA" }, - { kFlag_CHECK, "CHECK" }, - { kFlag_UNC_FRAGS, "UNCOMPRESSED_FRAGMENTS" }, - { kFlag_NO_FRAGS, "NO_FRAGMENTS" }, - { kFlag_ALWAYS_FRAG, "ALWAYS_FRAGMENTS" }, - { kFlag_DUPLICATE, "DUPLICATES_REMOVED" }, - { kFlag_EXPORT, "EXPORTABLE" } + "UNCOMPRESSED_INODES" + , "UNCOMPRESSED_DATA" + , "CHECK" + , "UNCOMPRESSED_FRAGMENTS" + , "NO_FRAGMENTS" + , "ALWAYS_FRAGMENTS" + , "DUPLICATES_REMOVED" + , "EXPORTABLE" }; static const UInt32 kNotCompressedBit16 = (1 << 15); @@ -841,6 +842,8 @@ class CHandler: CHeader _h; bool _noPropsLZMA; bool _needCheckLzma; + + UInt32 _openCodePage; CMyComPtr<IInStream> _stream; UInt64 _sizeCalculated; @@ -944,7 +947,8 @@ static const Byte kArcProps[] = kpidClusterSize, kpidBigEndian, kpidCTime, - kpidCharacts + kpidCharacts, + kpidCodePage // kpidNumBlocks }; @@ -1333,6 +1337,8 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned return S_FALSE; rem = fileSize; + AString tempString; + CRecordVector<CTempItem> tempItems; while (rem != 0) { @@ -1398,7 +1404,7 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned } CItem item; - item.Ptr = (UInt32)(p - _dirs.Data); + item.Ptr = (UInt32)(p - (const Byte *)_dirs.Data); UInt32 size; if (_h.IsOldVersion()) @@ -1432,6 +1438,14 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned size++; if (rem < size) return S_FALSE; + + if (_openCodePage == CP_UTF8) + { + tempString.SetFrom_CalcLen((const char *)p, size); + if (!CheckUTF8(tempString)) + _openCodePage = CP_OEMCP; + } + p += size; rem -= size; item.Parent = parent; @@ -1706,6 +1720,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb STDMETHODIMP CHandler::Close() { + _openCodePage = CP_UTF8; _sizeCalculated = 0; _limitedInStreamSpec->ReleaseStream(); @@ -1829,6 +1844,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { case kpidMethod: { + char sz[16]; const char *s; if (_noPropsLZMA) s = "LZMA Spec"; @@ -1836,25 +1852,27 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) s = "LZMA ZLIB"; else { - s = k_Methods[0]; + s = NULL; if (_h.Method < ARRAY_SIZE(k_Methods)) s = k_Methods[_h.Method]; + if (!s) + { + ConvertUInt32ToString(_h.Method, sz); + s = sz; + } } prop = s; break; } case kpidFileSystem: { - AString res = "SquashFS"; + AString res ("SquashFS"); if (_h.SeveralMethods) res += "-LZMA"; res.Add_Space(); - char s[16]; - ConvertUInt32ToString(_h.Major, s); - res += s; + res.Add_UInt32(_h.Major); res += '.'; - ConvertUInt32ToString(_h.Minor, s); - res += s; + res.Add_UInt32(_h.Minor); prop = res; break; } @@ -1875,6 +1893,24 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) if (_sizeCalculated >= _h.InodeTable) prop = _sizeCalculated - _h.InodeTable; break; + + case kpidCodePage: + { + char sz[16]; + const char *name = NULL; + switch (_openCodePage) + { + case CP_OEMCP: name = "OEM"; break; + case CP_UTF8: name = "UTF-8"; break; + } + if (!name) + { + ConvertUInt32ToString(_openCodePage, sz); + name = sz; + } + prop = name; + break; + } } prop.Detach(value); return S_OK; @@ -1892,7 +1928,17 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val switch (propID) { - case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break; + case kpidPath: + { + AString path (GetPath(index)); + UString s; + if (_openCodePage == CP_UTF8) + ConvertUTF8ToUnicode(path, s); + else + MultiByteToUnicodeString2(s, path, _openCodePage); + prop = s; + break; + } case kpidIsDir: prop = isDir; break; // case kpidOffset: if (!node.IsLink()) prop = (UInt64)node.StartBlock; break; case kpidSize: if (!isDir) prop = node.GetSize(); break; diff --git a/CPP/7zip/Archive/SwfHandler.cpp b/CPP/7zip/Archive/SwfHandler.cpp index 06ed2106..16a6e6f9 100644 --- a/CPP/7zip/Archive/SwfHandler.cpp +++ b/CPP/7zip/Archive/SwfHandler.cpp @@ -10,6 +10,7 @@ #include "../../Common/MyString.h" #include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" #include "../Common/InBuffer.h" #include "../Common/LimitedStreams.h" @@ -562,14 +563,13 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR { _lzmaMode = false; RINOK(_props.SetProperties(names, values, numProps)); - AString m = _props.MethodName; - m.MakeLower_Ascii(); - if (m.IsEqualTo("lzma")) + const AString &m = _props.MethodName; + if (m.IsEqualTo_Ascii_NoCase("lzma")) { return E_NOTIMPL; // _lzmaMode = true; } - else if (m.IsEqualTo("deflate") || m.IsEmpty()) + else if (m.IsEqualTo_Ascii_NoCase("Deflate") || m.IsEmpty()) _lzmaMode = false; else return E_INVALIDARG; @@ -762,12 +762,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidPackSize: prop = (UInt64)tag.Buf.Size(); break; case kpidComment: - if (tag.Type < ARRAY_SIZE(g_TagDesc)) - { - const char *s = g_TagDesc[tag.Type]; - if (s != NULL) - prop = s; - } + TYPE_TO_PROP(g_TagDesc, tag.Type, prop); break; } prop.Detach(value); diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp index baa43c79..72fbf74e 100644 --- a/CPP/7zip/Archive/Tar/TarHandler.cpp +++ b/CPP/7zip/Archive/Tar/TarHandler.cpp @@ -81,20 +81,19 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidCodePage: { + char sz[16]; const char *name = NULL; switch (_openCodePage) { case CP_OEMCP: name = "OEM"; break; - case CP_UTF8: name = "UTF-8"; break; + case CP_UTF8: name = "UTF-8"; break; } - if (name != NULL) - prop = name; - else + if (!name) { - char sz[16]; ConvertUInt32ToString(_openCodePage, sz); - prop = sz; - }; + name = sz; + } + prop = name; break; } } @@ -316,7 +315,7 @@ void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant else MultiByteToUnicodeString2(dest, s, _curCodePage); if (toOs) - NItemName::ConvertToOSName2(dest); + NItemName::ReplaceToOsSlashes_Remove_TailSlash(dest); prop = dest; } @@ -353,7 +352,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = ft; } break; - case kpidPosixAttrib: prop = item->Mode; break; + case kpidPosixAttrib: prop = item->Get_Combined_Mode(); break; case kpidUser: TarStringToUnicode(item->User, prop); break; case kpidGroup: TarStringToUnicode(item->Group, prop); break; case kpidSymLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kSymLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break; diff --git a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp index 0b67a285..41934339 100644 --- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp +++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp @@ -35,7 +35,7 @@ HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID pro { UString s = prop.bstrVal; if (convertSlash) - s = NItemName::MakeLegalName(s); + NItemName::ReplaceSlashes_OsToUnix(s); if (codePage == CP_UTF8) { @@ -123,6 +123,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return E_INVALIDARG; else ui.Mode = prop.ulVal; + // FIXME : we can clear high file type bits to be more compatible with tars created by GNU TAR. + // ui.Mode &= ~(UInt32)MY_LIN_S_IFMT; } { diff --git a/CPP/7zip/Archive/Tar/TarHeader.cpp b/CPP/7zip/Archive/Tar/TarHeader.cpp index 70be09f3..a22f36bd 100644 --- a/CPP/7zip/Archive/Tar/TarHeader.cpp +++ b/CPP/7zip/Archive/Tar/TarHeader.cpp @@ -8,15 +8,15 @@ namespace NArchive { namespace NTar { namespace NFileHeader { - const char *kLongLink = "././@LongLink"; - const char *kLongLink2 = "@LongLink"; + const char * const kLongLink = "././@LongLink"; + const char * const kLongLink2 = "@LongLink"; // The magic field is filled with this if uname and gname are valid. namespace NMagic { - // const char *kUsTar = "ustar"; // 5 chars - // const char *kGNUTar = "GNUtar "; // 7 chars and a null - // const char *kEmpty = "\0\0\0\0\0\0\0\0"; + // const char * const kUsTar = "ustar"; // 5 chars + // const char * const kGNUTar = "GNUtar "; // 7 chars and a null + // const char * const kEmpty = "\0\0\0\0\0\0\0\0"; const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ; } diff --git a/CPP/7zip/Archive/Tar/TarHeader.h b/CPP/7zip/Archive/Tar/TarHeader.h index df594d81..47971b58 100644 --- a/CPP/7zip/Archive/Tar/TarHeader.h +++ b/CPP/7zip/Archive/Tar/TarHeader.h @@ -67,15 +67,15 @@ namespace NFileHeader the last file name. */ } - extern const char *kLongLink; // = "././@LongLink"; - extern const char *kLongLink2; // = "@LongLink"; + extern const char * const kLongLink; // = "././@LongLink"; + extern const char * const kLongLink2; // = "@LongLink"; namespace NMagic { - // extern const char *kUsTar; // = "ustar"; // 5 chars - // extern const char *kGNUTar; // = "GNUtar "; // 7 chars and a null - // extern const char *kEmpty; // = "\0\0\0\0\0\0\0\0" - extern const char kUsTar_00[]; + // extern const char * const kUsTar; // = "ustar"; // 5 chars + // extern const char * const kGNUTar; // = "GNUtar "; // 7 chars and a null + // extern const char * const kEmpty; // = "\0\0\0\0\0\0\0\0" + extern const char kUsTar_00[8]; } } diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp index 57e18ac0..64807bfc 100644 --- a/CPP/7zip/Archive/Tar/TarIn.cpp +++ b/CPP/7zip/Archive/Tar/TarIn.cpp @@ -91,6 +91,16 @@ static bool ParseInt64(const char *p, Int64 &val) return res; } +static bool ParseInt64_MTime(const char *p, Int64 &val) +{ + // rare case tar contains spaces instead of MTime + for (unsigned i = 0; i < 12; i++) + if (p[i] != ' ') + return ParseInt64(p, val); + val = 0; + return true; +} + static bool ParseSize(const char *p, UInt64 &val) { if (GetBe32(p) == (UInt32)1 << 31) @@ -124,7 +134,7 @@ API_FUNC_IsArc IsArc_Tar(const Byte *p2, size_t size) Int64 time; UInt32 checkSum; CHECK(ParseSize(p, packSize)); p += 12; - CHECK(ParseInt64(p, time)); p += 12; + CHECK(ParseInt64_MTime(p, time)); p += 12; CHECK(OctalToNumber32(p, 8, checkSum)); return k_IsArc_Res_YES; } @@ -192,7 +202,7 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE RIF(ParseSize(p, item.PackSize)); item.Size = item.PackSize; p += 12; - RIF(ParseInt64(p, item.MTime)); p += 12; + RIF(ParseInt64_MTime(p, item.MTime)); p += 12; UInt32 checkSum; RIF(OctalToNumber32(p, 8, checkSum)); diff --git a/CPP/7zip/Archive/Tar/TarItem.h b/CPP/7zip/Archive/Tar/TarItem.h index 5245aaa4..bc3b4084 100644 --- a/CPP/7zip/Archive/Tar/TarItem.h +++ b/CPP/7zip/Archive/Tar/TarItem.h @@ -3,6 +3,8 @@ #ifndef __ARCHIVE_TAR_ITEM_H #define __ARCHIVE_TAR_ITEM_H +#include "../../../Common/MyLinux.h" + #include "../Common/ItemNameUtils.h" #include "TarHeader.h" @@ -56,6 +58,32 @@ struct CItem return false; } + UInt32 Get_Combined_Mode() const + { + return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag(); + } + + UInt32 Get_FileTypeMode_from_LinkFlag() const + { + switch (LinkFlag) + { + /* + case NFileHeader::NLinkFlag::kDirectory: + case NFileHeader::NLinkFlag::kDumpDir: + return MY_LIN_S_IFDIR; + */ + case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK; + case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK; + case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR; + case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO; + // case return MY_LIN_S_IFSOCK; + } + + if (IsDir()) + return MY_LIN_S_IFDIR; + return MY_LIN_S_IFREG; + } + bool IsDir() const { switch (LinkFlag) diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp index d52db9f4..cfe6c5ad 100644 --- a/CPP/7zip/Archive/Udf/UdfIn.cpp +++ b/CPP/7zip/Archive/Udf/UdfIn.cpp @@ -51,13 +51,13 @@ void MY_FAST_CALL Crc16GenerateTable(void) for (i = 0; i < 256; i++) { UInt32 r = (i << 8); - for (int j = 8; j > 0; j--) - r = ((r & 0x8000) ? ((r << 1) ^ kCrc16Poly) : (r << 1)) & 0xFFFF; + for (unsigned j = 0; j < 8; j++) + r = ((r << 1) ^ (kCrc16Poly & ((UInt32)0 - (r >> 15)))) & 0xFFFF; g_Crc16Table[i] = (UInt16)r; } } -UInt16 MY_FAST_CALL Crc16_Update(UInt16 v, const void *data, size_t size) +UInt32 MY_FAST_CALL Crc16_Update(UInt32 v, const void *data, size_t size) { const Byte *p = (const Byte *)data; for (; size > 0 ; size--, p++) @@ -65,12 +65,12 @@ UInt16 MY_FAST_CALL Crc16_Update(UInt16 v, const void *data, size_t size) return v; } -UInt16 MY_FAST_CALL Crc16Calc(const void *data, size_t size) +UInt32 MY_FAST_CALL Crc16Calc(const void *data, size_t size) { return Crc16_Update(CRC16_INIT_VAL, data, size); } -struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit; +static struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit; @@ -109,7 +109,7 @@ static UString ParseDString(const Byte *data, unsigned size) } } else - return L"[unknow]"; + return UString("[unknow]"); *p = 0; res.ReleaseBuf_SetLen((unsigned)(p - (const wchar_t *)res)); } @@ -179,12 +179,12 @@ HRESULT CTag::Parse(const Byte *buf, size_t size) Id = Get16(buf); Version = Get16(buf + 2); // SerialNumber = Get16(buf + 6); - UInt16 crc = Get16(buf + 8); - UInt16 crcLen = Get16(buf + 10); + UInt32 crc = Get16(buf + 8); + UInt32 crcLen = Get16(buf + 10); // TagLocation = Get32(buf + 12); - if (size >= 16 + (size_t)crcLen) - if (crc == Crc16Calc(buf + 16, crcLen)) + if (size >= 16 + crcLen) + if (crc == Crc16Calc(buf + 16, (size_t)crcLen)) return S_OK; return S_FALSE; } @@ -1077,14 +1077,7 @@ static UString GetSpecName(const UString &name) UString name2 = name; name2.Trim(); if (name2.IsEmpty()) - { - /* - wchar_t s[32]; - ConvertUInt64ToString(id, s); - return L"[" + (UString)s + L"]"; - */ - return L"[]"; - } + return UString("[]"); return name; } @@ -1116,22 +1109,19 @@ UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex, if (showFsName) { - wchar_t s[32]; - ConvertUInt32ToString(fsIndex, s); - UString newName = L"File Set "; - newName += s; + UString newName ("File Set "); + newName.Add_UInt32(fsIndex); UpdateWithName(name, newName); } if (showVolName) { - wchar_t s[32]; - ConvertUInt32ToString(volIndex, s); - UString newName = s; + UString newName; + newName.Add_UInt32(volIndex); UString newName2 = vol.GetName(); if (newName2.IsEmpty()) - newName2 = L"Volume"; - newName += L'-'; + newName2 = "Volume"; + newName += '-'; newName += newName2; UpdateWithName(name, newName); } diff --git a/CPP/7zip/Archive/UefiHandler.cpp b/CPP/7zip/Archive/UefiHandler.cpp index ff0737a0..f49b62c8 100644 --- a/CPP/7zip/Archive/UefiHandler.cpp +++ b/CPP/7zip/Archive/UefiHandler.cpp @@ -46,20 +46,58 @@ static const size_t kBufTotalSizeMax = (1 << 29); static const unsigned kNumFilesMax = (1 << 18); static const unsigned kLevelMax = 64; +static const Byte k_IntelMeSignature[] = +{ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x5A, 0xA5, 0xF0, 0x0F +}; + +bool IsIntelMe(const Byte *p) +{ + return memcmp(p, k_IntelMeSignature, sizeof(k_IntelMeSignature)) == 0; +} + static const unsigned kFvHeaderSize = 0x38; static const unsigned kGuidSize = 16; -#define CAPSULE_SIGNATURE \ - { 0xBD,0x86,0x66,0x3B,0x76,0x0D,0x30,0x40,0xB7,0x0E,0xB5,0x51,0x9E,0x2F,0xC5,0xA0 } -static const Byte kCapsuleSig[kGuidSize] = CAPSULE_SIGNATURE; + +#define CAPSULE_SIGNATURE 0xBD,0x86,0x66,0x3B,0x76,0x0D,0x30,0x40,0xB7,0x0E,0xB5,0x51,0x9E,0x2F,0xC5,0xA0 +#define CAPSULE2_SIGNATURE 0x8B,0xA6,0x3C,0x4A,0x23,0x77,0xFB,0x48,0x80,0x3D,0x57,0x8C,0xC1,0xFE,0xC4,0x4D +#define CAPSULE_UEFI_SIGNATURE 0xB9,0x82,0x91,0x53,0xB5,0xAB,0x91,0x43,0xB6,0x9A,0xE3,0xA9,0x43,0xF7,0x2F,0xCC +/* + 6dcbd5ed-e82d-4c44-bda1-7194199ad92a : Firmware Management ` +*/ + +static const Byte k_Guids_Capsules[][kGuidSize] = +{ + { CAPSULE_SIGNATURE }, + { CAPSULE2_SIGNATURE }, + { CAPSULE_UEFI_SIGNATURE } +}; + static const unsigned kFfsGuidOffset = 16; -#define FFS_SIGNATURE \ - { 0xD9,0x54,0x93,0x7A,0x68,0x04,0x4A,0x44,0x81,0xCE,0x0B,0xF6,0x17,0xD8,0x90,0xDF } -static const Byte k_FFS_Guid[kGuidSize] = FFS_SIGNATURE; -static const Byte k_MacFS_Guid[kGuidSize] = - { 0xAD,0xEE,0xAD,0x04,0xFF,0x61,0x31,0x4D,0xB6,0xBA,0x64,0xF8,0xBF,0x90,0x1F,0x5A }; +#define FFS1_SIGNATURE 0xD9,0x54,0x93,0x7A,0x68,0x04,0x4A,0x44,0x81,0xCE,0x0B,0xF6,0x17,0xD8,0x90,0xDF +#define FFS2_SIGNATURE 0x78,0xE5,0x8C,0x8C,0x3D,0x8A,0x1C,0x4F,0x99,0x35,0x89,0x61,0x85,0xC3,0x2D,0xD3 +#define MACFS_SIGNATURE 0xAD,0xEE,0xAD,0x04,0xFF,0x61,0x31,0x4D,0xB6,0xBA,0x64,0xF8,0xBF,0x90,0x1F,0x5A +// APPLE_BOOT +/* + "FFS3": "5473c07a-3dcb-4dca-bd6f-1e9689e7349a", + "NVRAM_EVSA": "fff12b8d-7696-4c8b-a985-2747075b4f50", + "NVRAM_NVAR": "cef5b9a3-476d-497f-9fdc-e98143e0422c", + "NVRAM_EVSA2": "00504624-8a59-4eeb-bd0f-6b36e96128e0", +static const Byte k_NVRAM_NVAR_Guid[kGuidSize] = + { 0xA3,0xB9,0xF5,0xCE,0x6D,0x47,0x7F,0x49,0x9F,0xDC,0xE9,0x81,0x43,0xE0,0x42,0x2C }; +*/ + +static const Byte k_Guids_FS[][kGuidSize] = +{ + { FFS1_SIGNATURE }, + { FFS2_SIGNATURE }, + { MACFS_SIGNATURE } +}; + static const UInt32 kFvSignature = 0x4856465F; // "_FVH" @@ -80,6 +118,8 @@ static const Byte kGuids[][kGuidSize] = { 0x18,0x88,0x53,0x4A,0xE0,0x5A,0xB2,0x4E,0xB2,0xEB,0x48,0x8B,0x23,0x65,0x70,0x22 } }; +static const Byte k_Guid_LZMA_COMPRESSED[kGuidSize] = + { 0x98,0x58,0x4E,0xEE,0x14,0x39,0x59,0x42,0x9D,0x6E,0xDC,0x7B,0xD7,0x94,0x03,0xCF }; static const char * const kGuidNames[] = { @@ -180,7 +220,12 @@ static int FindGuid(const Byte *p) static bool IsFfs(const Byte *p) { - return (Get32(p + 0x28) == kFvSignature && AreGuidsEq(p + kFfsGuidOffset, k_FFS_Guid)); + if (Get32(p + 0x28) != kFvSignature) + return false; + for (unsigned i = 0; i < ARRAY_SIZE(k_Guids_FS); i++) + if (AreGuidsEq(p + kFfsGuidOffset, k_Guids_FS[i])) + return true; + return false; } #define FVB_ERASE_POLARITY (1 << 11) @@ -329,39 +374,15 @@ static const char * const g_Methods[] = , "LZMA" }; -static AString UInt32ToString(UInt32 val) -{ - char sz[16]; - ConvertUInt32ToString(val, sz); - return sz; -} -static void ConvertByteToHex(unsigned value, char *s) +static void AddGuid(AString &dest, const Byte *p, bool full) { - for (int i = 0; i < 2; i++) - { - unsigned t = value & 0xF; - value >>= 4; - s[1 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); - } -} - -static AString GuidToString(const Byte *p, bool full) -{ - char s[16 * 2 + 8]; - int i; - for (i = 0; i < 4; i++) - ConvertByteToHex(p[3 - i], s + i * 2); - s[8] = 0; - - if (full) - { - s[8] = '-'; - for (i = 4; i < kGuidSize; i++) - ConvertByteToHex(p[i], s + 1 + i * 2); - s[32 + 1] = 0; - } - return s; + char s[64]; + ::RawLeGuidToString(p, s); + // MyStringUpper_Ascii(s); + if (!full) + s[8] = 0; + dest += s; } static const char * const kExpressionCommands[] = @@ -383,7 +404,7 @@ static bool ParseDepedencyExpression(const Byte *p, UInt32 size, AString &res) if (i + kGuidSize > size) return false; res.Add_Space(); - res += GuidToString(p + i, false); + AddGuid(res, p + i, false); i += kGuidSize; } res += "; "; @@ -433,6 +454,7 @@ static void AddSpaceAndString(AString &res, const AString &newString) class CFfsFileHeader { +PRF(public:) Byte CheckHeader; Byte CheckFile; Byte Attrib; @@ -530,7 +552,7 @@ public: if (align != 0) { s += " Align:"; - s += UInt32ToString((UInt32)1 << g_Allignment[align]); + s.Add_UInt32((UInt32)1 << g_Allignment[align]); } */ return s; @@ -538,6 +560,7 @@ public: }; #define G32(_offs_, dest) dest = Get32(p + (_offs_)); +#define G16(_offs_, dest) dest = Get16(p + (_offs_)); struct CCapsuleHeader { @@ -557,23 +580,51 @@ struct CCapsuleHeader void Clear() { memset(this, 0, sizeof(*this)); } - void Parse(const Byte *p) + bool Parse(const Byte *p) { + Clear(); G32(0x10, HeaderSize); G32(0x14, Flags); G32(0x18, CapsuleImageSize); - G32(0x1C, SequenceNumber); - G32(0x30, OffsetToSplitInformation); - G32(0x34, OffsetToCapsuleBody); - G32(0x38, OffsetToOemDefinedHeader); - G32(0x3C, OffsetToAuthorInformation); - G32(0x40, OffsetToRevisionInformation); - G32(0x44, OffsetToShortDescription); - G32(0x48, OffsetToLongDescription); - G32(0x4C, OffsetToApplicableDevices); + if (HeaderSize < 0x1C) + return false; + if (AreGuidsEq(p, k_Guids_Capsules[0])) + { + const unsigned kHeaderSize = 80; + if (HeaderSize != kHeaderSize) + return false; + G32(0x1C, SequenceNumber); + G32(0x30, OffsetToSplitInformation); + G32(0x34, OffsetToCapsuleBody); + G32(0x38, OffsetToOemDefinedHeader); + G32(0x3C, OffsetToAuthorInformation); + G32(0x40, OffsetToRevisionInformation); + G32(0x44, OffsetToShortDescription); + G32(0x48, OffsetToLongDescription); + G32(0x4C, OffsetToApplicableDevices); + return true; + } + else if (AreGuidsEq(p, k_Guids_Capsules[1])) + { + // capsule v2 + G16(0x1C, OffsetToCapsuleBody); + G16(0x1E, OffsetToOemDefinedHeader); + return true; + } + else if (AreGuidsEq(p, k_Guids_Capsules[2])) + { + OffsetToCapsuleBody = HeaderSize; + return true; + } + else + { + // here we must check for another capsule types + return false; + } } }; + struct CItem { AString Name; @@ -605,7 +656,10 @@ void CItem::SetGuid(const Byte *guidName, bool full) if (index >= 0) Name = kGuidNames[(unsigned)index]; else - Name = GuidToString(guidName, full); + { + Name.Empty(); + AddGuid(Name, guidName, full); + } } AString CItem::GetName(int numChildsInParent) const @@ -616,11 +670,14 @@ AString CItem::GetName(int numChildsInParent) const char sz2[32]; ConvertUInt32ToString(NameIndex, sz); ConvertUInt32ToString(numChildsInParent - 1, sz2); - unsigned numZeros = (unsigned)strlen(sz2) - (unsigned)strlen(sz); + int numZeros = (int)strlen(sz2) - (int)strlen(sz); AString res; - for (unsigned i = 0; i < numZeros; i++) + for (int i = 0; i < numZeros; i++) res += '0'; - return res + (AString)sz + '.' + Name; + res += sz; + res += '.'; + res += Name; + return res; } struct CItem2 @@ -644,21 +701,30 @@ class CHandler: UString _comment; UInt32 _methodsMask; bool _capsuleMode; + bool _headersError; size_t _totalBufsSize; CCapsuleHeader _h; UInt64 _phySize; - void AddCommentString(const wchar_t *name, UInt32 pos); + void AddCommentString(const char *name, UInt32 pos); int AddItem(const CItem &item); int AddFileItemWithIndex(CItem &item); int AddDirItem(CItem &item); unsigned AddBuf(size_t size); - HRESULT ParseSections(int bufIndex, UInt32 pos, UInt32 size, int parent, int method, unsigned level); + HRESULT DecodeLzma(const Byte *data, size_t inputSize); + + HRESULT ParseSections(int bufIndex, UInt32 pos, UInt32 size, int parent, int method, unsigned level, bool &error); + + HRESULT ParseIntelMe(int bufIndex, UInt32 posBase, + UInt32 exactSize, UInt32 limitSize, + int parent, int method, int level); + HRESULT ParseVolume(int bufIndex, UInt32 posBase, UInt32 exactSize, UInt32 limitSize, int parent, int method, int level); + HRESULT OpenCapsule(IInStream *stream); HRESULT OpenFv(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback); HRESULT Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback); @@ -674,6 +740,7 @@ static const Byte kProps[] = kpidPath, kpidIsDir, kpidSize, + // kpidOffset, kpidMethod, kpidCharacts }; @@ -698,7 +765,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { case kpidPath: { - AString path = item2.Name; + AString path (item2.Name); int cur = item2.Parent; while (cur >= 0) { @@ -714,13 +781,14 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidMethod: if (item.Method >= 0) prop = g_Methods[(unsigned)item.Method]; break; case kpidCharacts: if (!item2.Characts.IsEmpty()) prop = item2.Characts; break; case kpidSize: if (!item.IsDir) prop = (UInt64)item.Size; break; + // case kpidOffset: if (!item.IsDir) prop = item.Offset; break; } prop.Detach(value); return S_OK; COM_TRY_END } -void CHandler::AddCommentString(const wchar_t *name, UInt32 pos) +void CHandler::AddCommentString(const char *name, UInt32 pos) { UString s; const Byte *buf = _bufs[0]; @@ -747,7 +815,7 @@ void CHandler::AddCommentString(const wchar_t *name, UInt32 pos) return; _comment.Add_LF(); _comment += name; - _comment.AddAscii(": "); + _comment += ": "; _comment += s; } @@ -762,13 +830,22 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) AString s; for (unsigned i = 0; i < 32; i++) if ((_methodsMask & ((UInt32)1 << i)) != 0) - AddSpaceAndString(s, g_Methods[i]); + AddSpaceAndString(s, (AString)g_Methods[i]); if (!s.IsEmpty()) prop = s; break; } case kpidComment: if (!_comment.IsEmpty()) prop = _comment; break; case kpidPhySize: prop = (UInt64)_phySize; break; + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_headersError) v |= kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } } prop.Detach(value); return S_OK; @@ -785,7 +862,7 @@ static void PrintLevel(int level) static void MyPrint(UInt32 posBase, UInt32 size, int level, const char *name) { PrintLevel(level); - PRF(printf("%s, pos = %6x, size = %6d", name, posBase, size)); + PRF(printf("%s, pos = %6x, size = %6x", name, posBase, size)); } #else #define PrintLevel(level) @@ -829,8 +906,36 @@ unsigned CHandler::AddBuf(size_t size) return index; } -HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int parent, int method, unsigned level) + +HRESULT CHandler::DecodeLzma(const Byte *data, size_t inputSize) +{ + if (inputSize < 5 + 8) + return S_FALSE; + const UInt64 unpackSize = Get64(data + 5); + if (unpackSize > ((UInt32)1 << 30)) + return S_FALSE; + SizeT destLen = (SizeT)unpackSize; + const unsigned newBufIndex = AddBuf((size_t)unpackSize); + CByteBuffer &buf = _bufs[newBufIndex]; + ELzmaStatus status; + SizeT srcLen = inputSize - (5 + 8); + const SizeT srcLen2 = srcLen; + SRes res = LzmaDecode(buf, &destLen, data + 13, &srcLen, + data, 5, LZMA_FINISH_END, &status, &g_Alloc); + if (res != 0) + return S_FALSE; + if (srcLen != srcLen2 || destLen != unpackSize || ( + status != LZMA_STATUS_FINISHED_WITH_MARK && + status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) + return S_FALSE; + return S_OK; +} + + +HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int parent, int method, unsigned level, bool &error) { + error = false; + if (level > kLevelMax) return S_FALSE; MyPrint(posBase, size, level, "Sections"); @@ -842,7 +947,7 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p if (size == pos) return S_OK; PrintLevel(level); - PRF(printf("%s, pos = %6x", "Sect", pos)); + PRF(printf("%s, abs = %6x, relat = %6x", "Sect", posBase + pos, pos)); pos = (pos + 3) & ~(UInt32)3; if (pos > size) return S_FALSE; @@ -851,14 +956,23 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p return S_OK; if (rem < 4) return S_FALSE; + const Byte *p = bufData + posBase + pos; - UInt32 sectSize = Get24(p); - if (sectSize > rem || sectSize < 4) - return S_FALSE; - Byte type = p[3]; - PrintLevel(level); - PRF(printf("%s, type = %2x, pos = %6x, size = %6d", "Sect", type, pos, sectSize)); + const UInt32 sectSize = Get24(p); + const Byte type = p[3]; + + // PrintLevel(level); + PRF(printf(" type = %2x, sectSize = %6x", type, sectSize)); + + if (sectSize > rem || sectSize < 4) + { + _headersError = true; + error = true; + return S_OK; + // return S_FALSE; + } + CItem item; item.Method = method; item.BufIndex = bufIndex; @@ -891,7 +1005,8 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p // int parent = AddDirItem(item); if (compressionType == COMPRESSION_TYPE_NONE) { - RINOK(ParseSections(bufIndex, newOffset, newSectSize, parent, method, level)); + bool error2; + RINOK(ParseSections(bufIndex, newOffset, newSectSize, parent, method, level, error2)); } else if (compressionType == COMPRESSION_TYPE_LZH) { @@ -910,6 +1025,9 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p return S_FALSE; UInt32 packSize = Get32(src); UInt32 unpackSize = Get32(src + 4); + + PRF(printf(" LZH packSize = %6x, unpackSize = %6x", packSize, unpackSize)); + if (uncompressedSize != unpackSize || newSectSize - 8 != packSize) return S_FALSE; if (packSize < 1) @@ -921,30 +1039,34 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p CBufInStream *inStreamSpec = new CBufInStream; CMyComPtr<IInStream> inStream = inStreamSpec; - inStreamSpec->Init(src, packSize); CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; - outStreamSpec->Init(buf, uncompressedSize); UInt64 uncompressedSize64 = uncompressedSize; lzhDecoderSpec->FinishMode = true; /* - EFI 1.1 probably used small dictionary and (pbit = 4) in LZH. We don't support such archives. + EFI 1.1 probably used LZH with small dictionary and (pbit = 4). It was named "Efi compression". New version of compression code (named Tiano) uses LZH with (1 << 19) dictionary. But maybe LZH decoder in UEFI decoder supports larger than (1 << 19) dictionary. + We check both LZH versions: Tiano and then Efi. */ - lzhDecoderSpec->SetDictSize(1 << 19); - - HRESULT res = lzhDecoder->Code(inStream, outStream, NULL, &uncompressedSize64, NULL); - if (res != S_OK) - return res; - - if (lzhDecoderSpec->GetInputProcessedSize() != packSize) - return S_FALSE; + HRESULT res = S_FALSE; + + for (unsigned m = 0 ; m < 2; m++) + { + inStreamSpec->Init(src, packSize); + outStreamSpec->Init(buf, uncompressedSize); + lzhDecoderSpec->SetDictSize((m == 0) ? ((UInt32)1 << 19) : ((UInt32)1 << 14)); + res = lzhDecoder->Code(inStream, outStream, NULL, &uncompressedSize64, NULL); + if (res == S_OK) + break; + } + RINOK(res); } - RINOK(ParseSections(newBufIndex, 0, uncompressedSize, parent, compressionType, level)); + bool error2; + RINOK(ParseSections(newBufIndex, 0, uncompressedSize, parent, compressionType, level, error2)); } else { @@ -964,26 +1086,14 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p // firstSectType can be 0 in some archives } pStart += addSize; - UInt64 lzmaUncompressedSize = Get64(pStart + 5); - if (lzmaUncompressedSize > (1 << 30)) - return S_FALSE; + + RINOK(DecodeLzma(pStart, newSectSize - addSize)); + const size_t lzmaUncompressedSize = _bufs.Back().Size(); + // if (lzmaUncompressedSize != uncompressedSize) if (lzmaUncompressedSize < uncompressedSize) return S_FALSE; - SizeT destLen = (SizeT)lzmaUncompressedSize; - unsigned newBufIndex = AddBuf((size_t)lzmaUncompressedSize); - CByteBuffer &buf = _bufs[newBufIndex]; - ELzmaStatus status; - SizeT srcLen = newSectSize - (addSize + 5 + 8); - SizeT srcLen2 = srcLen; - SRes res = LzmaDecode(buf, &destLen, pStart + 13, &srcLen, - pStart, 5, LZMA_FINISH_END, &status, &g_Alloc); - if (res != 0) - return S_FALSE; - if (srcLen != srcLen2 || destLen != lzmaUncompressedSize || ( - status != LZMA_STATUS_FINISHED_WITH_MARK && - status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) - return S_FALSE; - RINOK(ParseSections(newBufIndex, 0, (UInt32)lzmaUncompressedSize, parent, compressionType, level)); + bool error2; + RINOK(ParseSections(_bufs.Size() - 1, 0, (UInt32)lzmaUncompressedSize, parent, compressionType, level, error2)); } _methodsMask |= (1 << compressionType); } @@ -1003,9 +1113,26 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p UInt32 newOffset = posBase + pos + dataOffset; item.Offset = newOffset; UInt32 propsSize = dataOffset - kHeaderSize; - bool needDir = true; AddSpaceAndString(item.Characts, FLAGS_TO_STRING(g_GUIDED_SECTION_ATTRIBUTES, attrib)); - if (AreGuidsEq(p + 0x4, kGuids[kGuidIndex_CRC]) && propsSize == 4) + + bool needDir = true; + unsigned newBufIndex = bufIndex; + int newMethod = method; + + if (AreGuidsEq(p + 0x4, k_Guid_LZMA_COMPRESSED)) + { + // item.Name = "guid.lzma"; + // AddItem(item); + const Byte *pStart = bufData + newOffset; + // do we need correct pStart here for lzma steram offset? + RINOK(DecodeLzma(pStart, newSectSize)); + _methodsMask |= (1 << COMPRESSION_TYPE_LZMA); + newBufIndex = _bufs.Size() - 1; + newOffset = 0; + newSectSize = (UInt32)_bufs.Back().Size(); + newMethod = COMPRESSION_TYPE_LZMA; + } + else if (AreGuidsEq(p + 0x4, kGuids[kGuidIndex_CRC]) && propsSize == 4) { needDir = false; item.KeepName = false; @@ -1023,10 +1150,12 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p AddItem(item2); } } + int newParent = parent; if (needDir) newParent = AddDirItem(item); - RINOK(ParseSections(bufIndex, newOffset, newSectSize, newParent, method, level)); + bool error2; + RINOK(ParseSections(newBufIndex, newOffset, newSectSize, newParent, newMethod, level, error2)); } else if (type == SECTION_FIRMWARE_VOLUME_IMAGE) { @@ -1100,8 +1229,8 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p AString s; if (ParseUtf16zString2(p + 6, sectDataSize - 2, s)) { - AString s2 = "ver:"; - s2 += UInt32ToString(Get16(p + 4)); + AString s2 ("ver:"); + s2.Add_UInt32(Get16(p + 4)); s2.Add_Space(); s2 += s; AddSpaceAndString(_items[item.Parent].Characts, s2); @@ -1135,6 +1264,7 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p if (needAdd) AddFileItemWithIndex(item); } + pos += sectSize; } } @@ -1174,6 +1304,7 @@ bool CVolFfsHeader::Parse(const Byte *p) return true; }; + HRESULT CHandler::ParseVolume( int bufIndex, UInt32 posBase, UInt32 exactSize, UInt32 limitSize, @@ -1181,14 +1312,13 @@ HRESULT CHandler::ParseVolume( { if (level > kLevelMax) return S_FALSE; - MyPrint(posBase, size, level, "Volume"); + MyPrint(posBase, exactSize, level, "Volume"); level++; if (exactSize < kFvHeaderSize) return S_FALSE; const Byte *p = _bufs[bufIndex] + posBase; // first 16 bytes must be zeros, but they are not zeros sometimes. - if (!AreGuidsEq(p + kFfsGuidOffset, k_FFS_Guid) && - !AreGuidsEq(p + kFfsGuidOffset, k_MacFS_Guid)) + if (!IsFfs(p)) { CItem item; item.Method = method; @@ -1196,8 +1326,10 @@ HRESULT CHandler::ParseVolume( item.Parent = parent; item.Offset = posBase; item.Size = exactSize; - item.SetGuid(p + kFfsGuidOffset); - item.Name += " [VOLUME]"; + if (!Is_FF_Stream(p + kFfsGuidOffset, 16)) + item.SetGuid(p + kFfsGuidOffset); + // if (item.Name.IsEmpty()) + item.Name += "[VOL]"; AddItem(item); return S_OK; } @@ -1268,9 +1400,13 @@ HRESULT CHandler::ParseVolume( item.Size = rem - num_FF_bytes; AddItem(item); } + PrintLevel(level); PRF(printf("== FF FF reminder")); + break; } - PrintLevel(level); PRF(printf("%s, pos = %6x, size = %6d", "FILE", posBase + pos, fh.Size)); + + PrintLevel(level); PRF(printf("%s, type = %3d, pos = %7x, size = %7x", "FILE", fh.Type, posBase + pos, fh.Size)); + if (!fh.Check(pFile, rem)) return S_FALSE; @@ -1295,9 +1431,16 @@ HRESULT CHandler::ParseVolume( item.SetGuid(fh.GuidName, full); item.Characts = fh.GetCharacts(); - PrintLevel(level); - PRF(printf("%s", item.Characts)); - + // PrintLevel(level); + PRF(printf(" : %s", item.Characts)); + + { + PRF(printf(" attrib = %2d State = %3d ", (unsigned)fh.Attrib, (unsigned)fh.State)); + PRF(char s[64]); + PRF(RawLeGuidToString(fh.GuidName, s)); + PRF(printf(" : %s ", s)); + } + if (fh.Type == FV_FILETYPE_FFS_PAD || fh.Type == FV_FILETYPE_RAW) { @@ -1321,23 +1464,127 @@ HRESULT CHandler::ParseVolume( } else { - int newParent = AddDirItem(item); - RINOK(ParseSections(bufIndex, offset, sectSize, newParent, method, level)); + /* + if (fh.Type == FV_FILETYPE_FREEFORM) + { + // in intel bio example: one FV_FILETYPE_FREEFORM file is wav file (not sections) + // AddItem(item); + } + else + */ + { + int newParent = AddDirItem(item); + bool error2; + RINOK(ParseSections(bufIndex, offset, sectSize, newParent, method, level + 1, error2)); + if (error2) + { + // in intel bio example: one FV_FILETYPE_FREEFORM file is wav file (not sections) + item.IsDir = false; + item.Size = sectSize; + item.Name.Insert(0, "[ERROR]"); + AddItem(item); + } + } } } + + return S_OK; +} + + +static const char * const kRegionName[] = +{ + "Descriptor" + , "BIOS" + , "ME" + , "GbE" + , "PDR" + , "Region5" + , "Region6" + , "Region7" +}; + + +HRESULT CHandler::ParseIntelMe( + int bufIndex, UInt32 posBase, + UInt32 exactSize, UInt32 limitSize, + int parent, int method, int level) +{ + UNUSED_VAR(limitSize) + level++; + const Byte *p = _bufs[bufIndex] + posBase; + if (exactSize < 16 + 16) + return S_FALSE; + if (!IsIntelMe(p)) + return S_FALSE; + + UInt32 v0 = GetUi32(p + 20); + // UInt32 numRegions = (v0 >> 24) & 0x7; + UInt32 regAddr = (v0 >> 12) & 0xFF0; + // UInt32 numComps = (v0 >> 8) & 0x3; + // UInt32 fcba = (v0 << 4) & 0xFF0; + + // (numRegions == 0) in header in some new images. + // So we don't use the value from header + UInt32 numRegions = 7; + + for (unsigned i = 0; i <= numRegions; i++) + { + UInt32 offset = regAddr + i * 4; + if (offset + 4 > exactSize) + break; + UInt32 val = GetUi32(p + offset); + + // only 12 bits probably are OK. + // How does it work for files larger than 16 MB? + const UInt32 kMask = 0xFFF; + // const UInt32 kMask = 0xFFFF; // 16-bit is more logical + const UInt32 lim = (val >> 16) & kMask; + const UInt32 base = (val & kMask); + + /* + strange combinations: + PDR: base = 0x1FFF lim = 0; + empty: base = 0xFFFF lim = 0xFFFF; + + PDR: base = 0x7FFF lim = 0; + empty: base = 0x7FFF lim = 0; + */ + if (base == kMask && lim == 0) + continue; // unused + + if (lim < base) + continue; // unused + + CItem item; + item.Name = kRegionName[i]; + item.Method = method; + item.BufIndex = bufIndex; + item.Parent = parent; + item.Offset = posBase + (base << 12); + if (item.Offset > exactSize) + continue; + item.Size = (lim + 1 - base) << 12; + // item.SetGuid(p + kFfsGuidOffset); + // item.Name += " [VOLUME]"; + AddItem(item); + } return S_OK; } + HRESULT CHandler::OpenCapsule(IInStream *stream) { const unsigned kHeaderSize = 80; Byte buf[kHeaderSize]; RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)); - _h.Parse(buf); - if (_h.HeaderSize != kHeaderSize || - _h.CapsuleImageSize < kHeaderSize || - _h.OffsetToCapsuleBody < kHeaderSize || - _h.OffsetToCapsuleBody > _h.CapsuleImageSize) + if (!_h.Parse(buf)) + return S_FALSE; + if (_h.CapsuleImageSize < kHeaderSize + || _h.CapsuleImageSize < _h.HeaderSize + || _h.OffsetToCapsuleBody < _h.HeaderSize + || _h.OffsetToCapsuleBody > _h.CapsuleImageSize + ) return S_FALSE; _phySize = _h.CapsuleImageSize; @@ -1350,17 +1597,21 @@ HRESULT CHandler::OpenCapsule(IInStream *stream) memcpy(buf0, buf, kHeaderSize); ReadStream_FALSE(stream, buf0 + kHeaderSize, _h.CapsuleImageSize - kHeaderSize); - AddCommentString(L"Author", _h.OffsetToAuthorInformation); - AddCommentString(L"Revision", _h.OffsetToRevisionInformation); - AddCommentString(L"Short Description", _h.OffsetToShortDescription); - AddCommentString(L"Long Description", _h.OffsetToLongDescription); + AddCommentString("Author", _h.OffsetToAuthorInformation); + AddCommentString("Revision", _h.OffsetToRevisionInformation); + AddCommentString("Short Description", _h.OffsetToShortDescription); + AddCommentString("Long Description", _h.OffsetToLongDescription); + + + const UInt32 size = _h.CapsuleImageSize - _h.OffsetToCapsuleBody; - return ParseVolume(bufIndex, _h.OffsetToCapsuleBody, - _h.CapsuleImageSize - _h.OffsetToCapsuleBody, - _h.CapsuleImageSize - _h.OffsetToCapsuleBody, - -1, -1, 0); + if (size >= 32 && IsIntelMe(buf0 + _h.OffsetToCapsuleBody)) + return ParseIntelMe(bufIndex, _h.OffsetToCapsuleBody, size, size, -1, -1, 0); + + return ParseVolume(bufIndex, _h.OffsetToCapsuleBody, size, size, -1, -1, 0); } + HRESULT CHandler::OpenFv(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback * /* callback */) { Byte buf[kFvHeaderSize]; @@ -1380,6 +1631,7 @@ HRESULT CHandler::OpenFv(IInStream *stream, const UInt64 * /* maxCheckStartPosit return ParseVolume(bufIndex, 0, fvSize32, fvSize32, -1, -1, 0); } + HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) { if (_capsuleMode) @@ -1432,8 +1684,8 @@ HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, int parent = item.Parent; if (parent >= 0) numItems = numChilds[(unsigned)parent]; - AString name2 = item.GetName(numItems); - AString characts2 = item.Characts; + AString name2 (item.GetName(numItems)); + AString characts2 (item.Characts); if (item.KeepName) name = name2; @@ -1444,7 +1696,7 @@ HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, break; if (item3.KeepName) { - AString name3 = item3.GetName(-1); + AString name3 (item3.GetName(-1)); if (name.IsEmpty()) name = name3; else @@ -1500,6 +1752,7 @@ STDMETHODIMP CHandler::Close() _items2.Clear(); _bufs.Clear(); _comment.Empty(); + _headersError = false; _h.Clear(); return S_OK; } @@ -1580,11 +1833,12 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) CBufInStream *streamSpec = new CBufInStream; CMyComPtr<IInStream> streamTemp = streamSpec; const CByteBuffer &buf = _bufs[item.BufIndex]; - /* - if (item.Offset + item.Size > buf.GetCapacity()) + if (item.Offset > buf.Size()) return S_FALSE; - */ - streamSpec->Init(buf + item.Offset, item.Size, (IInArchive *)this); + size_t size = buf.Size() - item.Offset; + if (size > item.Size) + size = item.Size; + streamSpec->Init(buf + item.Offset, size, (IInArchive *)this); *stream = streamTemp.Detach(); return S_OK; COM_TRY_END @@ -1593,11 +1847,19 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) namespace UEFIc { +static const Byte k_Capsule_Signatures[] = +{ + 16, CAPSULE_SIGNATURE, + 16, CAPSULE2_SIGNATURE, + 16, CAPSULE_UEFI_SIGNATURE +}; + REGISTER_ARC_I_CLS( CHandler(true), "UEFIc", "scap", 0, 0xD0, - kCapsuleSig, + k_Capsule_Signatures, 0, + NArcInfoFlags::kMultiSignature | NArcInfoFlags::kFindSignature, NULL) @@ -1605,11 +1867,19 @@ REGISTER_ARC_I_CLS( namespace UEFIf { +static const Byte k_FFS_Signatures[] = +{ + 16, FFS1_SIGNATURE, + 16, FFS2_SIGNATURE +}; + + REGISTER_ARC_I_CLS( CHandler(false), "UEFIf", "uefif", 0, 0xD1, - k_FFS_Guid, + k_FFS_Signatures, kFfsGuidOffset, + NArcInfoFlags::kMultiSignature | NArcInfoFlags::kFindSignature, NULL) diff --git a/CPP/7zip/Archive/VdiHandler.cpp b/CPP/7zip/Archive/VdiHandler.cpp index a8d3fe36..b8ef35bb 100644 --- a/CPP/7zip/Archive/VdiHandler.cpp +++ b/CPP/7zip/Archive/VdiHandler.cpp @@ -11,12 +11,14 @@ #include "../../Common/MyBuffer.h" #include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" #include "HandlerCont.h" +#define Get16(p) GetUi16(p) #define Get32(p) GetUi32(p) #define Get64(p) GetUi64(p) @@ -33,6 +35,7 @@ static const unsigned k_ClusterBits = 20; static const UInt32 k_ClusterSize = (UInt32)1 << k_ClusterBits; static const UInt32 k_UnusedCluster = 0xFFFFFFFF; + // static const UInt32 kDiskType_Dynamic = 1; // static const UInt32 kDiskType_Static = 2; @@ -41,8 +44,38 @@ static const char * const kDiskTypes[] = "0" , "Dynamic" , "Static" + , "Undo" + , "Diff" +}; + + +enum EGuidType +{ + k_GuidType_Creat, + k_GuidType_Modif, + k_GuidType_Link, + k_GuidType_PModif }; +static const unsigned kNumGuids = 4; +static const char * const kGuidNames[kNumGuids] = +{ + "Creat " + , "Modif " + , "Link " + , "PModif" +}; + +static bool IsEmptyGuid(const Byte *data) +{ + for (unsigned i = 0; i < 16; i++) + if (data[i] != 0) + return false; + return true; +} + + + class CHandler: public CHandlerImg { UInt32 _dataOffset; @@ -52,6 +85,8 @@ class CHandler: public CHandlerImg bool _isArc; bool _unsupported; + Byte Guids[kNumGuids][16]; + HRESULT Seek(UInt64 offset) { _posInArc = offset; @@ -137,7 +172,9 @@ static const Byte kProps[] = static const Byte kArcProps[] = { kpidHeadersSize, - kpidMethod + kpidMethod, + kpidComment, + kpidName }; IMP_IInArchive_Props @@ -156,16 +193,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidMethod: { - char s[16]; - const char *ptr; - if (_imageType < ARRAY_SIZE(kDiskTypes)) - ptr = kDiskTypes[_imageType]; - else - { - ConvertUInt32ToString(_imageType, s); - ptr = s; - } - prop = ptr; + TYPE_TO_PROP(kDiskTypes, _imageType, prop); break; } @@ -181,6 +209,42 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) prop = v; break; } + + case kpidComment: + { + AString s; + for (unsigned i = 0; i < kNumGuids; i++) + { + const Byte *guid = Guids[i]; + if (!IsEmptyGuid(guid)) + { + s.Add_LF(); + s += kGuidNames[i]; + s += " : "; + char temp[64]; + RawLeGuidToString_Braced(guid, temp); + MyStringLower_Ascii(temp); + s += temp; + } + } + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidName: + { + const Byte *guid = Guids[k_GuidType_Creat]; + if (!IsEmptyGuid(guid)) + { + char temp[64]; + RawLeGuidToString_Braced(guid, temp); + MyStringLower_Ascii(temp); + strcat(temp, ".vdi"); + prop = temp; + } + break; + } } prop.Detach(value); @@ -207,15 +271,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN } -static bool IsEmptyGuid(const Byte *data) -{ - for (unsigned i = 0; i < 16; i++) - if (data[i] != 0) - return false; - return true; -} - - HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback * /* openCallback */) { const unsigned kHeaderSize = 512; @@ -225,45 +280,65 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback * /* openCallbac if (memcmp(buf + 0x40, k_Signature, sizeof(k_Signature)) != 0) return S_FALSE; - UInt32 version = Get32(buf + 0x44); + const UInt32 version = Get32(buf + 0x44); if (version >= 0x20000) return S_FALSE; + if (version < 0x10000) + { + _unsupported = true; + return S_FALSE; + } - UInt32 headerSize = Get32(buf + 0x48); - if (headerSize < 0x140 || headerSize > 0x1B8) + const unsigned kHeaderOffset = 0x48; + const unsigned kGuidsOffsets = 0x188; + const UInt32 headerSize = Get32(buf + kHeaderOffset); + if (headerSize < kGuidsOffsets - kHeaderOffset || headerSize > 0x200 - kHeaderOffset) return S_FALSE; _imageType = Get32(buf + 0x4C); - _dataOffset = Get32(buf + 0x158); + // Int32 flags = Get32(buf + 0x50); + // Byte Comment[0x100] - UInt32 tableOffset = Get32(buf + 0x154); + const UInt32 tableOffset = Get32(buf + 0x154); if (tableOffset < 0x200) return S_FALSE; + + _dataOffset = Get32(buf + 0x158); + + // UInt32 geometry[3]; - UInt32 sectorSize = Get32(buf + 0x168); + const UInt32 sectorSize = Get32(buf + 0x168); if (sectorSize != 0x200) return S_FALSE; _size = Get64(buf + 0x170); + const UInt32 blockSize = Get32(buf + 0x178); + const UInt32 totalBlocks = Get32(buf + 0x180); + const UInt32 numAllocatedBlocks = Get32(buf + 0x184); + _isArc = true; - if (_imageType > 2) - { - _unsupported = true; - return S_FALSE; - } - if (_dataOffset < tableOffset) return S_FALSE; - UInt32 blockSize = Get32(buf + 0x178); - if (blockSize != ((UInt32)1 << k_ClusterBits)) + if (_imageType > 4) + _unsupported = true; + + if (blockSize != k_ClusterSize) { _unsupported = true; return S_FALSE; } - UInt32 totalBlocks = Get32(buf + 0x180); + if (headerSize >= kGuidsOffsets + kNumGuids * 16 - kHeaderOffset) + { + for (unsigned i = 0; i < kNumGuids; i++) + memcpy(Guids[i], buf + kGuidsOffsets + 16 * i, 16); + + if (!IsEmptyGuid(Guids[k_GuidType_Link]) || + !IsEmptyGuid(Guids[k_GuidType_PModif])) + _unsupported = true; + } { UInt64 size2 = (UInt64)totalBlocks << k_ClusterBits; @@ -278,18 +353,6 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback * /* openCallbac */ } - if (headerSize >= 0x180) - { - if (!IsEmptyGuid(buf + 0x1A8) || - !IsEmptyGuid(buf + 0x1B8)) - { - _unsupported = true; - return S_FALSE; - } - } - - UInt32 numAllocatedBlocks = Get32(buf + 0x184); - { UInt32 tableReserved = _dataOffset - tableOffset; if ((tableReserved >> 2) < totalBlocks) @@ -298,11 +361,11 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback * /* openCallbac _phySize = _dataOffset + ((UInt64)numAllocatedBlocks << k_ClusterBits); - size_t numBytes = (size_t)totalBlocks * 4; + const size_t numBytes = (size_t)totalBlocks * 4; if ((numBytes >> 2) != totalBlocks) { _unsupported = true; - return S_FALSE; + return E_OUTOFMEMORY; } _table.Alloc(numBytes); @@ -316,7 +379,10 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback * /* openCallbac if (v == k_UnusedCluster) continue; if (v >= numAllocatedBlocks) + { + _unsupported = true; return S_FALSE; + } } Stream = stream; @@ -332,6 +398,9 @@ STDMETHODIMP CHandler::Close() _isArc = false; _unsupported = false; + for (unsigned i = 0; i < kNumGuids; i++) + memset(Guids[i], 0, 16); + _imgExt = NULL; Stream.Release(); return S_OK; diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp index 12cbfa04..d79ae907 100644 --- a/CPP/7zip/Archive/VhdHandler.cpp +++ b/CPP/7zip/Archive/VhdHandler.cpp @@ -5,7 +5,6 @@ #include "../../../C/CpuArch.h" #include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" #include "../../Windows/PropVariant.h" @@ -69,17 +68,16 @@ struct CFooter UInt32 NumCyls() const { return DiskGeometry >> 16; } UInt32 NumHeads() const { return (DiskGeometry >> 8) & 0xFF; } UInt32 NumSectorsPerTrack() const { return DiskGeometry & 0xFF; } - AString GetTypeString() const; + void AddTypeString(AString &s) const; bool Parse(const Byte *p); }; -AString CFooter::GetTypeString() const +void CFooter::AddTypeString(AString &s) const { if (Type < ARRAY_SIZE(kDiskTypes)) - return kDiskTypes[Type]; - char s[16]; - ConvertUInt32ToString(Type, s); - return s; + s += kDiskTypes[Type]; + else + s.Add_UInt32(Type); } static bool CheckBlock(const Byte *p, unsigned size, unsigned checkSumOffset, unsigned zeroOffset) @@ -234,12 +232,15 @@ class CHandler: public CHandlerImg UString _errorMessage; // bool _unexpectedEnd; - void AddErrorMessage(const wchar_t *s) + void AddErrorMessage(const char *message, const wchar_t *name = NULL) { if (!_errorMessage.IsEmpty()) _errorMessage.Add_LF(); - _errorMessage += s; + _errorMessage += message; + if (name) + _errorMessage += name; } + void UpdatePhySize(UInt64 value) { if (_phySize < value) @@ -262,7 +263,7 @@ class CHandler: public CHandlerImg while (p && p->NeedParent()) { if (!res.IsEmpty()) - res.AddAscii(" -> "); + res += " -> "; UString mainName; UString anotherName; if (Dyn.RelativeNameWasUsed) @@ -279,9 +280,9 @@ class CHandler: public CHandlerImg if (mainName != anotherName && !anotherName.IsEmpty()) { res.Add_Space(); - res += L'('; + res += '('; res += anotherName; - res += L')'; + res += ')'; } p = p->Parent; } @@ -522,7 +523,7 @@ HRESULT CHandler::Open3() } _posInArcLimit = _phySize; _phySize += kHeaderSize; - AddErrorMessage(L"Can't find footer"); + AddErrorMessage("Can't find footer"); return S_OK; } @@ -679,7 +680,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidShortComment: case kpidMethod: { - AString s = Footer.GetTypeString(); + AString s; + Footer.AddTypeString(s); if (NeedParent()) { s += " -> "; @@ -689,7 +691,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) if (!p) s += '?'; else - s += p->Footer.GetTypeString(); + p->Footer.AddTypeString(s); } prop = s; break; @@ -698,14 +700,12 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { char s[16]; StringToAString(s, Footer.CreatorApp); - AString res = s; + AString res (s); res.Trim(); - ConvertUInt32ToString(Footer.CreatorVersion >> 16, s); res.Add_Space(); - res += s; + res.Add_UInt32(Footer.CreatorVersion >> 16); res += '.'; - ConvertUInt32ToString(Footer.CreatorVersion & 0xFFFF, s); - res += s; + res.Add_UInt32(Footer.CreatorVersion & 0xFFFF); prop = res; break; } @@ -806,10 +806,7 @@ HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback if (res == S_FALSE || !nextStream) { - UString s; - s.SetFromAscii("Missing volume : "); - s += name; - AddErrorMessage(s); + AddErrorMessage("Missing volume : ", name); return S_OK; } @@ -837,8 +834,7 @@ HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback p = p->Parent; if (!p) { - AddErrorMessage(L"Can't open parent VHD file:"); - AddErrorMessage(Dyn.ParentName); + AddErrorMessage("Can't open parent VHD file : ", Dyn.ParentName); break; } } diff --git a/CPP/7zip/Archive/VmdkHandler.cpp b/CPP/7zip/Archive/VmdkHandler.cpp index 5f93c738..942bd792 100644 --- a/CPP/7zip/Archive/VmdkHandler.cpp +++ b/CPP/7zip/Archive/VmdkHandler.cpp @@ -296,10 +296,15 @@ bool CDescriptor::Parse(const Byte *p, size_t size) AString name; AString val; - for (size_t i = 0;; i++) + for (;;) { - const char c = p[i]; - if (i == size || c == 0 || c == 0xA || c == 0xD) + char c = 0; + if (size != 0) + { + size--; + c = *p++; + } + if (c == 0 || c == 0xA || c == 0xD) { if (!s.IsEmpty() && s[0] != '#') { @@ -322,14 +327,12 @@ bool CDescriptor::Parse(const Byte *p, size_t size) } s.Empty(); - if (c == 0 || i >= size) - break; + if (c == 0) + return true; } else s += (char)c; } - - return true; } @@ -819,9 +822,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) else if (algo != (int)h.algo) { s.Add_Space_if_NotEmpty(); - char temp[16]; - ConvertUInt32ToString(h.algo, temp); - s += temp; + s.Add_UInt32(h.algo); algo = h.algo; } } @@ -831,16 +832,10 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } if (zlib) - { - s.Add_Space_if_NotEmpty(); - s += "zlib"; - } + s.Add_OptSpaced("zlib"); if (marker) - { - s.Add_Space_if_NotEmpty(); - s += "Marker"; - } + s.Add_OptSpaced("Marker"); if (!s.IsEmpty()) prop = s; @@ -888,8 +883,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { if (_missingVol || !_missingVolName.IsEmpty()) { - UString s; - s.SetFromAscii("Missing volume : "); + UString s ("Missing volume : "); if (!_missingVolName.IsEmpty()) s += _missingVolName; prop = s; @@ -983,6 +977,9 @@ void CHandler::CloseAtError() } +static const char * const kSignature_Descriptor = "# Disk DescriptorFile"; + + HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) { const unsigned kSectoreSize = 512; @@ -997,7 +994,6 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0) { - const char *kSignature_Descriptor = "# Disk DescriptorFile"; const size_t k_SigDesc_Size = strlen(kSignature_Descriptor); if (headerSize < k_SigDesc_Size) return S_FALSE; diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp index 234780dd..927a0b38 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.cpp +++ b/CPP/7zip/Archive/Wim/WimHandler.cpp @@ -94,15 +94,6 @@ static void AddErrorMessage(AString &s, const char *message) s += message; } -static void ConvertByteToHex(unsigned value, char *s) -{ - for (int i = 0; i < 2; i++) - { - unsigned t = value & 0xF; - value >>= 4; - s[1 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); - } -} STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { @@ -177,17 +168,14 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) UInt32 ver2 = (_version >> 8) & 0xFF; UInt32 ver3 = (_version) & 0xFF; - char s[16]; - ConvertUInt32ToString(ver1, s); - AString res = s; + AString res; + res.Add_UInt32(ver1); res += '.'; - ConvertUInt32ToString(ver2, s); - res += s; + res.Add_UInt32(ver2); if (ver3 != 0) { res += '.'; - ConvertUInt32ToString(ver3, s); - res += s; + res.Add_UInt32(ver3); } prop = res; break; @@ -229,22 +217,16 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) const CHeader &h = _volumes[_firstVolumeIndex].Header; if (GetUi32(h.Guid) != 0) { - char temp[16 * 2 + 4]; - int i; - for (i = 0; i < 4; i++) - ConvertByteToHex(h.Guid[i], temp + i * 2); - temp[i * 2] = 0; - AString s = temp; + char temp[64]; + RawLeGuidToString(h.Guid, temp); + temp[8] = 0; // for reduced GUID + AString s (temp); const char *ext = ".wim"; if (h.NumParts != 1) { s += '_'; if (h.PartNumber != 1) - { - char sz[16]; - ConvertUInt32ToString(h.PartNumber, sz); - s += sz; - } + s.Add_UInt32(h.PartNumber); ext = ".swm"; } s += ext; @@ -262,9 +244,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) AString s; if (h.PartNumber != 1) { - char sz[16]; - ConvertUInt32ToString(h.PartNumber, sz); - s = sz; + s.Add_UInt32(h.PartNumber); s += '.'; } s += "swm"; @@ -312,19 +292,15 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) if (methodUnknown != 0) { - char temp[32]; - ConvertUInt32ToString(methodUnknown, temp); res.Add_Space_if_NotEmpty(); - res += temp; + res.Add_UInt32(methodUnknown); numMethods++; } if (numMethods == 1 && chunkSizeBits != 0) { - char temp[32]; - temp[0] = ':'; - ConvertUInt32ToString((UInt32)chunkSizeBits, temp + 1); - res += temp; + res += ':'; + res.Add_UInt32((UInt32)chunkSizeBits); } prop = res; @@ -391,7 +367,7 @@ static void MethodToProp(int method, int chunksSizeBits, NCOM::CPropVariant &pro if ((unsigned)method < ARRAY_SIZE(k_Methods)) strcpy(temp, k_Methods[(unsigned)method]); else - ConvertUInt32ToString((unsigned)method, temp); + ConvertUInt32ToString((UInt32)(unsigned)method, temp); if (chunksSizeBits >= 0) { @@ -436,9 +412,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val _db.GetItemPath(realIndex, _showImageNumber, prop); else { - char sz[16]; - ConvertUInt32ToString(item.StreamIndex, sz); - AString s = sz; /* while (s.Len() < _nameLenForStreams) s = '0' + s; @@ -448,7 +421,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val s = (AString)("[Free]" STRING_PATH_SEPARATOR) + sz; else */ - s = (AString)(FILES_DIR_NAME STRING_PATH_SEPARATOR) + sz; + AString s (FILES_DIR_NAME STRING_PATH_SEPARATOR); + s.Add_UInt32(item.StreamIndex); prop = s; } break; @@ -874,9 +848,10 @@ public: UString GetNextName(UInt32 index) const { - wchar_t s[16]; - ConvertUInt32ToString(index, s); - return _before + (UString)s + _after; + UString s = _before; + s.Add_UInt32(index); + s += _after; + return s; } }; @@ -970,11 +945,9 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal if (_xmls.IsEmpty() || xml.Data != _xmls[0].Data) { - char sz[16]; - ConvertUInt32ToString(xml.VolIndex, sz); - xml.FileName = L'['; - xml.FileName.AddAscii(sz); - xml.FileName.AddAscii("].xml"); + xml.FileName = '['; + xml.FileName.Add_UInt32(xml.VolIndex); + xml.FileName += "].xml"; _xmls.Add(xml); } diff --git a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp index 1d198df0..99fd46ef 100644 --- a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp +++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp @@ -1828,7 +1828,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu curPos += kStreamInfoSize; } - AString xml = "<WIM>"; + AString xml ("<WIM>"); AddTagUInt64_ToString(xml, "TOTALBYTES", curPos); for (i = 0; i < trees.Size(); i++) { diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp index f35c2d50..b934478e 100644 --- a/CPP/7zip/Archive/Wim/WimIn.cpp +++ b/CPP/7zip/Archive/Wim/WimIn.cpp @@ -442,7 +442,7 @@ static inline void ParseStream(bool oldVersion, const Byte *p, CStreamInfo &s) } -static const char *kLongPath = "[LongPath]"; +#define kLongPath "[LongPath]" void CDatabase::GetShortName(unsigned index, NWindows::NCOM::CPropVariant &name) const { diff --git a/CPP/7zip/Archive/Wim/WimRegister.cpp b/CPP/7zip/Archive/Wim/WimRegister.cpp index 6ad28acc..ecebe8d9 100644 --- a/CPP/7zip/Archive/Wim/WimRegister.cpp +++ b/CPP/7zip/Archive/Wim/WimRegister.cpp @@ -10,7 +10,7 @@ namespace NArchive { namespace NWim { REGISTER_ARC_IO( - "wim", "wim swm esd", 0, 0xE6, + "wim", "wim swm esd ppkg", 0, 0xE6, kSignature, 0, NArcInfoFlags::kAltStreams | diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp index 96386809..f20b1eb9 100644 --- a/CPP/7zip/Archive/XarHandler.cpp +++ b/CPP/7zip/Archive/XarHandler.cpp @@ -153,7 +153,7 @@ IMP_IInArchive_ArcProps static bool ParseUInt64(const CXmlItem &item, const char *name, UInt64 &res) { - const AString s = item.GetSubStringForTag(name); + const AString s (item.GetSubStringForTag(name)); if (s.IsEmpty()) return false; const char *end; @@ -163,7 +163,7 @@ static bool ParseUInt64(const CXmlItem &item, const char *name, UInt64 &res) static UInt64 ParseTime(const CXmlItem &item, const char *name) { - const AString s = item.GetSubStringForTag(name); + const AString s (item.GetSubStringForTag(name)); if (s.Len() < 20) return 0; const char *p = s; @@ -198,10 +198,10 @@ static bool ParseSha1(const CXmlItem &item, const char *name, Byte *digest) if (index < 0) return false; const CXmlItem &checkItem = item.SubItems[index]; - const AString style = checkItem.GetPropVal("style"); + const AString style (checkItem.GetPropVal("style")); if (style == "SHA1") { - const AString s = checkItem.GetSubString(); + const AString s (checkItem.GetSubString()); if (s.Len() != SHA1_DIGEST_SIZE * 2) return false; for (unsigned i = 0; i < s.Len(); i += 2) @@ -227,7 +227,7 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren file.Parent = parent; parent = files.Size(); file.Name = item.GetSubStringForTag("name"); - AString type = item.GetSubStringForTag("type"); + const AString type (item.GetSubStringForTag("type")); if (type == "directory") file.IsDir = true; else if (type == "file") @@ -254,14 +254,14 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren const CXmlItem &encodingItem = dataItem.SubItems[encodingIndex]; if (encodingItem.IsTag) { - AString s = encodingItem.GetPropVal("style"); + AString s (encodingItem.GetPropVal("style")); if (!s.IsEmpty()) { - const AString appl = "application/"; + const AString appl ("application/"); if (s.IsPrefixedBy(appl)) { s.DeleteFrontal(appl.Len()); - const AString xx = "x-"; + const AString xx ("x-"); if (s.IsPrefixedBy(xx)) { s.DeleteFrontal(xx.Len()); @@ -280,7 +280,7 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren file.ATime = ParseTime(item, "atime"); { - const AString s = item.GetSubStringForTag("mode"); + const AString s (item.GetSubStringForTag("mode")); if (s[0] == '0') { const char *end; diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp index 318be190..fd90c88d 100644 --- a/CPP/7zip/Archive/XzHandler.cpp +++ b/CPP/7zip/Archive/XzHandler.cpp @@ -3,8 +3,6 @@ #include "StdAfx.h" #include "../../../C/Alloc.h" -#include "../../../C/XzCrc64.h" -#include "../../../C/XzEnc.h" #include "../../Common/ComTry.h" #include "../../Common/Defs.h" @@ -12,14 +10,14 @@ #include "../../Windows/PropVariant.h" -#include "../ICoder.h" - #include "../Common/CWrappers.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" #include "../Compress/CopyCoder.h" +#include "../Compress/XzDecoder.h" +#include "../Compress/XzEncoder.h" #include "IArchive.h" @@ -27,46 +25,13 @@ #include "Common/HandlerOut.h" #endif -#include "XzHandler.h" - using namespace NWindows; -namespace NCompress { -namespace NLzma2 { - -HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props); - -}} - namespace NArchive { namespace NXz { -struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit; - -static const char *k_LZMA2_Name = "LZMA2"; +#define k_LZMA2_Name "LZMA2" -void CStatInfo::Clear() -{ - InSize = 0; - OutSize = 0; - PhySize = 0; - - NumStreams = 0; - NumBlocks = 0; - - UnpackSize_Defined = false; - - NumStreams_Defined = false; - NumBlocks_Defined = false; - - IsArc = false; - UnexpectedEnd = false; - DataAfterEnd = false; - Unsupported = false; - HeadersError = false; - DataError = false; - CrcError = false; -} class CHandler: public IInArchive, @@ -78,7 +43,7 @@ class CHandler: #endif public CMyUnknownImp { - CStatInfo _stat; + NCompress::NXz::CStatInfo _stat; bool _isArc; bool _needSeekToStart; @@ -104,9 +69,12 @@ class CHandler: HRESULT Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback); HRESULT Decode2(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, - CDecoder &decoder, ICompressProgressInfo *progress) + NCompress::NXz::CDecoder &decoder, ICompressProgressInfo *progress) { - RINOK(decoder.Decode(seqInStream, outStream, progress)); + RINOK(decoder.Decode(seqInStream, outStream, + NULL, // *outSizeLimit + true, // finishStream + progress)); _stat = decoder; _phySize_Defined = true; return S_OK; @@ -169,13 +137,6 @@ static inline void AddHexToString(AString &s, Byte value) s += GetHex(value & 0xF); } -static void AddUInt32ToString(AString &s, UInt32 value) -{ - char temp[16]; - ConvertUInt32ToString(value, temp); - s += temp; -} - static void Lzma2PropToString(AString &s, unsigned prop) { char c = 0; @@ -192,7 +153,7 @@ static void Lzma2PropToString(AString &s, unsigned prop) c = 'm'; } } - AddUInt32ToString(s, size); + s.Add_UInt32(size); if (c != 0) s += c; } @@ -232,7 +193,7 @@ static AString GetMethodString(const CXzFilter &f) p = temp; } - AString s = p; + AString s (p); if (f.propsSize > 0) { @@ -240,7 +201,7 @@ static AString GetMethodString(const CXzFilter &f) if (f.id == XZ_ID_LZMA2 && f.propsSize == 1) Lzma2PropToString(s, f.props[0]); else if (f.id == XZ_ID_Delta && f.propsSize == 1) - AddUInt32ToString(s, (UInt32)f.props[0] + 1); + s.Add_UInt32((UInt32)f.props[0] + 1); else { s += '['; @@ -294,7 +255,7 @@ static AString GetCheckString(const CXzs &xzs) else { s2 = "Check-"; - AddUInt32ToString(s2, (UInt32)i); + s2.Add_UInt32((UInt32)i); } AddString(s, s2); } @@ -354,27 +315,28 @@ STDMETHODIMP CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value) struct COpenCallbackWrap { - ICompressProgress p; + ICompressProgress vt; IArchiveOpenCallback *OpenCallback; HRESULT Res; COpenCallbackWrap(IArchiveOpenCallback *progress); }; -static SRes OpenCallbackProgress(void *pp, UInt64 inSize, UInt64 /* outSize */) +static SRes OpenCallbackProgress(const ICompressProgress *pp, UInt64 inSize, UInt64 /* outSize */) { - COpenCallbackWrap *p = (COpenCallbackWrap *)pp; + COpenCallbackWrap *p = CONTAINER_FROM_VTBL(pp, COpenCallbackWrap, vt); if (p->OpenCallback) p->Res = p->OpenCallback->SetCompleted(NULL, &inSize); - return (SRes)p->Res; + return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS); } COpenCallbackWrap::COpenCallbackWrap(IArchiveOpenCallback *callback) { - p.Progress = OpenCallbackProgress; + vt.Progress = OpenCallbackProgress; OpenCallback = callback; Res = SZ_OK; } + struct CXzsCPP { CXzs p; @@ -382,6 +344,30 @@ struct CXzsCPP ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); } }; +#define kInputBufSize ((size_t)1 << 10) + +struct CLookToRead2_CPP: public CLookToRead2 +{ + CLookToRead2_CPP() + { + buf = NULL; + LookToRead2_CreateVTable(this, + True // Lookahead ? + ); + } + void Alloc(size_t allocSize) + { + buf = (Byte *)MyAlloc(allocSize); + if (buf) + this->bufSize = allocSize; + } + ~CLookToRead2_CPP() + { + MyFree(buf); + } +}; + + static HRESULT SRes_to_Open_HRESULT(SRes res) { switch (res) @@ -401,14 +387,18 @@ static HRESULT SRes_to_Open_HRESULT(SRes res) return S_FALSE; } + + HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback) { _needSeekToStart = true; { CXzStreamFlags st; - CSeqInStreamWrap inStreamWrap(inStream); - SRes res = Xz_ReadHeader(&st, &inStreamWrap.p); + CSeqInStreamWrap inStreamWrap; + + inStreamWrap.Init(inStream); + SRes res = Xz_ReadHeader(&st, &inStreamWrap.vt); if (res != SZ_OK) return SRes_to_Open_HRESULT(res); @@ -416,7 +406,7 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal CXzBlock block; Bool isIndex; UInt32 headerSizeRes; - SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.p, &isIndex, &headerSizeRes); + SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.vt, &isIndex, &headerSizeRes); if (res2 == SZ_OK && !isIndex) { unsigned numFilters = XzBlock_GetNumFilters(&block); @@ -432,18 +422,25 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal RINOK(callback->SetTotal(NULL, &_stat.PhySize)); } - CSeekInStreamWrap inStreamImp(inStream); + CSeekInStreamWrap inStreamImp;; + + inStreamImp.Init(inStream); + + CLookToRead2_CPP lookStream; + + lookStream.Alloc(kInputBufSize); + + if (!lookStream.buf) + return E_OUTOFMEMORY; - CLookToRead lookStream; - LookToRead_CreateVTable(&lookStream, True); - lookStream.realStream = &inStreamImp.p; - LookToRead_Init(&lookStream); + lookStream.realStream = &inStreamImp.vt; + LookToRead2_Init(&lookStream); COpenCallbackWrap openWrap(callback); CXzsCPP xzs; Int64 startPosition; - SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.s, &startPosition, &openWrap.p, &g_Alloc); + SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.vt, &startPosition, &openWrap.vt, &g_Alloc); if (res == SZ_ERROR_PROGRESS) return (openWrap.Res == S_OK) ? E_FAIL : openWrap.Res; /* @@ -511,6 +508,8 @@ STDMETHODIMP CHandler::Close() return S_OK; } + + class CSeekToSeqStream: public IInStream, public CMyUnknownImp @@ -530,169 +529,12 @@ STDMETHODIMP CSeekToSeqStream::Read(void *data, UInt32 size, UInt32 *processedSi STDMETHODIMP CSeekToSeqStream::Seek(Int64, UInt32, UInt64 *) { return E_NOTIMPL; } -CXzUnpackerCPP::CXzUnpackerCPP(): InBuf(0), OutBuf(0) -{ - XzUnpacker_Construct(&p, &g_Alloc); -} - -CXzUnpackerCPP::~CXzUnpackerCPP() -{ - XzUnpacker_Free(&p); - MyFree(InBuf); - MyFree(OutBuf); -} - -HRESULT CDecoder::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress) -{ - const size_t kInBufSize = 1 << 15; - const size_t kOutBufSize = 1 << 21; - - Clear(); - DecodeRes = SZ_OK; - - XzUnpacker_Init(&xzu.p); - if (!xzu.InBuf) - xzu.InBuf = (Byte *)MyAlloc(kInBufSize); - if (!xzu.OutBuf) - xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize); - - UInt32 inSize = 0; - SizeT inPos = 0; - SizeT outPos = 0; - - for (;;) - { - if (inPos == inSize) - { - inPos = inSize = 0; - RINOK(seqInStream->Read(xzu.InBuf, kInBufSize, &inSize)); - } - - SizeT inLen = inSize - inPos; - SizeT outLen = kOutBufSize - outPos; - ECoderStatus status; - - SRes res = XzUnpacker_Code(&xzu.p, - xzu.OutBuf + outPos, &outLen, - xzu.InBuf + inPos, &inLen, - (inSize == 0 ? CODER_FINISH_END : CODER_FINISH_ANY), &status); - inPos += inLen; - outPos += outLen; - InSize += inLen; - OutSize += outLen; - DecodeRes = res; - bool finished = ((inLen == 0 && outLen == 0) || res != SZ_OK); - if (outStream) - { - if (outPos == kOutBufSize || finished) - { - if (outPos != 0) - { - RINOK(WriteStream(outStream, xzu.OutBuf, outPos)); - outPos = 0; - } - } - } - else - outPos = 0; - - if (progress) - { - RINOK(progress->SetRatioInfo(&InSize, &OutSize)); - } - - if (finished) - { - PhySize = InSize; - NumStreams = xzu.p.numStartedStreams; - if (NumStreams > 0) - IsArc = true; - NumBlocks = xzu.p.numTotalBlocks; - UnpackSize_Defined = true; - NumStreams_Defined = true; - NumBlocks_Defined = true; - - UInt64 extraSize = XzUnpacker_GetExtraSize(&xzu.p); - - if (res == SZ_OK) - { - if (status == CODER_STATUS_NEEDS_MORE_INPUT) - { - extraSize = 0; - if (!XzUnpacker_IsStreamWasFinished(&xzu.p)) - { - // finished at padding bytes, but padding is not aligned for 4 - UnexpectedEnd = true; - res = SZ_ERROR_DATA; - } - } - else // status == CODER_STATUS_NOT_FINISHED - res = SZ_ERROR_DATA; - } - else if (res == SZ_ERROR_NO_ARCHIVE) - { - if (InSize == extraSize) - IsArc = false; - else - { - if (extraSize != 0 || inPos != inSize) - { - DataAfterEnd = true; - res = SZ_OK; - } - } - } - - DecodeRes = res; - PhySize -= extraSize; - - switch (res) - { - case SZ_OK: break; - case SZ_ERROR_NO_ARCHIVE: IsArc = false; break; - case SZ_ERROR_ARCHIVE: HeadersError = true; break; - case SZ_ERROR_UNSUPPORTED: Unsupported = true; break; - case SZ_ERROR_CRC: CrcError = true; break; - case SZ_ERROR_DATA: DataError = true; break; - default: DataError = true; break; - } - - break; - } - } - - return S_OK; -} - -Int32 CDecoder::Get_Extract_OperationResult() const -{ - Int32 opRes; - if (!IsArc) - opRes = NExtract::NOperationResult::kIsNotArc; - else if (UnexpectedEnd) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - else if (DataAfterEnd) - opRes = NExtract::NOperationResult::kDataAfterEnd; - else if (CrcError) - opRes = NExtract::NOperationResult::kCRCError; - else if (Unsupported) - opRes = NExtract::NOperationResult::kUnsupportedMethod; - else if (HeadersError) - opRes = NExtract::NOperationResult::kDataError; - else if (DataError) - opRes = NExtract::NOperationResult::kDataError; - else if (DecodeRes != SZ_OK) - opRes = NExtract::NOperationResult::kDataError; - else - opRes = NExtract::NOperationResult::kOK; - return opRes; -} STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) @@ -733,7 +575,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, else _needSeekToStart = true; - CDecoder decoder; + NCompress::NXz::CDecoder decoder; RINOK(Decode2(_seqStream, realOutStream, decoder, lpsRef)); Int32 opRes = decoder.Get_Extract_OperationResult(); @@ -755,11 +597,13 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt { COM_TRY_BEGIN - CSeqOutStreamWrap seqOutStream(outStream); if (numItems == 0) { - SRes res = Xz_EncodeEmpty(&seqOutStream.p); + CSeqOutStreamWrap seqOutStream; + + seqOutStream.Init(outStream); + SRes res = Xz_EncodeEmpty(&seqOutStream.vt); return SResToHRESULT(res); } @@ -795,34 +639,36 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt RINOK(updateCallback->SetTotal(size)); } - CLzma2EncProps lzma2Props; - Lzma2EncProps_Init(&lzma2Props); + NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder; + CMyComPtr<ICompressCoder> encoder = encoderSpec; + CLzma2EncProps &lzma2Props = encoderSpec->_lzma2Props; lzma2Props.lzmaProps.level = GetLevel(); CMyComPtr<ISequentialInStream> fileInStream; RINOK(updateCallback->GetStream(0, &fileInStream)); - CSeqInStreamWrap seqInStream(fileInStream); - { NCOM::CPropVariant prop = (UInt64)size; - RINOK(NCompress::NLzma2::SetLzma2Prop(NCoderPropID::kReduceSize, prop, lzma2Props)); + RINOK(encoderSpec->SetCoderProp(NCoderPropID::kReduceSize, prop)); } FOR_VECTOR (i, _methods) { COneMethodInfo &m = _methods[i]; - SetGlobalLevelAndThreads(m + + /* + SetGlobalLevelTo(m); #ifndef _7ZIP_ST - , _numThreads + CMultiMethodProps::SetMethodThreads(m, _numThreads); #endif - ); + */ + { FOR_VECTOR (j, m.Props) { const CProp &prop = m.Props[j]; - RINOK(NCompress::NLzma2::SetLzma2Prop(prop.Id, prop.Value, lzma2Props)); + RINOK(encoderSpec->SetCoderProp(prop.Id, prop.Value)); } } } @@ -835,11 +681,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(updateCallback, true); - CCompressProgressWrap progressWrap(progress); - CXzProps xzProps; - CXzFilterProps filter; + CXzProps &xzProps = encoderSpec->xzProps; + CXzFilterProps &filter = encoderSpec->filter; + XzProps_Init(&xzProps); XzFilterProps_Init(&filter); + xzProps.lzma2Props = &lzma2Props; xzProps.filterProps = (_filterId != 0 ? &filter : NULL); switch (_crcSize) @@ -869,10 +716,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (!deltaDefined) return E_INVALIDARG; } - SRes res = Xz_Encode(&seqOutStream.p, &seqInStream.p, &xzProps, &progressWrap.p); - if (res == SZ_OK) - return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); - return SResToHRESULT(res); + + return encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress); } if (indexInArchive != 0) @@ -901,6 +746,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt COM_TRY_END } + STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN diff --git a/CPP/7zip/Archive/XzHandler.h b/CPP/7zip/Archive/XzHandler.h index 4a59e356..24e8eeb4 100644 --- a/CPP/7zip/Archive/XzHandler.h +++ b/CPP/7zip/Archive/XzHandler.h @@ -3,63 +3,9 @@ #ifndef __XZ_HANDLER_H #define __XZ_HANDLER_H -#include "../../../C/Xz.h" - -#include "../ICoder.h" - namespace NArchive { namespace NXz { -struct CXzUnpackerCPP -{ - Byte *InBuf; - Byte *OutBuf; - CXzUnpacker p; - - CXzUnpackerCPP(); - ~CXzUnpackerCPP(); -}; - -struct CStatInfo -{ - UInt64 InSize; - UInt64 OutSize; - UInt64 PhySize; - - UInt64 NumStreams; - UInt64 NumBlocks; - - bool UnpackSize_Defined; - - bool NumStreams_Defined; - bool NumBlocks_Defined; - - bool IsArc; - bool UnexpectedEnd; - bool DataAfterEnd; - bool Unsupported; - bool HeadersError; - bool DataError; - bool CrcError; - - CStatInfo() { Clear(); } - - void Clear(); -}; - -struct CDecoder: public CStatInfo -{ - CXzUnpackerCPP xzu; - SRes DecodeRes; // it's not HRESULT - - CDecoder(): DecodeRes(SZ_OK) {} - - /* Decode() can return ERROR code only if there is progress or stream error. - Decode() returns S_OK in case of xz decoding error, but DecodeRes and CStatInfo contain error information */ - HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, ICompressProgressInfo *compressProgress); - Int32 Get_Extract_OperationResult() const; -}; - }} #endif diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp index 06fbe22f..dd83f87f 100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp @@ -17,6 +17,7 @@ #include "../../Compress/LzmaEncoder.h" #include "../../Compress/PpmdZip.h" +#include "../../Compress/XzEncoder.h" #include "../Common/InStreamWithCRC.h" @@ -26,8 +27,8 @@ namespace NArchive { namespace NZip { -static const CMethodId kMethodId_ZipBase = 0x040100; -static const CMethodId kMethodId_BZip2 = 0x040202; +using namespace NFileHeader; + static const UInt32 kLzmaPropsSize = 5; static const UInt32 kLzmaHeaderSize = 4 + kLzmaPropsSize; @@ -37,10 +38,11 @@ class CLzmaEncoder: public ICompressSetCoderProperties, public CMyUnknownImp { +public: NCompress::NLzma::CEncoder *EncoderSpec; CMyComPtr<ICompressCoder> Encoder; Byte Header[kLzmaHeaderSize]; -public: + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); @@ -81,7 +83,8 @@ CAddCommon::CAddCommon(const CCompressionMethodMode &options): _options(options), _copyCoderSpec(NULL), _cryptoStreamSpec(NULL), - _buf(NULL) + _buf(NULL), + _isLzmaEos(false) {} CAddCommon::~CAddCommon() @@ -114,49 +117,100 @@ HRESULT CAddCommon::CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultC } } + +HRESULT CAddCommon::Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, CCompressingResult &opRes) const +{ + // We use Zip64, if unPackSize size is larger than 0xF8000000 to support + // cases when compressed size can be about 3% larger than uncompressed size + + const UInt32 kUnpackZip64Limit = 0xF8000000; + + opRes.UnpackSize = unpackSize; + opRes.PackSize = (UInt64)1 << 60; // we use big value to force Zip64 mode. + + if (unpackSize < kUnpackZip64Limit) + opRes.PackSize = (UInt32)0xFFFFFFFF - 1; // it will not use Zip64 for that size + + if (opRes.PackSize < unpackSize) + opRes.PackSize = unpackSize; + + Byte method = _options.MethodSequence[0]; + + if (method == NCompressionMethod::kStore && !_options.PasswordIsDefined) + opRes.PackSize = unpackSize; + + opRes.CRC = 0; + + opRes.LzmaEos = false; + + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; + opRes.FileTimeWasUsed = false; + + if (_options.PasswordIsDefined) + { + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_ZipCrypto; + if (_options.IsAesMode) + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes; + else + { + if (seqMode) + opRes.FileTimeWasUsed = true; + } + } + + opRes.Method = method; + Byte ver = 0; + + switch (method) + { + case NCompressionMethod::kStore: break; + case NCompressionMethod::kDeflate: ver = NCompressionMethod::kExtractVersion_Deflate; break; + case NCompressionMethod::kDeflate64: ver = NCompressionMethod::kExtractVersion_Deflate64; break; + case NCompressionMethod::kXz : ver = NCompressionMethod::kExtractVersion_Xz; break; + case NCompressionMethod::kPPMd : ver = NCompressionMethod::kExtractVersion_PPMd; break; + case NCompressionMethod::kBZip2: ver = NCompressionMethod::kExtractVersion_BZip2; break; + case NCompressionMethod::kLZMA : + { + ver = NCompressionMethod::kExtractVersion_LZMA; + const COneMethodInfo *oneMethodMain = &_options._methods[0]; + opRes.LzmaEos = oneMethodMain->Get_Lzma_Eos(); + break; + } + } + if (opRes.ExtractVersion < ver) + opRes.ExtractVersion = ver; + + return S_OK; +} + + HRESULT CAddCommon::Compress( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, IOutStream *outStream, - UInt32 /* fileTime */, + bool seqMode, UInt32 fileTime, ICompressProgressInfo *progress, CCompressingResult &opRes) { + opRes.LzmaEos = false; + if (!inStream) { // We can create empty stream here. But it was already implemented in caller code in 9.33+ return E_INVALIDARG; } - // CSequentialInStreamWithCRC *inSecCrcStreamSpec = NULL; - CInStreamWithCRC *inCrcStreamSpec = NULL; - CMyComPtr<ISequentialInStream> inCrcStream; - { - CMyComPtr<IInStream> inStream2; - + CSequentialInStreamWithCRC *inSecCrcStreamSpec = new CSequentialInStreamWithCRC; + CMyComPtr<ISequentialInStream> inCrcStream = inSecCrcStreamSpec; + + CMyComPtr<IInStream> inStream2; + if (!seqMode) inStream->QueryInterface(IID_IInStream, (void **)&inStream2); - if (inStream2) - { - inCrcStreamSpec = new CInStreamWithCRC; - inCrcStream = inCrcStreamSpec; - inCrcStreamSpec->SetStream(inStream2); - inCrcStreamSpec->Init(); - } - else - { - // we don't support stdin, since stream from stdin can require 64-bit size header - return E_NOTIMPL; - /* - inSecCrcStreamSpec = new CSequentialInStreamWithCRC; - inCrcStream = inSecCrcStreamSpec; - inSecCrcStreamSpec->SetStream(inStream); - inSecCrcStreamSpec->Init(); - */ - } - } + inSecCrcStreamSpec->SetStream(inStream); + inSecCrcStreamSpec->Init(); unsigned numTestMethods = _options.MethodSequence.Size(); - if (numTestMethods > 1 && !inCrcStreamSpec) + if (seqMode || (numTestMethods > 1 && !inStream2)) numTestMethods = 1; UInt32 crc = 0; @@ -164,20 +218,24 @@ HRESULT CAddCommon::Compress( Byte method = 0; CFilterCoder::C_OutStream_Releaser outStreamReleaser; - opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default; + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; opRes.FileTimeWasUsed = false; for (unsigned i = 0; i < numTestMethods; i++) { - opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default; - if (inCrcStreamSpec) - RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL)); + opRes.LzmaEos = false; + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; + if (inStream2 && i != 0) + { + inSecCrcStreamSpec->Init(); + RINOK(inStream2->Seek(0, STREAM_SEEK_SET, NULL)); + } RINOK(outStream->SetSize(0)); RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL)); if (_options.PasswordIsDefined) { - opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_ZipCrypto; + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_ZipCrypto; if (!_cryptoStream) { @@ -187,7 +245,7 @@ HRESULT CAddCommon::Compress( if (_options.IsAesMode) { - opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Aes; + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes; if (!_cryptoStreamSpec->Filter) { _cryptoStreamSpec->Filter = _filterAesSpec = new NCrypto::NWzAes::CEncoder; @@ -206,23 +264,22 @@ HRESULT CAddCommon::Compress( UInt32 check; - // if (inCrcStreamSpec) + if (inStream2) { if (!crc_IsCalculated) { RINOK(CalcStreamCRC(inStream, crc)); crc_IsCalculated = true; - RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(inStream2->Seek(0, STREAM_SEEK_SET, NULL)); + inSecCrcStreamSpec->Init(); } check = (crc >> 16); } - /* else { opRes.FileTimeWasUsed = true; check = (fileTime & 0xFFFF); } - */ RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check)); } @@ -236,7 +293,7 @@ HRESULT CAddCommon::Compress( switch (method) { - case NFileHeader::NCompressionMethod::kStored: + case NCompressionMethod::kStore: { if (_copyCoderSpec == NULL) { @@ -256,15 +313,22 @@ HRESULT CAddCommon::Compress( { if (!_compressEncoder) { - if (method == NFileHeader::NCompressionMethod::kLZMA) + CLzmaEncoder *_lzmaEncoder = NULL; + if (method == NCompressionMethod::kLZMA) { - _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_LZMA; - CLzmaEncoder *_lzmaEncoder = new CLzmaEncoder(); + _compressExtractVersion = NCompressionMethod::kExtractVersion_LZMA; + _lzmaEncoder = new CLzmaEncoder(); _compressEncoder = _lzmaEncoder; } - else if (method == NFileHeader::NCompressionMethod::kPPMd) + else if (method == NCompressionMethod::kXz) + { + _compressExtractVersion = NCompressionMethod::kExtractVersion_Xz; + NCompress::NXz::CEncoder *encoder = new NCompress::NXz::CEncoder(); + _compressEncoder = encoder; + } + else if (method == NCompressionMethod::kPPMd) { - _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_PPMd; + _compressExtractVersion = NCompressionMethod::kExtractVersion_PPMd; NCompress::NPpmdZip::CEncoder *encoder = new NCompress::NPpmdZip::CEncoder(); _compressEncoder = encoder; } @@ -273,14 +337,14 @@ HRESULT CAddCommon::Compress( CMethodId methodId; switch (method) { - case NFileHeader::NCompressionMethod::kBZip2: + case NCompressionMethod::kBZip2: methodId = kMethodId_BZip2; - _compressExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_BZip2; + _compressExtractVersion = NCompressionMethod::kExtractVersion_BZip2; break; default: - _compressExtractVersion = ((method == NFileHeader::NCompressionMethod::kDeflated64) ? - NFileHeader::NCompressionMethod::kExtractVersion_Deflate64 : - NFileHeader::NCompressionMethod::kExtractVersion_Deflate); + _compressExtractVersion = ((method == NCompressionMethod::kDeflate64) ? + NCompressionMethod::kExtractVersion_Deflate64 : + NCompressionMethod::kExtractVersion_Deflate); methodId = kMethodId_ZipBase + method; break; } @@ -290,11 +354,11 @@ HRESULT CAddCommon::Compress( if (!_compressEncoder) return E_NOTIMPL; - if (method == NFileHeader::NCompressionMethod::kDeflated || - method == NFileHeader::NCompressionMethod::kDeflated64) + if (method == NCompressionMethod::kDeflate || + method == NCompressionMethod::kDeflate64) { } - else if (method == NFileHeader::NCompressionMethod::kBZip2) + else if (method == NCompressionMethod::kBZip2) { } } @@ -303,11 +367,22 @@ HRESULT CAddCommon::Compress( _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProps); if (setCoderProps) { - RINOK(_options.MethodInfo.SetCoderProps(setCoderProps, - _options._dataSizeReduceDefined ? &_options._dataSizeReduce : NULL)); + if (!_options._methods.IsEmpty()) + { + COneMethodInfo *oneMethodMain = &_options._methods[0]; + + RINOK(oneMethodMain->SetCoderProps(setCoderProps, + _options._dataSizeReduceDefined ? &_options._dataSizeReduce : NULL)); + } } } + if (method == NCompressionMethod::kLZMA) + _isLzmaEos = _lzmaEncoder->EncoderSpec->IsWriteEndMark(); } + + if (method == NCompressionMethod::kLZMA) + opRes.LzmaEos = _isLzmaEos; + CMyComPtr<ISequentialOutStream> outStreamNew; if (_options.PasswordIsDefined) outStreamNew = _cryptoStream; @@ -332,18 +407,10 @@ HRESULT CAddCommon::Compress( RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize)); - // if (inCrcStreamSpec) - { - opRes.CRC = inCrcStreamSpec->GetCRC(); - opRes.UnpackSize = inCrcStreamSpec->GetSize(); - } - /* - else { opRes.CRC = inSecCrcStreamSpec->GetCRC(); opRes.UnpackSize = inSecCrcStreamSpec->GetSize(); } - */ if (_options.PasswordIsDefined) { diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.h b/CPP/7zip/Archive/Zip/ZipAddCommon.h index 1e0c3bfa..ea5f8180 100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.h +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.h @@ -27,6 +27,7 @@ struct CCompressingResult UInt16 Method; Byte ExtractVersion; bool FileTimeWasUsed; + bool LzmaEos; }; class CAddCommon @@ -37,6 +38,7 @@ class CAddCommon CMyComPtr<ICompressCoder> _compressEncoder; Byte _compressExtractVersion; + bool _isLzmaEos; CFilterCoder *_cryptoStreamSpec; CMyComPtr<ISequentialOutStream> _cryptoStream; @@ -50,11 +52,14 @@ class CAddCommon public: CAddCommon(const CCompressionMethodMode &options); ~CAddCommon(); + + HRESULT Set_Pre_CompressionResult(bool seqMode, UInt64 unpackSize, CCompressingResult &opRes) const; + HRESULT Compress( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, IOutStream *outStream, - UInt32 fileTime, - ICompressProgressInfo *progress, CCompressingResult &operationResult); + bool seqMode, UInt32 fileTime, + ICompressProgressInfo *progress, CCompressingResult &opRes); }; }} diff --git a/CPP/7zip/Archive/Zip/ZipCompressionMode.h b/CPP/7zip/Archive/Zip/ZipCompressionMode.h index 86548d95..1125f6ed 100644 --- a/CPP/7zip/Archive/Zip/ZipCompressionMode.h +++ b/CPP/7zip/Archive/Zip/ZipCompressionMode.h @@ -14,26 +14,18 @@ namespace NArchive { namespace NZip { -struct CBaseProps -{ - CMethodProps MethodInfo; - Int32 Level; +const CMethodId kMethodId_ZipBase = 0x040100; +const CMethodId kMethodId_BZip2 = 0x040202; - #ifndef _7ZIP_ST - UInt32 NumThreads; - bool NumThreadsWasChanged; - #endif +struct CBaseProps: public CMultiMethodProps +{ bool IsAesMode; Byte AesKeyMode; void Init() { - MethodInfo.Clear(); - Level = -1; - #ifndef _7ZIP_ST - NumThreads = NWindows::NSystem::GetNumberOfProcessors();; - NumThreadsWasChanged = false; - #endif + CMultiMethodProps::Init(); + IsAesMode = false; AesKeyMode = 3; } diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp index 75034de0..75fad760 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp @@ -3,10 +3,10 @@ #include "StdAfx.h" #include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantUtils.h" #include "../../../Windows/TimeUtils.h" #include "../../IPassword.h" @@ -22,6 +22,7 @@ #include "../../Compress/ImplodeDecoder.h" #include "../../Compress/PpmdZip.h" #include "../../Compress/ShrinkDecoder.h" +#include "../../Compress/XzDecoder.h" #include "../../Crypto/WzAes.h" #include "../../Crypto/ZipCrypto.h" @@ -30,7 +31,6 @@ #include "../Common/ItemNameUtils.h" #include "../Common/OutStreamWithCRC.h" -#include "../XzHandler.h" #include "ZipHandler.h" @@ -39,9 +39,6 @@ using namespace NWindows; namespace NArchive { namespace NZip { -static const CMethodId kMethodId_ZipBase = 0x040100; -static const CMethodId kMethodId_BZip2 = 0x040202; - static const char * const kHostOS[] = { "FAT" @@ -66,24 +63,57 @@ static const char * const kHostOS[] = , "OS/X" }; -static const char * const kMethods[] = + +const char * const kMethodNames1[kNumMethodNames1] = { "Store" , "Shrink" - , "Reduced1" - , "Reduced2" - , "Reduced3" - , "Reduced4" + , "Reduce1" + , "Reduce2" + , "Reduce3" + , "Reduce4" , "Implode" - , "Tokenizing" + , NULL // "Tokenize" , "Deflate" , "Deflate64" , "PKImploding" + , NULL + , "BZip2" + , NULL + , "LZMA" +}; + + +const char * const kMethodNames2[kNumMethodNames2] = +{ + "xz" + , "Jpeg" + , "WavPack" + , "PPMd" + , "WzAES" }; -static const char *kMethod_AES = "AES"; -static const char *kMethod_ZipCrypto = "ZipCrypto"; -static const char *kMethod_StrongCrypto = "StrongCrypto"; +#define kMethod_AES "AES" +#define kMethod_ZipCrypto "ZipCrypto" +#define kMethod_StrongCrypto "StrongCrypto" + +static const char * const kDeflateLevels[4] = +{ + "Normal" + , "Maximum" + , "Fast" + , "Fastest" +}; + + +static const CUInt32PCharPair g_HeaderCharacts[] = +{ + { 0, "Encrypt" }, + { 3, "Descriptor" }, + // { 5, "Patched" }, + { 6, kMethod_StrongCrypto }, + { 11, "UTF8" } +}; struct CIdToNamePair { @@ -91,15 +121,6 @@ struct CIdToNamePair const char *Name; }; -static const CIdToNamePair k_MethodIdNamePairs[] = -{ - { NFileHeader::NCompressionMethod::kBZip2, "BZip2" }, - { NFileHeader::NCompressionMethod::kLZMA, "LZMA" }, - { NFileHeader::NCompressionMethod::kXz, "xz" }, - { NFileHeader::NCompressionMethod::kJpeg, "Jpeg" }, - { NFileHeader::NCompressionMethod::kWavPack, "WavPack" }, - { NFileHeader::NCompressionMethod::kPPMd, "PPMd" } -}; static const CIdToNamePair k_StrongCryptoPairs[] = { @@ -116,7 +137,7 @@ static const CIdToNamePair k_StrongCryptoPairs[] = { NStrongCrypto_AlgId::kRC4, "RC4" } }; -const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id) +static const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id) { for (unsigned i = 0; i < num; i++) { @@ -127,6 +148,7 @@ const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id) return NULL; } + static const Byte kProps[] = { kpidPath, @@ -142,9 +164,11 @@ static const Byte kProps[] = kpidComment, kpidCRC, kpidMethod, + kpidCharacts, kpidHostOS, kpidUnpackVer, - kpidVolumeIndex + kpidVolumeIndex, + kpidOffset }; static const Byte kArcProps[] = @@ -152,6 +176,7 @@ static const Byte kArcProps[] = kpidEmbeddedStubSize, kpidBit64, kpidComment, + kpidCharacts, kpidTotalPhySize, kpidIsVolume, kpidVolumeIndex, @@ -193,11 +218,34 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) break; } - case kpidTotalPhySize: if (m_Archive.IsMultiVol) prop = m_Archive.Vols.GetTotalSize(); break; + case kpidTotalPhySize: if (m_Archive.IsMultiVol) prop = m_Archive.Vols.TotalBytesSize; break; case kpidVolumeIndex: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.StartVolIndex; break; case kpidIsVolume: if (m_Archive.IsMultiVol) prop = true; break; case kpidNumVolumes: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.Streams.Size(); break; + case kpidCharacts: + { + AString s; + + if (m_Archive.LocalsWereRead) + { + s.Add_OptSpaced("Local"); + + if (m_Archive.LocalsCenterMerged) + s.Add_OptSpaced("Central"); + } + + if (m_Archive.IsZip64) + s.Add_OptSpaced("Zip64"); + + if (m_Archive.ExtraMinorError) + s.Add_OptSpaced("Minor_Extra_ERROR"); + + if (!s.IsEmpty()) + prop = s; + break; + } + case kpidWarningFlags: { UInt32 v = 0; @@ -208,12 +256,23 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) break; } + case kpidWarning: + { + AString s; + if (m_Archive.Overflow32bit) + s.Add_OptSpaced("32-bit overflow in headers"); + if (m_Archive.Cd_NumEntries_Overflow_16bit) + s.Add_OptSpaced("16-bit overflow for number of files in headers"); + if (!s.IsEmpty()) + prop = s; + break; + } + case kpidError: { if (!m_Archive.Vols.MissingName.IsEmpty()) { - UString s; - s.SetFromAscii("Missing volume : "); + UString s("Missing volume : "); s += m_Archive.Vols.MissingName; prop = s; } @@ -273,13 +332,19 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { UString res; item.GetUnicodeString(res, item.Name, false, _forceCodePage, _specifiedCodePage); - NItemName::ConvertToOSName2(res); + NItemName::ReplaceToOsSlashes_Remove_TailSlash(res); prop = res; break; } case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: prop = item.Size; break; + case kpidSize: + { + if (item.FromCentral || !item.FromLocal || !item.HasDescriptor() || item.DescriptorWasRead) + prop = item.Size; + break; + } + case kpidPackSize: prop = item.PackSize; break; case kpidTimeType: @@ -299,17 +364,36 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidCTime: { - FILETIME ft; - if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, ft)) - prop = ft; + FILETIME utc; + bool defined = true; + if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, utc)) + { + UInt32 unixTime = 0; + if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kCTime, unixTime)) + NTime::UnixTimeToFileTime(unixTime, utc); + else + defined = false; + } + if (defined) + prop = utc; break; } case kpidATime: { - FILETIME ft; - if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, ft)) - prop = ft; + FILETIME utc; + bool defined = true; + if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, utc)) + { + UInt32 unixTime = 0; + if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kATime, unixTime)) + NTime::UnixTimeToFileTime(unixTime, utc); + else + defined = false; + } + if (defined) + prop = utc; + break; } @@ -375,10 +459,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val CWzAesExtra aesField; if (extra.GetWzAes(aesField)) { - char s[16]; - s[0] = '-'; - ConvertUInt32ToString(((unsigned)aesField.Strength + 1) * 64 , s + 1); - m += s; + m += '-'; + m.Add_UInt32(((unsigned)aesField.Strength + 1) * 64); id = aesField.Method; } } @@ -394,10 +476,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val else { m += kMethod_StrongCrypto; - char temp[16]; - temp[0] = ':'; - ConvertUInt32ToString(f.AlgId, temp + 1); - m += temp; + m += ':'; + m.Add_UInt32(f.AlgId); } if (f.CertificateIsUsed()) m += "-Cert"; @@ -411,41 +491,96 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } { - char temp[16]; const char *s = NULL; - if (id < ARRAY_SIZE(kMethods)) - s = kMethods[id]; + if (id < kNumMethodNames1) + s = kMethodNames1[id]; else { - s = FindNameForId(k_MethodIdNamePairs, ARRAY_SIZE(k_MethodIdNamePairs), id); - if (!s) + int id2 = (int)id - (int)kMethodNames2Start; + if (id2 >= 0 && id2 < kNumMethodNames2) + s = kMethodNames2[id2]; + } + if (s) + m += s; + else + m.Add_UInt32(id); + } + { + unsigned level = item.GetDeflateLevel(); + if (level != 0) + { + if (id == NFileHeader::NCompressionMethod::kLZMA) + { + if (level & 1) + m += ":eos"; + level &= ~1; + } + else if (id == NFileHeader::NCompressionMethod::kDeflate) { - ConvertUInt32ToString(id, temp); - s = temp; + m += ':'; + m += kDeflateLevels[level]; + level = 0; + } + + if (level != 0) + { + m += ":v"; + m.Add_UInt32(level); } } - m += s; - if (id == NFileHeader::NCompressionMethod::kLZMA && item.IsLzmaEOS()) - m += ":EOS"; } prop = m; break; } - case kpidHostOS: + case kpidCharacts: { - Byte hostOS = item.GetHostOS(); - char temp[16]; - const char *s = NULL; - if (hostOS < ARRAY_SIZE(kHostOS)) - s = kHostOS[hostOS]; - else + AString s; + + if (item.FromLocal) + { + s.Add_OptSpaced("Local"); + + item.LocalExtra.PrintInfo(s); + + if (item.FromCentral) + { + s.Add_OptSpaced(":"); + s.Add_OptSpaced("Central"); + } + } + + if (item.FromCentral) { - ConvertUInt32ToString(hostOS, temp); - s = temp; + item.CentralExtra.PrintInfo(s); } - prop = s; + + UInt32 flags = item.Flags; + flags &= ~(6); // we don't need compression related bits here. + + if (flags != 0) + { + AString s2 = FlagsToString(g_HeaderCharacts, ARRAY_SIZE(g_HeaderCharacts), flags); + if (!s2.IsEmpty()) + { + s.Add_OptSpaced(":"); + s.Add_OptSpaced(s2); + } + } + + if (!item.FromCentral && item.FromLocal && item.HasDescriptor() && !item.DescriptorWasRead) + s.Add_OptSpaced("Descriptor_ERROR"); + + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidHostOS: + { + const Byte hostOS = item.GetHostOS(); + TYPE_TO_PROP(kHostOS, hostOS, prop); break; } @@ -456,6 +591,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidVolumeIndex: prop = item.Disk; break; + + case kpidOffset: + prop = item.LocalHeaderPos; + break; } prop.Detach(value); @@ -475,7 +614,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, if (res != S_OK) { m_Items.Clear(); - m_Archive.ClearRefs(); + m_Archive.ClearRefs(); // we don't want to clear error flags } return res; } @@ -493,16 +632,24 @@ STDMETHODIMP CHandler::Close() class CLzmaDecoder: public ICompressCoder, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, public CMyUnknownImp { +public: NCompress::NLzma::CDecoder *DecoderSpec; CMyComPtr<ICompressCoder> Decoder; -public: - CLzmaDecoder(); + + MY_UNKNOWN_IMP2( + ICompressSetFinishMode, + ICompressGetInStreamProcessedSize) + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + STDMETHOD(SetFinishMode)(UInt32 finishMode); + STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); - MY_UNKNOWN_IMP + CLzmaDecoder(); }; CLzmaDecoder::CLzmaDecoder() @@ -511,44 +658,45 @@ CLzmaDecoder::CLzmaDecoder() Decoder = DecoderSpec; } +static const unsigned kZipLzmaPropsSize = 4 + LZMA_PROPS_SIZE; + HRESULT CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) { - Byte buf[9]; - RINOK(ReadStream_FALSE(inStream, buf, 9)); - if (buf[2] != 5 || buf[3] != 0) + Byte buf[kZipLzmaPropsSize]; + RINOK(ReadStream_FALSE(inStream, buf, kZipLzmaPropsSize)); + if (buf[2] != LZMA_PROPS_SIZE || buf[3] != 0) return E_NOTIMPL; - RINOK(DecoderSpec->SetDecoderProperties2(buf + 4, 5)); - return Decoder->Code(inStream, outStream, NULL, outSize, progress); + RINOK(DecoderSpec->SetDecoderProperties2(buf + 4, LZMA_PROPS_SIZE)); + UInt64 inSize2 = 0; + if (inSize) + { + inSize2 = *inSize; + if (inSize2 < kZipLzmaPropsSize) + return S_FALSE; + inSize2 -= kZipLzmaPropsSize; + } + return Decoder->Code(inStream, outStream, inSize ? &inSize2 : NULL, outSize, progress); } - -class CXzDecoder: - public ICompressCoder, - public CMyUnknownImp +STDMETHODIMP CLzmaDecoder::SetFinishMode(UInt32 finishMode) { - NArchive::NXz::CDecoder _decoder; -public: - - STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - - MY_UNKNOWN_IMP -}; + DecoderSpec->FinishStream = (finishMode != 0); + return S_OK; +} -HRESULT CXzDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) +STDMETHODIMP CLzmaDecoder::GetInStreamProcessedSize(UInt64 *value) { - RINOK(_decoder.Decode(inStream, outStream, progress)); - Int32 opRes = _decoder.Get_Extract_OperationResult(); - if (opRes == NExtract::NOperationResult::kUnsupportedMethod) - return E_NOTIMPL; - if (opRes != NExtract::NOperationResult::kOK) - return S_FALSE; + *value = DecoderSpec->GetInputProcessedSize() + kZipLzmaPropsSize; return S_OK; } + + + + + struct CMethodItem { unsigned ZipMethod; @@ -572,12 +720,15 @@ class CZipDecoder CMyComPtr<ICryptoGetTextPassword> getTextPassword; CObjectVector<CMethodItem> methodItems; + CLzmaDecoder *lzmaDecoderSpec; public: CZipDecoder(): _zipCryptoDecoderSpec(0), _pkAesDecoderSpec(0), _wzAesDecoderSpec(0), - filterStreamSpec(0) {} + filterStreamSpec(0), + lzmaDecoderSpec(0) + {} HRESULT Decode( DECL_EXTERNAL_CODECS_LOC_VARS @@ -592,19 +743,18 @@ public: }; -static HRESULT SkipStreamData(ISequentialInStream *stream, UInt64 size) +static HRESULT SkipStreamData(ISequentialInStream *stream, bool &thereAreData) { + thereAreData = false; const size_t kBufSize = 1 << 12; Byte buf[kBufSize]; for (;;) { + size_t size = kBufSize; + RINOK(ReadStream(stream, buf, &size)); if (size == 0) return S_OK; - size_t curSize = kBufSize; - if (curSize > size) - curSize = (size_t)size; - RINOK(ReadStream_FALSE(stream, buf, curSize)); - size -= curSize; + thereAreData = true; } } @@ -620,12 +770,15 @@ HRESULT CZipDecoder::Decode( #endif Int32 &res) { - res = NExtract::NOperationResult::kDataError; + res = NExtract::NOperationResult::kHeadersError; + CFilterCoder::C_InStream_Releaser inStreamReleaser; + CFilterCoder::C_Filter_Releaser filterReleaser; bool needCRC = true; bool wzAesMode = false; bool pkAesMode = false; + unsigned id = item.Method; if (item.IsEncrypted()) @@ -633,27 +786,23 @@ HRESULT CZipDecoder::Decode( if (item.IsStrongEncrypted()) { CStrongCryptoExtra f; - if (item.CentralExtra.GetStrongCrypto(f)) - { - pkAesMode = true; - } - if (!pkAesMode) + if (!item.CentralExtra.GetStrongCrypto(f)) { res = NExtract::NOperationResult::kUnsupportedMethod; return S_OK; } + pkAesMode = true; } - if (!pkAesMode && id == NFileHeader::NCompressionMethod::kWzAES) + else if (id == NFileHeader::NCompressionMethod::kWzAES) { CWzAesExtra aesField; - if (item.GetMainExtra().GetWzAes(aesField)) - { - wzAesMode = true; - needCRC = aesField.NeedCrc(); - } + if (!item.GetMainExtra().GetWzAes(aesField)) + return S_OK; + wzAesMode = true; + needCRC = aesField.NeedCrc(); } } - + COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; outStreamSpec->SetStream(realOutStream); @@ -681,6 +830,9 @@ HRESULT CZipDecoder::Decode( limitedStreamSpec->SetStream(packStream); limitedStreamSpec->Init(packSize); } + + + res = NExtract::NOperationResult::kDataError; CMyComPtr<ICompressFilter> cryptoFilter; @@ -725,6 +877,8 @@ HRESULT CZipDecoder::Decode( CMyComPtr<ICryptoSetPassword> cryptoSetPassword; RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)); + if (!cryptoSetPassword) + return E_FAIL; if (!getTextPassword) extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); @@ -736,39 +890,35 @@ HRESULT CZipDecoder::Decode( AString charPassword; if (password) { + UnicodeStringToMultiByte2(charPassword, (const wchar_t *)password, CP_ACP); + /* if (wzAesMode || pkAesMode) { - charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP); - /* - for (unsigned i = 0;; i++) - { - wchar_t c = password[i]; - if (c == 0) - break; - if (c >= 0x80) - { - res = NExtract::NOperationResult::kDataError; - return S_OK; - } - charPassword += (char)c; - } - */ } else { - /* pkzip25 / WinZip / Windows probably use ANSI for some files - We use OEM for compatibility with previous versions of 7-Zip? */ - charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP); + // PASSWORD encoding for ZipCrypto: + // pkzip25 / WinZip / Windows probably use ANSI + // 7-Zip < 4.43 creates ZIP archives with OEM encoding in password + // 7-Zip >= 4.43 creates ZIP archives only with ASCII characters in password + // 7-Zip < 17.00 uses CP_OEMCP for password decoding + // 7-Zip >= 17.00 uses CP_ACP for password decoding } + */ } HRESULT result = cryptoSetPassword->CryptoSetPassword( (const Byte *)(const char *)charPassword, charPassword.Len()); if (result != S_OK) + { + res = NExtract::NOperationResult::kWrongPassword; return S_OK; + } } else { - RINOK(cryptoSetPassword->CryptoSetPassword(0, 0)); + res = NExtract::NOperationResult::kWrongPassword; + return S_OK; + // RINOK(cryptoSetPassword->CryptoSetPassword(NULL, 0)); } } @@ -781,16 +931,19 @@ HRESULT CZipDecoder::Decode( { CMethodItem mi; mi.ZipMethod = id; - if (id == NFileHeader::NCompressionMethod::kStored) + if (id == NFileHeader::NCompressionMethod::kStore) mi.Coder = new NCompress::CCopyCoder; - else if (id == NFileHeader::NCompressionMethod::kShrunk) + else if (id == NFileHeader::NCompressionMethod::kShrink) mi.Coder = new NCompress::NShrink::CDecoder; - else if (id == NFileHeader::NCompressionMethod::kImploded) + else if (id == NFileHeader::NCompressionMethod::kImplode) mi.Coder = new NCompress::NImplode::NDecoder::CCoder; else if (id == NFileHeader::NCompressionMethod::kLZMA) - mi.Coder = new CLzmaDecoder; + { + lzmaDecoderSpec = new CLzmaDecoder; + mi.Coder = lzmaDecoderSpec; + } else if (id == NFileHeader::NCompressionMethod::kXz) - mi.Coder = new CXzDecoder; + mi.Coder = new NCompress::NXz::CComDecoder; else if (id == NFileHeader::NCompressionMethod::kPPMd) mi.Coder = new NCompress::NPpmdZip::CDecoder(true); else @@ -810,7 +963,7 @@ HRESULT CZipDecoder::Decode( RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, false, mi.Coder)); - if (mi.Coder == 0) + if (!mi.Coder) { res = NExtract::NOperationResult::kUnsupportedMethod; return S_OK; @@ -842,9 +995,17 @@ HRESULT CZipDecoder::Decode( } #endif + CMyComPtr<ISequentialInStream> inStreamNew; + + bool isFullStreamExpected = (!item.HasDescriptor() || item.PackSize != 0); + bool needReminderCheck = false; + + bool dataAfterEnd = false; + bool truncatedError = false; + bool lzmaEosError = false; + { HRESULT result = S_OK; - CMyComPtr<ISequentialInStream> inStreamNew; if (item.IsEncrypted()) { if (!filterStream) @@ -853,6 +1014,7 @@ HRESULT CZipDecoder::Decode( filterStream = filterStreamSpec; } + filterReleaser.FilterCoder = filterStreamSpec; filterStreamSpec->Filter = cryptoFilter; if (wzAesMode) @@ -869,6 +1031,7 @@ HRESULT CZipDecoder::Decode( } else if (pkAesMode) { + isFullStreamExpected = false; result =_pkAesDecoderSpec->ReadHeader(inStream, item.Crc, item.Size); if (result == S_OK) { @@ -926,7 +1089,70 @@ HRESULT CZipDecoder::Decode( inStreamNew = inStream; if (result == S_OK) - result = coder->Code(inStreamNew, outStream, NULL, &item.Size, compressProgress); + { + CMyComPtr<ICompressSetFinishMode> setFinishMode; + coder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); + if (setFinishMode) + { + RINOK(setFinishMode->SetFinishMode(BoolToInt(true))); + } + + const UInt64 coderPackSize = limitedStreamSpec->GetRem(); + + bool useUnpackLimit = (id == 0 + || !item.HasDescriptor() + || item.Size >= ((UInt64)1 << 32) + || item.LocalExtra.IsZip64 + || item.CentralExtra.IsZip64 + ); + + result = coder->Code(inStreamNew, outStream, + isFullStreamExpected ? &coderPackSize : NULL, + // NULL, + useUnpackLimit ? &item.Size : NULL, + compressProgress); + + if (result == S_OK) + { + CMyComPtr<ICompressGetInStreamProcessedSize> getInStreamProcessedSize; + coder->QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize); + if (getInStreamProcessedSize && setFinishMode) + { + UInt64 processed; + RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed)); + if (processed != (UInt64)(Int64)-1) + { + if (pkAesMode) + { + const UInt32 padSize = _pkAesDecoderSpec->GetPadSize((UInt32)processed); + if (processed + padSize > coderPackSize) + truncatedError = true; + else + { + if (processed + padSize < coderPackSize) + dataAfterEnd = true; + // also here we can check PKCS7 padding data from reminder (it can be inside stream buffer in coder). + } + } + else + { + if (processed < coderPackSize) + { + if (isFullStreamExpected) + dataAfterEnd = true; + } + else if (processed > coderPackSize) + truncatedError = true; + needReminderCheck = isFullStreamExpected; + } + } + } + } + + if (result == S_OK && id == NFileHeader::NCompressionMethod::kLZMA) + if (!lzmaDecoderSpec->DecoderSpec->CheckFinishStatus(item.IsLzmaEOS())) + lzmaEosError = true; + } if (result == S_FALSE) return S_OK; @@ -947,19 +1173,40 @@ HRESULT CZipDecoder::Decode( if (wzAesMode) { - const UInt64 rem = limitedStreamSpec->GetRem(); - if (rem != 0) - if (SkipStreamData(inStream, rem) != S_OK) - authOk = false; + bool thereAreData = false; + if (SkipStreamData(inStreamNew, thereAreData) != S_OK) + authOk = false; + if (needReminderCheck && thereAreData) + dataAfterEnd = true; + limitedStreamSpec->Init(NCrypto::NWzAes::kMacSize); if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK) authOk = false; } - - res = ((crcOK && authOk) ? - NExtract::NOperationResult::kOK : - NExtract::NOperationResult::kCRCError); + + res = NExtract::NOperationResult::kCRCError; + + if (crcOK && authOk) + { + res = NExtract::NOperationResult::kOK; + + if (dataAfterEnd) + res = NExtract::NOperationResult::kDataAfterEnd; + else if (truncatedError) + res = NExtract::NOperationResult::kUnexpectedEnd; + else if (lzmaEosError) + res = NExtract::NOperationResult::kHeadersError; + + // CheckDescriptor() supports only data descriptor with signature and + // it doesn't support "old" pkzip's data descriptor without signature. + // So we disable that check. + /* + if (item.HasDescriptor() && archive.CheckDescriptor(item) != S_OK) + res = NExtract::NOperationResult::kHeadersError; + */ + } + return S_OK; } @@ -1026,11 +1273,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnavailable)); continue; } + + bool headersError = false; if (!item.FromLocal) { bool isAvail = true; - HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item, isAvail); + HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item, isAvail, headersError); if (res == S_FALSE) { if (item.IsDir() || realOutStream || testMode) @@ -1069,12 +1318,16 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, m_Archive, item, realOutStream, extractCallback, progress, #ifndef _7ZIP_ST - _props.NumThreads, + _props._numThreads, #endif res); + RINOK(hres); realOutStream.Release(); + if (res == NExtract::NOperationResult::kOK && headersError) + res = NExtract::NOperationResult::kHeadersError; + RINOK(extractCallback->SetOperationResult(res)) } diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h index c2a362a7..53e6a460 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.h +++ b/CPP/7zip/Archive/Zip/ZipHandler.h @@ -9,12 +9,20 @@ #include "../../Common/CreateCoder.h" -#include "ZipIn.h" #include "ZipCompressionMode.h" +#include "ZipIn.h" namespace NArchive { namespace NZip { +const unsigned kNumMethodNames1 = NFileHeader::NCompressionMethod::kLZMA + 1; +const unsigned kMethodNames2Start = NFileHeader::NCompressionMethod::kXz; +const unsigned kNumMethodNames2 = NFileHeader::NCompressionMethod::kWzAES + 1 - kMethodNames2Start; + +extern const char * const kMethodNames1[kNumMethodNames1]; +extern const char * const kMethodNames2[kNumMethodNames2]; + + class CHandler: public IInArchive, public IOutArchive, diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp index 8a8de511..8ecf7942 100644 --- a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp @@ -46,6 +46,30 @@ static bool IsSimpleAsciiString(const wchar_t *s) } } + +static int FindZipMethod(const char *s, const char * const *names, unsigned num) +{ + for (unsigned i = 0; i < num; i++) + { + const char *name = names[i]; + if (name && StringsAreEqualNoCase_Ascii(s, name)) + return i; + } + return -1; +} + +static int FindZipMethod(const char *s) +{ + int k = FindZipMethod(s, kMethodNames1, kNumMethodNames1); + if (k >= 0) + return k; + k = FindZipMethod(s, kMethodNames2, kNumMethodNames2); + if (k >= 0) + return kMethodNames2Start + k; + return -1; +} + + #define COM_TRY_BEGIN2 try { #define COM_TRY_END2 } \ catch(const CSystemException &e) { return e.ErrorCode; } \ @@ -63,6 +87,7 @@ static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propI return S_OK; } + STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *callback) { @@ -75,31 +100,46 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt } CObjectVector<CUpdateItem> updateItems; + updateItems.ClearAndReserve(numItems); + bool thereAreAesUpdates = false; UInt64 largestSize = 0; bool largestSizeDefined = false; + UString name; + CUpdateItem ui; + for (UInt32 i = 0; i < numItems; i++) { - CUpdateItem ui; Int32 newData; Int32 newProps; - UInt32 indexInArchive; + UInt32 indexInArc; + if (!callback) return E_FAIL; - RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); + + RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc)); + + name.Empty(); + ui.Clear(); + ui.NewProps = IntToBool(newProps); ui.NewData = IntToBool(newData); - ui.IndexInArc = indexInArchive; + ui.IndexInArc = indexInArc; ui.IndexInClient = i; - bool existInArchive = (indexInArchive != (UInt32)(Int32)-1); - if (existInArchive && newData) - if (m_Items[indexInArchive].IsAesEncrypted()) + + bool existInArchive = (indexInArc != (UInt32)(Int32)-1); + if (existInArchive) + { + const CItemEx &inputItem = m_Items[indexInArc]; + if (inputItem.IsAesEncrypted()) thereAreAesUpdates = true; + if (!IntToBool(newProps)) + ui.IsDir = inputItem.IsDir(); + } if (IntToBool(newProps)) { - UString name; { NCOM::CPropVariant prop; RINOK(callback->GetProperty(i, kpidAttrib, &prop)); @@ -115,12 +155,15 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt NCOM::CPropVariant prop; RINOK(callback->GetProperty(i, kpidPath, &prop)); if (prop.vt == VT_EMPTY) - name.Empty(); + { + // name.Empty(); + } else if (prop.vt != VT_BSTR) return E_INVALIDARG; else name = prop.bstrVal; } + { NCOM::CPropVariant prop; RINOK(callback->GetProperty(i, kpidIsDir, &prop)); @@ -153,7 +196,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt FileTimeToDosTime(localFileTime, ui.Time); } - name = NItemName::MakeLegalName(name); + NItemName::ReplaceSlashes_OsToUnix(name); + bool needSlash = ui.IsDir; const wchar_t kSlash = L'/'; if (!name.IsEmpty()) @@ -188,11 +232,37 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (ui.Name.Len() >= (1 << 16)) return E_INVALIDARG; - ui.IndexInClient = i; + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidComment, &prop)); + if (prop.vt == VT_EMPTY) + { + // ui.Comment.Free(); + } + else if (prop.vt != VT_BSTR) + return E_INVALIDARG; + else + { + UString s = prop.bstrVal; + AString a; + if (ui.IsUtf8) + ConvertUnicodeToUTF8(s, a); + else + { + bool defaultCharWasUsed; + a = UnicodeStringToMultiByte(s, codePage, '_', defaultCharWasUsed); + } + if (a.Len() >= (1 << 16)) + return E_INVALIDARG; + ui.Comment.CopyFrom((const Byte *)(const char *)a, a.Len()); + } + } + + /* if (existInArchive) { - const CItemEx &itemInfo = m_Items[indexInArchive]; + const CItemEx &itemInfo = m_Items[indexInArc]; // ui.Commented = itemInfo.IsCommented(); ui.Commented = false; if (ui.Commented) @@ -205,6 +275,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt ui.Commented = false; */ } + + if (IntToBool(newData)) { UInt64 size = 0; @@ -220,12 +292,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt largestSizeDefined = true; } ui.Size = size; - - // ui.Size -= ui.Size / 2; } + updateItems.Add(ui); } + CMyComPtr<ICryptoGetTextPassword2> getTextPassword; { CMyComPtr<IArchiveUpdateCallback> udateCallBack2(callback); @@ -261,16 +333,52 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt } } - Byte mainMethod; - if (m_MainMethod < 0) - mainMethod = (Byte)(((_props.Level == 0) ? - NFileHeader::NCompressionMethod::kStored : - NFileHeader::NCompressionMethod::kDeflated)); + + int mainMethod = m_MainMethod; + + if (mainMethod < 0) + { + if (!_props._methods.IsEmpty()) + { + const AString &methodName = _props._methods.Front().MethodName; + if (!methodName.IsEmpty()) + { + mainMethod = FindZipMethod(methodName); + if (mainMethod < 0) + { + CMethodId methodId; + UInt32 numStreams; + if (!FindMethod(EXTERNAL_CODECS_VARS methodName, methodId, numStreams)) + return E_NOTIMPL; + if (numStreams != 1) + return E_NOTIMPL; + if (methodId == kMethodId_BZip2) + mainMethod = NFileHeader::NCompressionMethod::kBZip2; + else + { + if (methodId < kMethodId_ZipBase) + return E_NOTIMPL; + methodId -= kMethodId_ZipBase; + if (methodId > 0xFF) + return E_NOTIMPL; + mainMethod = (int)methodId; + } + } + } + } + } + + if (mainMethod < 0) + mainMethod = (Byte)(((_props.GetLevel() == 0) ? + NFileHeader::NCompressionMethod::kStore : + NFileHeader::NCompressionMethod::kDeflate)); else - mainMethod = (Byte)m_MainMethod; - options.MethodSequence.Add(mainMethod); - if (mainMethod != NFileHeader::NCompressionMethod::kStored) - options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStored); + mainMethod = (Byte)mainMethod; + + options.MethodSequence.Add((Byte)mainMethod); + + if (mainMethod != NFileHeader::NCompressionMethod::kStore) + options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStore); return Update( EXTERNAL_CODECS_VARS @@ -281,28 +389,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt COM_TRY_END2 } -struct CMethodIndexToName -{ - unsigned Method; - const char *Name; -}; -static const CMethodIndexToName k_SupportedMethods[] = -{ - { NFileHeader::NCompressionMethod::kStored, "copy" }, - { NFileHeader::NCompressionMethod::kDeflated, "deflate" }, - { NFileHeader::NCompressionMethod::kDeflated64, "deflate64" }, - { NFileHeader::NCompressionMethod::kBZip2, "bzip2" }, - { NFileHeader::NCompressionMethod::kLZMA, "lzma" }, - { NFileHeader::NCompressionMethod::kPPMd, "ppmd" } -}; STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { InitMethodProps(); - #ifndef _7ZIP_ST - const UInt32 numProcessors = _props.NumThreads; - #endif for (UInt32 i = 0; i < numProps; i++) { @@ -313,82 +404,27 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR const PROPVARIANT &prop = values[i]; - if (name[0] == L'x') - { - UInt32 level = 9; - RINOK(ParsePropToUInt32(name.Ptr(1), prop, level)); - _props.Level = level; - _props.MethodInfo.AddProp_Level(level); - } - else if (name == L"m") - { - if (prop.vt == VT_BSTR) - { - UString m = prop.bstrVal, m2; - m.MakeLower_Ascii(); - int colonPos = m.Find(L':'); - if (colonPos >= 0) - { - m2 = m.Ptr(colonPos + 1); - m.DeleteFrom(colonPos); - } - unsigned k; - for (k = 0; k < ARRAY_SIZE(k_SupportedMethods); k++) - { - const CMethodIndexToName &pair = k_SupportedMethods[k]; - if (m.IsEqualTo(pair.Name)) - { - if (!m2.IsEmpty()) - { - RINOK(_props.MethodInfo.ParseParamsFromString(m2)); - } - m_MainMethod = pair.Method; - break; - } - } - if (k == ARRAY_SIZE(k_SupportedMethods)) - return E_INVALIDARG; - } - else if (prop.vt == VT_UI4) - { - unsigned k; - for (k = 0; k < ARRAY_SIZE(k_SupportedMethods); k++) - { - unsigned method = k_SupportedMethods[k].Method; - if (prop.ulVal == method) - { - m_MainMethod = method; - break; - } - } - if (k == ARRAY_SIZE(k_SupportedMethods)) - return E_INVALIDARG; - } - else - return E_INVALIDARG; - } - else if (name.IsPrefixedBy(L"em")) + if (name.IsEqualTo_Ascii_NoCase("em")) { if (prop.vt != VT_BSTR) return E_INVALIDARG; { - UString m = prop.bstrVal; - m.MakeLower_Ascii(); - if (m.IsPrefixedBy(L"aes")) + const wchar_t *m = prop.bstrVal; + if (IsString1PrefixedByString2_NoCase_Ascii(m, "aes")) { - m.DeleteFrontal(3); - if (m == L"128") + m += 3; + if (StringsAreEqual_Ascii(m, "128")) _props.AesKeyMode = 1; - else if (m == L"192") + else if (StringsAreEqual_Ascii(m, "192")) _props.AesKeyMode = 2; - else if (m == L"256" || m.IsEmpty()) + else if (StringsAreEqual_Ascii(m, "256") || m[0] == 0) _props.AesKeyMode = 3; else return E_INVALIDARG; _props.IsAesMode = true; m_ForceAesMode = true; } - else if (m == L"zipcrypto") + else if (StringsAreEqualNoCase_Ascii(m, "ZipCrypto")) { _props.IsAesMode = false; m_ForceAesMode = true; @@ -397,13 +433,6 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR return E_INVALIDARG; } } - else if (name.IsPrefixedBy(L"mt")) - { - #ifndef _7ZIP_ST - RINOK(ParseMtProp(name.Ptr(2), prop, numProcessors, _props.NumThreads)); - _props.NumThreadsWasChanged = true; - #endif - } else if (name.IsEqualTo("tc")) { RINOK(PROPVARIANT_to_bool(prop, m_WriteNtfsTimeExtra)); @@ -433,9 +462,39 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR } else { - RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop)); + if (name.IsEqualTo_Ascii_NoCase("m") && prop.vt == VT_UI4) + { + UInt32 id = prop.ulVal; + if (id > 0xFF) + return E_INVALIDARG; + m_MainMethod = id; + } + else + { + RINOK(_props.SetProperty(name, prop)); + } + // RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop)); } } + + _props._methods.DeleteFrontal(_props.GetNumEmptyMethods()); + if (_props._methods.Size() > 1) + return E_INVALIDARG; + if (_props._methods.Size() == 1) + { + const AString &methodName = _props._methods[0].MethodName; + + if (!methodName.IsEmpty()) + { + const char *end; + UInt32 id = ConvertStringToUInt32(methodName, &end); + if (*end == 0 && id <= 0xFF) + m_MainMethod = id; + else if (methodName.IsEqualTo_Ascii_NoCase("Copy")) // it's alias for "Store" + m_MainMethod = 0; + } + } + return S_OK; } diff --git a/CPP/7zip/Archive/Zip/ZipHeader.h b/CPP/7zip/Archive/Zip/ZipHeader.h index fead0192..61b4ea4b 100644 --- a/CPP/7zip/Archive/Zip/ZipHeader.h +++ b/CPP/7zip/Archive/Zip/ZipHeader.h @@ -23,7 +23,8 @@ namespace NSignature } const unsigned kLocalHeaderSize = 4 + 26; // including signature -const unsigned kDataDescriptorSize = 4 + 12; // including signature +const unsigned kDataDescriptorSize32 = 4 + 4 + 4 * 2; // including signature +const unsigned kDataDescriptorSize64 = 4 + 4 + 8 * 2; // including signature const unsigned kCentralHeaderSize = 4 + 42; // including signature const unsigned kEcdSize = 22; // including signature @@ -37,28 +38,30 @@ namespace NFileHeader { enum EType { - kStored = 0, - kShrunk = 1, - kReduced1 = 2, - kReduced2 = 3, - kReduced3 = 4, - kReduced4 = 5, - kImploded = 6, - kReservedTokenizing = 7, // reserved for tokenizing - kDeflated = 8, - kDeflated64 = 9, + kStore = 0, + kShrink = 1, + kReduce1 = 2, + kReduce2 = 3, + kReduce3 = 4, + kReduce4 = 5, + kImplode = 6, + kTokenize = 7, + kDeflate = 8, + kDeflate64 = 9, kPKImploding = 10, kBZip2 = 12, + kLZMA = 14, + kTerse = 18, kLz77 = 19, - kXz = 0x5F, - kJpeg = 0x60, - kWavPack = 0x61, - kPPMd = 0x62, - kWzAES = 0x63 + kXz = 95, + kJpeg = 96, + kWavPack = 97, + kPPMd = 98, + kWzAES = 99 }; const Byte kMadeByProgramVersion = 63; @@ -73,6 +76,7 @@ namespace NFileHeader const Byte kExtractVersion_Aes = 51; const Byte kExtractVersion_LZMA = 63; const Byte kExtractVersion_PPMd = 63; + const Byte kExtractVersion_Xz = 20; // test it } namespace NExtraID @@ -83,6 +87,7 @@ namespace NFileHeader kNTFS = 0x0A, kStrongEncrypt = 0x17, kUnixTime = 0x5455, + kUnixExtra = 0x5855, kIzUnicodeComment = 0x6375, kIzUnicodeName = 0x7075, kWzAES = 0x9901 @@ -110,6 +115,15 @@ namespace NFileHeader }; } + namespace NUnixExtra + { + enum + { + kATime = 0, + kMTime + }; + } + namespace NFlags { const unsigned kEncrypted = 1 << 0; @@ -121,10 +135,12 @@ namespace NFileHeader const unsigned kImplodeDictionarySizeMask = 1 << 1; const unsigned kImplodeLiteralsOnMask = 1 << 2; + /* const unsigned kDeflateTypeBitStart = 1; const unsigned kNumDeflateTypeBits = 2; const unsigned kNumDeflateTypes = (1 << kNumDeflateTypeBits); const unsigned kDeflateTypeMask = (1 << kNumDeflateTypeBits) - 1; + */ } namespace NHostOS diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index 6361dc5c..09443a61 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -6,6 +6,7 @@ #include "../../../Common/DynamicBuffer.h" #include "../../../Common/IntToString.h" +#include "../../../Common/MyException.h" #include "../../../Common/StringToInt.h" #include "../../../Windows/PropVariant.h" @@ -27,6 +28,19 @@ namespace NArchive { namespace NZip { +// (kBufferSize >= kDataDescriptorSize64 + 4) + +static const size_t kSeqBufferSize = (size_t)1 << 14; + +/* + if (not defined ZIP_SELF_CHECK) : it reads CD and if error in first pass CD reading, it reads LOCALS-CD-MODE + if ( defined ZIP_SELF_CHECK) : it always reads CD and LOCALS-CD-MODE + use ZIP_SELF_CHECK to check LOCALS-CD-MODE for any zip archive +*/ + +// #define ZIP_SELF_CHECK + + struct CEcd { UInt16 ThisDisk; @@ -66,6 +80,7 @@ void CEcd::Parse(const Byte *p) void CCdInfo::ParseEcd32(const Byte *p) { + IsFromEcd64 = false; // (p) includes signature p += 4; G16(0, ThisDisk); @@ -79,6 +94,7 @@ void CCdInfo::ParseEcd32(const Byte *p) void CCdInfo::ParseEcd64e(const Byte *p) { + IsFromEcd64 = true; // (p) exclude signature G16(0, VersionMade); G16(2, VersionNeedExtract); @@ -106,9 +122,14 @@ struct CLocator G64(4, Ecd64Offset); G32(12, NumDisks); } -}; + bool IsEmptyArc() const + { + return Ecd64Disk == 0 && NumDisks == 0 && Ecd64Offset == 0; + } +}; + void CInArchive::ClearRefs() @@ -123,27 +144,174 @@ void CInArchive::ClearRefs() void CInArchive::Close() { - _processedCnt = 0; - IsArc = false; + _cnt = 0; + DisableBufMode(); + IsArcOpen = false; - IsMultiVol = false; - UseDisk_in_SingleVol = false; - EcdVolIndex = 0; + + IsArc = false; + IsZip64 = false; + HeadersError = false; HeadersWarning = false; ExtraMinorError = false; UnexpectedEnd = false; + LocalsWereRead = false; + LocalsCenterMerged = false; NoCentralDir = false; - IsZip64 = false; + Overflow32bit = false; + Cd_NumEntries_Overflow_16bit = false; + MarkerIsFound = false; + MarkerIsSafe = false; + + IsMultiVol = false; + UseDisk_in_SingleVol = false; + EcdVolIndex = 0; + ArcInfo.Clear(); + ClearRefs(); } -HRESULT CInArchive::Seek(UInt64 offset) + +HRESULT CInArchive::Seek_SavePos(UInt64 offset) +{ + // InitBuf(); + // if (!Stream) return S_FALSE; + return Stream->Seek(offset, STREAM_SEEK_SET, &_streamPos); +} + +HRESULT CInArchive::SeekToVol(int volIndex, UInt64 offset) +{ + if (volIndex != Vols.StreamIndex) + { + InitBuf(); + if (IsMultiVol && volIndex >= 0) + { + if ((unsigned)volIndex >= Vols.Streams.Size()) + return S_FALSE; + if (!Vols.Streams[volIndex].Stream) + return S_FALSE; + Stream = Vols.Streams[volIndex].Stream; + } + else if (volIndex == -2) + { + if (!Vols.ZipStream) + return S_FALSE; + Stream = Vols.ZipStream; + } + else + Stream = StartStream; + Vols.StreamIndex = volIndex; + } + else + { + if (offset <= _streamPos) + { + const UInt64 back = _streamPos - offset; + if (back <= _bufCached) + { + _bufPos = _bufCached - (size_t)back; + return S_OK; + } + } + InitBuf(); + } + return Seek_SavePos(offset); +} + + +// ---------- ReadFromCache ---------- +// reads from cache and from Stream +// move to next volume can be allowed if (CanStartNewVol) and only before first byte reading + +HRESULT CInArchive::ReadFromCache(Byte *data, unsigned size, unsigned &processed) { - return Stream->Seek(offset, STREAM_SEEK_SET, NULL); + HRESULT result = S_OK; + processed = 0; + + for (;;) + { + if (size == 0) + return S_OK; + + const size_t avail = GetAvail(); + + if (avail != 0) + { + unsigned cur = size; + if (cur > avail) + cur = (unsigned)avail; + memcpy(data, (const Byte *)Buffer + _bufPos, cur); + + data += cur; + size -= cur; + processed += cur; + + _bufPos += cur; + _cnt += cur; + + CanStartNewVol = false; + + continue; + } + + InitBuf(); + + if (_inBufMode) + { + UInt32 cur = 0; + result = Stream->Read(Buffer, (UInt32)Buffer.Size(), &cur); + _bufPos = 0; + _bufCached = cur; + _streamPos += cur; + if (cur != 0) + CanStartNewVol = false; + if (result != S_OK) + break; + if (cur != 0) + continue; + } + else + { + UInt32 cur = 0; + result = Stream->Read(data, size, &cur); + data += cur; + size -= cur; + processed += cur; + _streamPos += cur; + _cnt += cur; + if (cur != 0) + { + CanStartNewVol = false; + break; + } + if (result != S_OK) + break; + } + + if ( !IsMultiVol + || !CanStartNewVol + || Vols.StreamIndex < 0 + || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size()) + break; + + const CVols::CSubStreamInfo &s = Vols.Streams[Vols.StreamIndex + 1]; + if (!s.Stream) + break; + result = s.SeekToStart(); + if (result != S_OK) + break; + Vols.StreamIndex++; + _streamPos = 0; + // Vols.NeedSeek = false; + + Stream = s.Stream; + } + + return result; } @@ -168,18 +336,33 @@ API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size) if (p[0] != 'P') return k_IsArc_Res_NO; - UInt32 value = Get32(p); + UInt32 sig = Get32(p); - if (value == NSignature::kNoSpan - || value == NSignature::kSpan) + if (sig == NSignature::kNoSpan || sig == NSignature::kSpan) { p += 4; size -= 4; } - value = Get32(p); + sig = Get32(p); - if (value == NSignature::kEcd) + if (sig == NSignature::kEcd64) + { + if (size < kEcd64_FullSize) + return k_IsArc_Res_NEED_MORE; + + const UInt64 recordSize = Get64(p + 4); + if ( recordSize < kEcd64_MainSize + || recordSize > kEcd64_MainSize + (1 << 20)) + return k_IsArc_Res_NO; + CCdInfo cdInfo; + cdInfo.ParseEcd64e(p + 12); + if (!cdInfo.IsEmptyArc()) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; // k_IsArc_Res_YES_2; + } + + if (sig == NSignature::kEcd) { if (size < kEcdSize) return k_IsArc_Res_NEED_MORE; @@ -190,8 +373,8 @@ API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size) return k_IsArc_Res_NO; return k_IsArc_Res_YES; // k_IsArc_Res_YES_2; } - - if (value != NSignature::kLocalFileHeader) + + if (sig != NSignature::kLocalFileHeader) return k_IsArc_Res_NO; if (size < kLocalHeaderSize) @@ -240,8 +423,17 @@ API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size) const Byte *p2 = p + kLocalHeaderSize; for (size_t i = 0; i < rem; i++) if (p2[i] == 0) + { + // we support some "bad" zip archives that contain zeros after name + for (size_t k = i + 1; k < rem; k++) + if (p2[k] != 0) + return k_IsArc_Res_NO; + break; + /* if (i != nameSize - 1) return k_IsArc_Res_NO; + */ + } } if (size < extraOffset) @@ -288,398 +480,562 @@ static UInt32 IsArc_Zip_2(const Byte *p, size_t size, bool isFinal) } + +MY_NO_INLINE +static const Byte *FindPK(const Byte *p, const Byte *limit) +{ + for (;;) + { + for (;;) + { + Byte b0 = p[0]; + if (p >= limit) + return p; + p++; + if (b0 == 0x50) + break; + } + if (p[0] == 0x4B) + return p - 1; + } +} + -HRESULT CInArchive::FindMarker(IInStream *stream, const UInt64 *searchLimit) +/* +---------- FindMarker ---------- +returns: + S_OK: + ArcInfo.MarkerVolIndex : volume of marker + ArcInfo.MarkerPos : Pos of first signature + ArcInfo.MarkerPos2 : Pos of main signature (local item signature in most cases) + _streamPos : stream pos + _cnt : The number of virtal Bytes after start of search to offset after signature + _signature : main signature + + S_FALSE: can't find marker, or there is some non-zip data after marker + + Error code: stream reading error. +*/ + +HRESULT CInArchive::FindMarker(const UInt64 *searchLimit) { - ArcInfo.MarkerPos = m_Position; - ArcInfo.MarkerPos2 = m_Position; + ArcInfo.MarkerPos = GetVirtStreamPos(); + ArcInfo.MarkerPos2 = ArcInfo.MarkerPos; + ArcInfo.MarkerVolIndex = Vols.StreamIndex; + + _cnt = 0; + + CanStartNewVol = false; if (searchLimit && *searchLimit == 0) { Byte startBuf[kMarkerSize]; - { - size_t processed = kMarkerSize; - RINOK(ReadStream(stream, startBuf, &processed)); - m_Position += processed; - if (processed != kMarkerSize) - return S_FALSE; - } + unsigned processed; + RINOK(ReadFromCache(startBuf, kMarkerSize, processed)); + if (processed != kMarkerSize) + return S_FALSE; - m_Signature = Get32(startBuf); + UInt32 marker = Get32(startBuf); + _signature = marker; - if (m_Signature != NSignature::kEcd && - m_Signature != NSignature::kLocalFileHeader) + if ( marker == NSignature::kNoSpan + || marker == NSignature::kSpan) { - if (m_Signature != NSignature::kNoSpan) - { - if (m_Signature != NSignature::kSpan) - return S_FALSE; - if (m_Position != 4) // we don't support multivol archives with sfx stub - return S_FALSE; - ArcInfo.IsSpanMode = true; - } - size_t processed = kMarkerSize; - RINOK(ReadStream(stream, startBuf, &processed)); - m_Position += processed; + RINOK(ReadFromCache(startBuf, kMarkerSize, processed)); if (processed != kMarkerSize) return S_FALSE; - m_Signature = Get32(startBuf); - if (m_Signature != NSignature::kEcd && - m_Signature != NSignature::kLocalFileHeader) - return S_FALSE; - ArcInfo.MarkerPos2 += 4; + _signature = Get32(startBuf); } + + if ( _signature != NSignature::kEcd + && _signature != NSignature::kEcd64 + && _signature != NSignature::kLocalFileHeader) + return S_FALSE; + + ArcInfo.MarkerPos2 = GetVirtStreamPos() - 4; + ArcInfo.IsSpanMode = (marker == NSignature::kSpan); // we use weak test in case of (*searchLimit == 0) // since error will be detected later in Open function - return S_OK; // maybe we need to search backward. + return S_OK; } - const size_t kBufSize = (size_t)1 << 18; // must be larger than kCheckSize const size_t kCheckSize = (size_t)1 << 16; // must be smaller than kBufSize - CByteArr buffer(kBufSize); - - size_t numBytesInBuffer = 0; - UInt64 curScanPos = 0; + const size_t kBufSize = (size_t)1 << 17; // must be larger than kCheckSize + + if (Buffer.Size() < kBufSize) + { + InitBuf(); + Buffer.AllocAtLeast(kBufSize); + if (!Buffer.IsAllocated()) + return E_OUTOFMEMORY; + } + + _inBufMode = true; + + UInt64 progressPrev = 0; for (;;) { - size_t numReadBytes = kBufSize - numBytesInBuffer; - RINOK(ReadStream(stream, buffer + numBytesInBuffer, &numReadBytes)); - m_Position += numReadBytes; - numBytesInBuffer += numReadBytes; - const bool isFinished = (numBytesInBuffer != kBufSize); + RINOK(LookAhead(kBufSize)); - size_t limit = numBytesInBuffer;; + const size_t avail = GetAvail(); + + size_t limitPos; + const bool isFinished = (avail != kBufSize); if (isFinished) { - if (limit == 0) - break; - limit--; + const unsigned kMinAllowed = 4; + if (avail <= kMinAllowed) + { + if ( !IsMultiVol + || Vols.StreamIndex < 0 + || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size()) + break; + + SkipLookahed(avail); + + const CVols::CSubStreamInfo &s = Vols.Streams[Vols.StreamIndex + 1]; + if (!s.Stream) + break; + + RINOK(s.SeekToStart()); + + InitBuf(); + Vols.StreamIndex++; + _streamPos = 0; + Stream = s.Stream; + continue; + } + limitPos = avail - kMinAllowed; } else - limit -= kCheckSize; + limitPos = (avail - kCheckSize); - if (searchLimit && curScanPos + limit > *searchLimit) - limit = (size_t)(*searchLimit - curScanPos + 1); + // we don't check at (limitPos) for good fast aligned operations - if (limit < 1) + if (searchLimit) + { + if (_cnt > *searchLimit) + break; + UInt64 rem = *searchLimit - _cnt; + if (limitPos > rem) + limitPos = (size_t)rem + 1; + } + + if (limitPos == 0) break; - const Byte *buf = buffer; - for (size_t pos = 0; pos < limit; pos++) + const Byte * const pStart = Buffer + _bufPos; + const Byte * p = pStart; + const Byte * const limit = pStart + limitPos; + + for (;; p++) { - if (buf[pos] != 0x50) - continue; - if (buf[pos + 1] != 0x4B) - continue; - size_t rem = numBytesInBuffer - pos; - UInt32 res = IsArc_Zip_2(buf + pos, rem, isFinished); + p = FindPK(p, limit); + if (p >= limit) + break; + const size_t rem = pStart + avail - p; + UInt32 res = IsArc_Zip_2(p, rem, isFinished); if (res != k_IsArc_Res_NO) { if (rem < kMarkerSize) return S_FALSE; - m_Signature = Get32(buf + pos); - ArcInfo.MarkerPos += curScanPos + pos; + _signature = Get32(p); + SkipLookahed(p - pStart); + ArcInfo.MarkerVolIndex = Vols.StreamIndex; + ArcInfo.MarkerPos = GetVirtStreamPos(); ArcInfo.MarkerPos2 = ArcInfo.MarkerPos; - if (m_Signature == NSignature::kNoSpan - || m_Signature == NSignature::kSpan) + SkipLookahed(4); + if ( _signature == NSignature::kNoSpan + || _signature == NSignature::kSpan) { - m_Signature = Get32(buf + pos + 4); + if (rem < kMarkerSize * 2) + return S_FALSE; + ArcInfo.IsSpanMode = (_signature == NSignature::kSpan); + _signature = Get32(p + 4); ArcInfo.MarkerPos2 += 4; + SkipLookahed(4); } - m_Position = ArcInfo.MarkerPos2 + kMarkerSize; return S_OK; } } - if (isFinished) + if (!IsMultiVol && isFinished) break; - curScanPos += limit; - numBytesInBuffer -= limit; - memmove(buffer, buffer + limit, numBytesInBuffer); + SkipLookahed(p - pStart); + + if (Callback && (_cnt - progressPrev) >= ((UInt32)1 << 23)) + { + progressPrev = _cnt; + // const UInt64 numFiles64 = 0; + RINOK(Callback->SetCompleted(NULL, &_cnt)); + } } return S_FALSE; } -HRESULT CInArchive::IncreaseRealPosition(Int64 addValue, bool &isFinished) +/* +---------- IncreaseRealPosition ---------- +moves virtual offset in virtual stream. +changing to new volumes is allowed +*/ + +HRESULT CInArchive::IncreaseRealPosition(UInt64 offset, bool &isFinished) { isFinished = false; + + for (;;) + { + const size_t avail = GetAvail(); + + if (offset <= avail) + { + _bufPos += (size_t)offset; + _cnt += offset; + return S_OK; + } + + _cnt += avail; + offset -= avail; + + _bufCached = 0; + _bufPos = 0; + + if (!_inBufMode) + break; + + CanStartNewVol = true; + LookAhead(1); + + if (GetAvail() == 0) + return S_OK; + } + if (!IsMultiVol) - return Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position); + { + _cnt += offset; + return Stream->Seek(offset, STREAM_SEEK_CUR, &_streamPos); + } for (;;) { - if (addValue == 0) + if (offset == 0) return S_OK; - if (addValue > 0) + + if (Vols.StreamIndex < 0) + return S_FALSE; + if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size()) { - if (Vols.StreamIndex < 0) - return S_FALSE; - if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size()) + isFinished = true; + return S_OK; + } + { + const CVols::CSubStreamInfo &s = Vols.Streams[Vols.StreamIndex]; + if (!s.Stream) { isFinished = true; return S_OK; } + if (_streamPos > s.Size) + return S_FALSE; + const UInt64 rem = s.Size - _streamPos; + if ((UInt64)offset <= rem) { - const CVols::CSubStreamInfo &s = Vols.Streams[Vols.StreamIndex]; - if (!s.Stream) - { - isFinished = true; - return S_OK; - } - if (m_Position > s.Size) - return S_FALSE; - UInt64 rem = s.Size - m_Position; - if ((UInt64)addValue <= rem) - return Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position); - RINOK(Stream->Seek(s.Size, STREAM_SEEK_SET, &m_Position)); - addValue -= rem; - Stream = NULL; - Vols.StreamIndex++; - if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size()) - { - isFinished = true; - return S_OK; - } - } - const CVols::CSubStreamInfo &s2 = Vols.Streams[Vols.StreamIndex]; - if (!s2.Stream) - { - isFinished = true; - return S_OK; + _cnt += offset; + return Stream->Seek(offset, STREAM_SEEK_CUR, &_streamPos); } - Stream = s2.Stream; - m_Position = 0; - RINOK(Stream->Seek(0, STREAM_SEEK_SET, &m_Position)); + RINOK(Seek_SavePos(s.Size)); + offset -= rem; + _cnt += rem; } - else + + Stream = NULL; + _streamPos = 0; + Vols.StreamIndex++; + if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size()) { - if (!Stream) - return S_FALSE; - { - if (m_Position >= (UInt64)(-addValue)) - return Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position); - addValue += m_Position; - RINOK(Stream->Seek(0, STREAM_SEEK_SET, &m_Position)); - m_Position = 0; - Stream = NULL; - if (--Vols.StreamIndex < 0) - return S_FALSE; - } - const CVols::CSubStreamInfo &s2 = Vols.Streams[Vols.StreamIndex]; - if (!s2.Stream) - return S_FALSE; - Stream = s2.Stream; - m_Position = s2.Size; - RINOK(Stream->Seek(s2.Size, STREAM_SEEK_SET, &m_Position)); + isFinished = true; + return S_OK; + } + const CVols::CSubStreamInfo &s2 = Vols.Streams[Vols.StreamIndex]; + if (!s2.Stream) + { + isFinished = true; + return S_OK; } + Stream = s2.Stream; + RINOK(Seek_SavePos(0)); } } -class CUnexpectEnd {}; +/* +---------- LookAhead ---------- +Reads data to buffer, if required. -HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize) -{ - size_t realProcessedSize = size; - HRESULT result = S_OK; - if (_inBufMode) - { - try { realProcessedSize = _inBuffer.ReadBytes((Byte *)data, size); } - catch (const CInBufferException &e) { return e.ErrorCode; } - } - else - result = ReadStream(Stream, data, &realProcessedSize); - if (processedSize) - *processedSize = (UInt32)realProcessedSize; - m_Position += realProcessedSize; - return result; -} +It can read from volumes as long as Buffer.Size(). +But it moves to new volume, only if it's required to provide minRequired bytes in buffer. -void CInArchive::SafeReadBytes(void *data, unsigned size) -{ - size_t processed = size; - - HRESULT result = S_OK; +in: + (minRequired <= Buffer.Size()) - if (!_inBufMode) - result = ReadStream(Stream, data, &processed); - else +return: + S_OK : if (GetAvail() < minRequired) after function return, it's end of stream(s) data, or no new volume stream. + Error codes: IInStream::Read() error or IInStream::Seek() error for multivol +*/ + +HRESULT CInArchive::LookAhead(size_t minRequired) +{ + for (;;) { - for (;;) + const size_t avail = GetAvail(); + + if (minRequired <= avail) + return S_OK; + + if (_bufPos != 0) { - processed = _inBuffer.ReadBytes((Byte *)data, size); - if (processed != 0 - || IsMultiVol - || !CanStartNewVol - || Vols.StreamIndex < 0 - || (unsigned)Vols.StreamIndex >= Vols.Streams.Size()) - break; - Vols.StreamIndex++; - const CVols::CSubStreamInfo &s = Vols.Streams[Vols.StreamIndex]; - if (!s.Stream) - break; - // if (Vols.NeedSeek) - { - result = s.Stream->Seek(0, STREAM_SEEK_SET, NULL); - m_Position = 0; - if (result != S_OK) - break; - Vols.NeedSeek = false; - } - _inBuffer.SetStream(s.Stream); - _inBuffer.Init(); + if (avail != 0) + memmove(Buffer, Buffer + _bufPos, avail); + _bufPos = 0; + _bufCached = avail; } - CanStartNewVol = false; + + const size_t pos = _bufCached; + UInt32 processed = 0; + HRESULT res = Stream->Read(Buffer + pos, (UInt32)(Buffer.Size() - pos), &processed); + _streamPos += processed; + _bufCached += processed; + + if (res != S_OK) + return res; + + if (processed != 0) + continue; + + if ( !IsMultiVol + || !CanStartNewVol + || Vols.StreamIndex < 0 + || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size()) + return S_OK; + + const CVols::CSubStreamInfo &s = Vols.Streams[Vols.StreamIndex + 1]; + if (!s.Stream) + return S_OK; + + RINOK(s.SeekToStart()); + + Vols.StreamIndex++; + _streamPos = 0; + Stream = s.Stream; + // Vols.NeedSeek = false; } +} + + +class CUnexpectEnd {}; + + +/* +---------- SafeRead ---------- + +reads data of exact size from stream(s) - m_Position += processed; - _processedCnt += processed; +in: + _inBufMode + if (CanStartNewVol) it can go to next volume before first byte reading, if there is end of volume data. +in, out: + _streamPos : position in Stream + Stream + Vols : if (IsMultiVol) + _cnt + +out: + (CanStartNewVol == false), if some data was read + +return: + S_OK : success reading of requested data + +exceptions: + CSystemException() - stream reading error + CUnexpectEnd() : could not read data of requested size +*/ + +void CInArchive::SafeRead(Byte *data, unsigned size) +{ + unsigned processed; + HRESULT result = ReadFromCache(data, size, processed); if (result != S_OK) throw CSystemException(result); - - if (processed != size) + if (size != processed) throw CUnexpectEnd(); } void CInArchive::ReadBuffer(CByteBuffer &buffer, unsigned size) { buffer.Alloc(size); - if (size > 0) - SafeReadBytes(buffer, size); + if (size != 0) + SafeRead(buffer, size); } -Byte CInArchive::ReadByte() +// Byte CInArchive::ReadByte () { Byte b; SafeRead(&b, 1); return b; } +// UInt16 CInArchive::ReadUInt16() { Byte buf[2]; SafeRead(buf, 2); return Get16(buf); } +UInt32 CInArchive::ReadUInt32() { Byte buf[4]; SafeRead(buf, 4); return Get32(buf); } +UInt64 CInArchive::ReadUInt64() { Byte buf[8]; SafeRead(buf, 8); return Get64(buf); } + +void CInArchive::ReadSignature() { - Byte b; - SafeReadBytes(&b, 1); - return b; + CanStartNewVol = true; + _signature = ReadUInt32(); + // CanStartNewVol = false; // it's already changed in SafeRead } -UInt16 CInArchive::ReadUInt16() { Byte buf[2]; SafeReadBytes(buf, 2); return Get16(buf); } -UInt32 CInArchive::ReadUInt32() { Byte buf[4]; SafeReadBytes(buf, 4); return Get32(buf); } -UInt64 CInArchive::ReadUInt64() { Byte buf[8]; SafeReadBytes(buf, 8); return Get64(buf); } -// we use Skip() inside headers only, so no need for stream change in multivol. +// we Skip() inside headers only, so no need for stream change in multivol. -void CInArchive::Skip(unsigned num) +void CInArchive::Skip(size_t num) { - if (_inBufMode) - { - size_t skip = _inBuffer.Skip(num); - m_Position += skip; - _processedCnt += skip; - if (skip != num) - throw CUnexpectEnd(); - } - else + while (num != 0) { - for (unsigned i = 0; i < num; i++) - ReadByte(); + const unsigned kBufSize = (size_t)1 << 10; + Byte buf[kBufSize]; + unsigned step = kBufSize; + if (step > num) + step = (unsigned)num; + SafeRead(buf, step); + num -= step; } } -void CInArchive::Skip64(UInt64 num) +/* +HRESULT CInArchive::Callback_Completed(unsigned numFiles) +{ + const UInt64 numFiles64 = numFiles; + return Callback->SetCompleted(&numFiles64, &_cnt); +} +*/ + +HRESULT CInArchive::Skip64(UInt64 num, unsigned numFiles) { - for (UInt64 i = 0; i < num; i++) - ReadByte(); + if (num == 0) + return S_OK; + + for (;;) + { + size_t step = (size_t)1 << 24; + if (step > num) + step = (size_t)num; + Skip(step); + num -= step; + if (num == 0) + return S_OK; + if (Callback) + { + const UInt64 numFiles64 = numFiles; + RINOK(Callback->SetCompleted(&numFiles64, &_cnt)); + } + } } -void CInArchive::ReadFileName(unsigned size, AString &s) +bool CInArchive::ReadFileName(unsigned size, AString &s) { if (size == 0) { s.Empty(); - return; + return true; + } + char *p = s.GetBuf(size); + SafeRead((Byte *)p, size); + unsigned i = size; + do + { + if (p[i - 1] != 0) + break; } - SafeReadBytes(s.GetBuf(size), size); + while (--i); s.ReleaseBuf_CalcLen(size); + return s.Len() == i; } -bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extraBlock, - UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber) +#define ZIP64_IS_32_MAX(n) ((n) == 0xFFFFFFFF) +#define ZIP64_IS_16_MAX(n) ((n) == 0xFFFF) + + +bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extra, + UInt64 &unpackSize, UInt64 &packSize, UInt64 &localOffset, UInt32 &disk) { - extraBlock.Clear(); + extra.Clear(); - UInt32 remain = extraSize; - - while (remain >= 4) + while (extraSize >= 4) { CExtraSubBlock subBlock; - subBlock.ID = ReadUInt16(); - unsigned dataSize = ReadUInt16(); - remain -= 4; - if (dataSize > remain) // it's bug + const UInt32 pair = ReadUInt32(); + subBlock.ID = (pair & 0xFFFF); + unsigned size = (unsigned)(pair >> 16); + + extraSize -= 4; + + if (size > extraSize) { + // it's error in extra HeadersWarning = true; - Skip(remain); + extra.Error = true; + Skip(extraSize); return false; } + + extraSize -= size; + if (subBlock.ID == NFileHeader::NExtraID::kZip64) { - if (unpackSize == 0xFFFFFFFF) - { - if (dataSize < 8) - { - HeadersWarning = true; - Skip(remain); - return false; - } - unpackSize = ReadUInt64(); - remain -= 8; - dataSize -= 8; - } - if (packSize == 0xFFFFFFFF) - { - if (dataSize < 8) - break; - packSize = ReadUInt64(); - remain -= 8; - dataSize -= 8; - } - if (localHeaderOffset == 0xFFFFFFFF) - { - if (dataSize < 8) - break; - localHeaderOffset = ReadUInt64(); - remain -= 8; - dataSize -= 8; - } - if (diskStartNumber == 0xFFFF) + extra.IsZip64 = true; + bool isOK = true; + + 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_16_MAX(disk)) + if (size < 4) isOK = false; else { size -= 4; disk = ReadUInt32(); } + + if (!isOK || size != 0) { - if (dataSize < 4) - break; - diskStartNumber = ReadUInt32(); - remain -= 4; - dataSize -= 4; + HeadersWarning = true; + extra.Error = true; + extra.IsZip64_Error = true; + Skip(size); } - Skip(dataSize); } else { - ReadBuffer(subBlock.Data, dataSize); - extraBlock.SubBlocks.Add(subBlock); + ReadBuffer(subBlock.Data, size); + extra.SubBlocks.Add(subBlock); } - remain -= dataSize; } - if (remain != 0) + if (extraSize != 0) { ExtraMinorError = true; + extra.MinorError = true; // 7-Zip before 9.31 created incorrect WsAES Extra in folder's local headers. // so we don't return false, but just set warning flag // return false; + Skip(extraSize); } - - Skip(remain); + return true; } @@ -691,7 +1047,7 @@ bool CInArchive::ReadLocalItem(CItemEx &item) item.Disk = Vols.StreamIndex; const unsigned kPureHeaderSize = kLocalHeaderSize - 4; Byte p[kPureHeaderSize]; - SafeReadBytes(p, kPureHeaderSize); + SafeRead(p, kPureHeaderSize); { unsigned i; for (i = 0; i < kPureHeaderSize && p[i] == 0; i++); @@ -709,8 +1065,9 @@ bool CInArchive::ReadLocalItem(CItemEx &item) G32(18, item.Size); const unsigned nameSize = Get16(p + 22); const unsigned extraSize = Get16(p + 24); - ReadFileName(nameSize, item.Name); + bool isOkName = ReadFileName(nameSize, item.Name); item.LocalFullHeaderSize = kLocalHeaderSize + (UInt32)nameSize + extraSize; + item.DescriptorWasRead = false; /* if (item.IsDir()) @@ -719,10 +1076,9 @@ bool CInArchive::ReadLocalItem(CItemEx &item) if (extraSize > 0) { - UInt64 localHeaderOffset = 0; - UInt32 diskStartNumber = 0; - if (!ReadExtra(extraSize, item.LocalExtra, item.Size, item.PackSize, - localHeaderOffset, diskStartNumber)) + UInt64 localOffset = 0; + UInt32 disk = 0; + if (!ReadExtra(extraSize, item.LocalExtra, item.Size, item.PackSize, localOffset, disk)) { /* 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. @@ -739,8 +1095,8 @@ bool CInArchive::ReadLocalItem(CItemEx &item) if (item.Name.Len() != nameSize) { - // we support "bad" archives with null-terminated name. - if (item.Name.Len() + 1 != nameSize) + // we support some "bad" zip archives that contain zeros after name + if (!isOkName) return false; HeadersWarning = true; } @@ -758,11 +1114,11 @@ static bool FlagsAreSame(const CItem &i1, const CItem &i2) UInt32 mask = 0xFFFF; switch (i1.Method) { - case NFileHeader::NCompressionMethod::kDeflated: + case NFileHeader::NCompressionMethod::kDeflate: mask = 0x7FF9; break; default: - if (i1.Method <= NFileHeader::NCompressionMethod::kImploded) + if (i1.Method <= NFileHeader::NCompressionMethod::kImplode) mask = 0x7FFF; } @@ -805,9 +1161,9 @@ static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem) return false; if (!localItem.HasDescriptor()) { - if (cdItem.Crc != localItem.Crc || - cdItem.PackSize != localItem.PackSize || - cdItem.Size != localItem.Size) + if (cdItem.PackSize != localItem.PackSize + || cdItem.Size != localItem.Size + || cdItem.Crc != localItem.Crc && cdItem.Crc != 0) // some program writes 0 to crc field in central directory return false; } /* pkzip 2.50 creates incorrect archives. It uses @@ -833,7 +1189,8 @@ static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem) // pkzip 2.50 uses DOS encoding in central dir and WIN encoding in local header. // so we ignore that error if (hostOs != NFileHeader::NHostOS::kFAT - || cdItem.MadeByVersion.Version != 25) + || cdItem.MadeByVersion.Version < 25 + || cdItem.MadeByVersion.Version > 40) return false; } } @@ -847,9 +1204,13 @@ static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem) } -HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail) +HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail, bool &headersError) { + InitBuf(); + _inBufMode = false; + isAvail = true; + headersError = false; if (item.FromLocal) return S_OK; try @@ -863,15 +1224,13 @@ HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail) isAvail = false; return S_FALSE; } - IInStream *str2 = Vols.Streams[item.Disk].Stream; - if (!str2) + Stream = Vols.Streams[item.Disk].Stream; + Vols.StreamIndex = item.Disk; + if (!Stream) { isAvail = false; return S_FALSE; } - RINOK(str2->Seek(offset, STREAM_SEEK_SET, NULL)); - Stream = str2; - Vols.StreamIndex = item.Disk; } else { @@ -888,9 +1247,16 @@ HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail) isAvail = false; return S_FALSE; } - RINOK(Seek(offset)); } + RINOK(Seek_SavePos(offset)); + + /* + // we can check buf mode + InitBuf(); + _inBufMode = true; + Buffer.AllocAtLeast(1 << 10); + */ CItemEx localItem; if (ReadUInt32() != NSignature::kLocalFileHeader) @@ -900,6 +1266,11 @@ HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail) return S_FALSE; item.LocalFullHeaderSize = localItem.LocalFullHeaderSize; item.LocalExtra = localItem.LocalExtra; + if (item.Crc != localItem.Crc && !localItem.HasDescriptor()) + { + item.Crc = localItem.Crc; + headersError = true; + } item.FromLocal = true; } catch(...) { return S_FALSE; } @@ -907,53 +1278,202 @@ HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail) } -HRESULT CInArchive::ReadLocalItemDescriptor(CItemEx &item) +/* +---------- FindDescriptor ---------- + +in: + _streamPos : position in Stream + Stream : + Vols : if (IsMultiVol) + +action: + searches descriptor in input stream(s). + sets + item.DescriptorWasRead = true; + item.Size + item.PackSize + item.Crc + if descriptor was found + +out: + S_OK: + if ( item.DescriptorWasRead) : if descriptor was found + if (!item.DescriptorWasRead) : if descriptor was not found : unexpected end of stream(s) + + S_FALSE: if no items or there is just one item with strange properies that doesn't look like real archive. + + another error code: Callback error. + +exceptions : + CSystemException() : stream reading error +*/ + +HRESULT CInArchive::FindDescriptor(CItemEx &item, unsigned numFiles) { - const unsigned kBufSize = (1 << 12); - Byte buf[kBufSize]; + // const size_t kBufSize = (size_t)1 << 5; // don't increase it too much. It reads data look ahead. + + // Buffer.Alloc(kBufSize); + // Byte *buf = Buffer; - UInt32 numBytesInBuffer = 0; - UInt32 packedSize = 0; + UInt64 packedSize = 0; + UInt64 progressPrev = _cnt; + for (;;) { - UInt32 processedSize; - RINOK(ReadBytes(buf + numBytesInBuffer, kBufSize - numBytesInBuffer, &processedSize)); - numBytesInBuffer += processedSize; - if (numBytesInBuffer < kDataDescriptorSize) - return S_FALSE; + /* appnote specification claims that we must use 64-bit descriptor, if there is zip64 extra. + But some old third-party xps archives used 64-bit descriptor without zip64 extra. */ + // unsigned descriptorSize = kDataDescriptorSize64 + kNextSignatureSize; + + // const unsigned kNextSignatureSize = 0; // we can disable check for next signatuire + const unsigned kNextSignatureSize = 4; // we check also for signature for next File headear + + const unsigned descriptorSize4 = item.GetDescriptorSize() + kNextSignatureSize; + + if (descriptorSize4 > Buffer.Size()) return E_FAIL; + + // size_t processedSize; + CanStartNewVol = true; + RINOK(LookAhead(descriptorSize4)); + const size_t avail = GetAvail(); + + if (avail < descriptorSize4) + { + // we write to packSize all these available bytes. + // later it's simpler to work with such value than with 0 + if (item.PackSize == 0) + item.PackSize = packedSize + avail; + return S_OK; + } + + const Byte * const pStart = Buffer + _bufPos; + const Byte * p = pStart; + const Byte * const limit = pStart + (avail - descriptorSize4); - UInt32 i; - for (i = 0; i <= numBytesInBuffer - kDataDescriptorSize; i++) + for (; p <= limit; p++) { // descriptor signature field is Info-ZIP's extension to pkware Zip specification. // New ZIP specification also allows descriptorSignature. - if (buf[i] != 0x50) + + p = FindPK(p, limit + 1); + if (p > limit) + break; + + /* + if (*p != 0x50) + continue; + */ + + if (Get32(p) != NSignature::kDataDescriptor) continue; - // !!!! It must be fixed for Zip64 archives - if (Get32(buf + i) == NSignature::kDataDescriptor) + + // we check next signatuire after descriptor + // maybe we need check only 2 bytes "PK" instead of 4 bytes, if some another type of header is possible after descriptor + const UInt32 sig = Get32(p + descriptorSize4 - kNextSignatureSize); + if ( sig != NSignature::kLocalFileHeader + && sig != NSignature::kCentralFileHeader) + continue; + + const UInt64 packSizeCur = packedSize + (p - pStart); + if (descriptorSize4 == kDataDescriptorSize64 + kNextSignatureSize) // if (item.LocalExtra.IsZip64) { - UInt32 descriptorPackSize = Get32(buf + i + 8); - if (descriptorPackSize == packedSize + i) - { - item.Crc = Get32(buf + i + 4); - item.PackSize = descriptorPackSize; - item.Size = Get32(buf + i + 12); - bool isFinished; - return IncreaseRealPosition((Int64)(Int32)(0 - (numBytesInBuffer - i - kDataDescriptorSize)), isFinished); - } + const UInt64 descriptorPackSize = Get64(p + 8); + if (descriptorPackSize != packSizeCur) + continue; + item.Size = Get64(p + 16); } + else + { + const UInt32 descriptorPackSize = Get32(p + 8); + if (descriptorPackSize != (UInt32)packSizeCur) + continue; + item.Size = Get32(p + 12); + // that item.Size can be truncated to 32-bit value here + } + // We write calculated 64-bit packSize, even if descriptor64 was not used + item.PackSize = packSizeCur; + + item.DescriptorWasRead = true; + item.Crc = Get32(p + 4); + + const size_t skip = (p - pStart) + descriptorSize4 - kNextSignatureSize; + + SkipLookahed(skip); + + return S_OK; } - packedSize += i; - unsigned j; - for (j = 0; i < numBytesInBuffer; i++, j++) - buf[j] = buf[i]; - numBytesInBuffer = j; + const size_t skip = (p - pStart); + SkipLookahed(skip); + + packedSize += skip; + + if (Callback) + if (_cnt - progressPrev >= ((UInt32)1 << 22)) + { + progressPrev = _cnt; + const UInt64 numFiles64 = numFiles; + RINOK(Callback->SetCompleted(&numFiles64, &_cnt)); + } } } +HRESULT CInArchive::CheckDescriptor(const CItemEx &item) +{ + if (!item.HasDescriptor()) + return S_OK; + + // pkzip's version without descriptor signature is not supported + + bool isFinished = false; + RINOK(IncreaseRealPosition(item.PackSize, isFinished)); + if (isFinished) + return S_FALSE; + + /* + if (!IsMultiVol) + { + RINOK(Seek_SavePos(ArcInfo.Base + item.GetDataPosition() + item.PackSize)); + } + */ + + Byte buf[kDataDescriptorSize64]; + try + { + CanStartNewVol = true; + SafeRead(buf, item.GetDescriptorSize()); + } + catch (const CSystemException &e) { return e.ErrorCode; } + // catch (const CUnexpectEnd &) + catch(...) + { + return S_FALSE; + } + // RINOK(ReadStream_FALSE(Stream, buf, item.GetDescriptorSize())); + + if (Get32(buf) != NSignature::kDataDescriptor) + return S_FALSE; + UInt32 crc = Get32(buf + 4); + UInt64 packSize, unpackSize; + + if (item.LocalExtra.IsZip64) + { + packSize = Get64(buf + 8); + unpackSize = Get64(buf + 16); + } + else + { + packSize = Get32(buf + 8); + unpackSize = Get32(buf + 12); + } + + if (crc != item.Crc || item.PackSize != packSize || item.Size != unpackSize) + return S_FALSE; + return S_OK; +} + + HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item) { if (item.FromLocal) @@ -961,32 +1481,12 @@ HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item) try { bool isAvail = true; - RINOK(ReadLocalItemAfterCdItem(item, isAvail)); + bool headersError = false; + RINOK(ReadLocalItemAfterCdItem(item, isAvail, headersError)); + if (headersError) + return S_FALSE; if (item.HasDescriptor()) - { - // pkzip's version without descriptor is not supported - RINOK(Seek(ArcInfo.Base + item.GetDataPosition() + item.PackSize)); - if (ReadUInt32() != NSignature::kDataDescriptor) - return S_FALSE; - UInt32 crc = ReadUInt32(); - UInt64 packSize, unpackSize; - - /* - if (IsZip64) - { - packSize = ReadUInt64(); - unpackSize = ReadUInt64(); - } - else - */ - { - packSize = ReadUInt32(); - unpackSize = ReadUInt32(); - } - - if (crc != item.Crc || item.PackSize != packSize || item.Size != unpackSize) - return S_FALSE; - } + return CheckDescriptor(item); } catch(...) { return S_FALSE; } return S_OK; @@ -997,7 +1497,7 @@ HRESULT CInArchive::ReadCdItem(CItemEx &item) { item.FromCentral = true; Byte p[kCentralHeaderSize - 4]; - SafeReadBytes(p, kCentralHeaderSize - 4); + SafeRead(p, kCentralHeaderSize - 4); item.MadeByVersion.Version = p[0]; item.MadeByVersion.HostOS = p[1]; @@ -1036,15 +1536,19 @@ HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo) { if (offset >= ((UInt64)1 << 63)) return S_FALSE; - RINOK(Seek(offset)); Byte buf[kEcd64_FullSize]; - RINOK(ReadStream_FALSE(Stream, buf, kEcd64_FullSize)); + RINOK(SeekToVol(Vols.StreamIndex, offset)); + unsigned processed = 0; + ReadFromCache(buf, kEcd64_FullSize, processed); + + if (processed != kEcd64_FullSize) + return S_FALSE; if (Get32(buf) != NSignature::kEcd64) return S_FALSE; UInt64 mainSize = Get64(buf + 4); - if (mainSize < kEcd64_MainSize || mainSize > ((UInt64)1 << 32)) + if (mainSize < kEcd64_MainSize || mainSize > ((UInt64)1 << 40)) return S_FALSE; cdInfo.ParseEcd64e(buf + 12); return S_OK; @@ -1057,27 +1561,49 @@ HRESULT CInArchive::FindCd(bool checkOffsetMode) UInt64 endPos; + // There are no useful data in cache in most cases here. + // So here we don't use cache data from previous operations . + + InitBuf(); RINOK(Stream->Seek(0, STREAM_SEEK_END, &endPos)); + _streamPos = endPos; + + // const UInt32 kBufSizeMax2 = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize; + const size_t kBufSizeMax = ((size_t)1 << 17); // must be larger than kBufSizeMax2 - const UInt32 kBufSizeMax = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize; - const UInt32 bufSize = (endPos < kBufSizeMax) ? (UInt32)endPos : kBufSizeMax; + const size_t bufSize = (endPos < kBufSizeMax) ? (size_t)endPos : kBufSizeMax; if (bufSize < kEcdSize) return S_FALSE; - CByteArr byteBuffer(bufSize); + // CByteArr byteBuffer(bufSize); + + if (Buffer.Size() < kBufSizeMax) + { + // InitBuf(); + Buffer.AllocAtLeast(kBufSizeMax); + if (!Buffer.IsAllocated()) + return E_OUTOFMEMORY; + } - const UInt64 startPos = endPos - bufSize; - RINOK(Stream->Seek(startPos, STREAM_SEEK_SET, &m_Position)); - if (m_Position != startPos) + RINOK(Seek_SavePos(endPos - bufSize)); + + size_t processed = bufSize; + HRESULT res = ReadStream(Stream, Buffer, &processed); + _streamPos += processed; + _bufCached = processed; + _bufPos = 0; + _cnt += processed; + if (res != S_OK) + return res; + if (processed != bufSize) return S_FALSE; + - RINOK(ReadStream_FALSE(Stream, byteBuffer, bufSize)); - - for (UInt32 i = bufSize - kEcdSize + 1;;) + for (size_t i = bufSize - kEcdSize + 1;;) { if (i == 0) return S_FALSE; - const Byte *buf = byteBuffer; + const Byte *buf = Buffer; for (;;) { @@ -1095,24 +1621,26 @@ HRESULT CInArchive::FindCd(bool checkOffsetMode) if (i >= kEcd64Locator_Size) { - const Byte *locatorPtr = buf + i - kEcd64Locator_Size; - if (Get32(locatorPtr) == NSignature::kEcd64Locator) + const size_t locatorIndex = i - kEcd64Locator_Size; + if (Get32(buf + locatorIndex) == NSignature::kEcd64Locator) { CLocator locator; - locator.Parse(locatorPtr + 4); - if ((cdInfo.ThisDisk == locator.NumDisks - 1 || cdInfo.ThisDisk == 0xFFFF) + locator.Parse(buf + locatorIndex + 4); + if ((cdInfo.ThisDisk == locator.NumDisks - 1 || ZIP64_IS_16_MAX(cdInfo.ThisDisk)) && locator.Ecd64Disk < locator.NumDisks) { - if (locator.Ecd64Disk != cdInfo.ThisDisk && cdInfo.ThisDisk != 0xFFFF) + if (locator.Ecd64Disk != cdInfo.ThisDisk && !ZIP64_IS_16_MAX(cdInfo.ThisDisk)) return E_NOTIMPL; // Most of the zip64 use fixed size Zip64 ECD // we try relative backward reading. UInt64 absEcd64 = endPos - bufSize + i - (kEcd64Locator_Size + kEcd64_FullSize); + + if (locatorIndex >= kEcd64_FullSize) if (checkOffsetMode || absEcd64 == locator.Ecd64Offset) { - const Byte *ecd64 = locatorPtr - kEcd64_FullSize; + const Byte *ecd64 = buf + locatorIndex - kEcd64_FullSize; if (Get32(ecd64) == NSignature::kEcd64) { UInt64 mainEcd64Size = Get64(ecd64 + 4); @@ -1193,42 +1721,25 @@ HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdIn { items.Clear(); - ISequentialInStream *stream; - - if (!IsMultiVol) - { - stream = this->StartStream; - Vols.StreamIndex = -1; - RINOK(this->StartStream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position)); - if (m_Position != cdOffset) - return S_FALSE; - } - else - { - if (cdInfo.CdDisk >= Vols.Streams.Size()) - return S_FALSE; - IInStream *str2 = Vols.Streams[cdInfo.CdDisk].Stream; - if (!str2) - return S_FALSE; - RINOK(str2->Seek(cdOffset, STREAM_SEEK_SET, NULL)); - stream = str2; - Vols.NeedSeek = false; - Vols.StreamIndex = cdInfo.CdDisk; - m_Position = cdOffset; - } + RINOK(SeekToVol(IsMultiVol ? cdInfo.CdDisk : -1, cdOffset)); - _inBuffer.SetStream(stream); - - _inBuffer.Init(); _inBufMode = true; + _cnt = 0; - _processedCnt = 0; + if (Callback) + { + RINOK(Callback->SetTotal(&cdInfo.NumEntries, IsMultiVol ? &Vols.TotalBytesSize : NULL)); + } + UInt64 numFileExpected = cdInfo.NumEntries; + const UInt64 *totalFilesPtr = &numFileExpected; + bool isCorrect_NumEntries = (cdInfo.IsFromEcd64 || numFileExpected >= ((UInt32)1 << 16)); - while (_processedCnt < cdSize) + while (_cnt < cdSize) { CanStartNewVol = true; if (ReadUInt32() != NSignature::kCentralFileHeader) return S_FALSE; + CanStartNewVol = false; { CItemEx cdItem; RINOK(ReadCdItem(cdItem)); @@ -1237,13 +1748,24 @@ HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdIn if (Callback && (items.Size() & 0xFFF) == 0) { const UInt64 numFiles = items.Size(); - RINOK(Callback->SetCompleted(&numFiles, NULL)); + + if (numFiles > numFileExpected && totalFilesPtr) + { + if (isCorrect_NumEntries) + totalFilesPtr = NULL; + else + while (numFiles > numFileExpected) + numFileExpected += (UInt32)1 << 16; + RINOK(Callback->SetTotal(totalFilesPtr, NULL)); + } + + RINOK(Callback->SetCompleted(&numFiles, &_cnt)); } } CanStartNewVol = true; - return (_processedCnt == cdSize) ? S_OK : S_FALSE; + return (_cnt == cdSize) ? S_OK : S_FALSE; } @@ -1275,11 +1797,12 @@ HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64 cdOffset = cdInfo.Offset; cdDisk = cdInfo.CdDisk; - if (Callback) + if (!IsMultiVol) { - RINOK(Callback->SetTotal(&cdInfo.NumEntries, NULL)); + if (cdInfo.ThisDisk != cdInfo.CdDisk) + return S_FALSE; } - + const UInt64 base = (IsMultiVol ? 0 : ArcInfo.Base); res = TryReadCd(items, cdInfo, base + cdOffset, cdSize); @@ -1323,47 +1846,83 @@ static bool IsStrangeItem(const CItem &item) } + +/* + ---------- ReadLocals ---------- + +in: + (_signature == NSignature::kLocalFileHeader) + VirtStreamPos : after _signature : position in Stream + Stream : + Vols : if (IsMultiVol) + (_inBufMode == false) + +action: + it parses local items. + + if ( IsMultiVol) it writes absolute offsets to CItemEx::LocalHeaderPos + if (!IsMultiVol) it writes relative (from ArcInfo.Base) offsets to CItemEx::LocalHeaderPos + later we can correct CItemEx::LocalHeaderPos values, if + some new value for ArcInfo.Base will be detected +out: + S_OK: + (_signature != NSignature::kLocalFileHeade) + _streamPos : after _signature + + S_FALSE: if no items or there is just one item with strange properies that doesn't look like real archive. + + another error code: stream reading error or Callback error. + + CUnexpectEnd() exception : it's not fatal exception here. + It means that reading was interrupted by unexpected end of input stream, + but some CItemEx items were parsed OK. + We can stop further archive parsing. + But we can use all filled CItemEx items. +*/ + HRESULT CInArchive::ReadLocals(CObjectVector<CItemEx> &items) { items.Clear(); + + UInt64 progressPrev = _cnt; - while (m_Signature == NSignature::kLocalFileHeader) + if (Callback) + { + RINOK(Callback->SetTotal(NULL, IsMultiVol ? &Vols.TotalBytesSize : NULL)); + } + + while (_signature == NSignature::kLocalFileHeader) { CItemEx item; - item.LocalHeaderPos = m_Position - 4; - if (!IsMultiVol) - item.LocalHeaderPos -= ArcInfo.MarkerPos; - // we write ralative LocalHeaderPos here. Later we can correct it to real Base. + item.LocalHeaderPos = GetVirtStreamPos() - 4; + if (!IsMultiVol) + item.LocalHeaderPos -= ArcInfo.Base; try { ReadLocalItem(item); item.FromLocal = true; bool isFinished = false; - + if (item.HasDescriptor()) - ReadLocalItemDescriptor(item); + { + RINOK(FindDescriptor(item, items.Size())); + isFinished = !item.DescriptorWasRead; + } else { - /* - if (IsMultiVol) - { - const int kStep = 10000; - RINOK(IncreaseRealPosition(-kStep, isFinished)); - RINOK(IncreaseRealPosition(item.PackSize + kStep, isFinished)); - } - else - */ + if (item.PackSize >= ((UInt64)1 << 62)) + throw CUnexpectEnd(); RINOK(IncreaseRealPosition(item.PackSize, isFinished)); } - + items.Add(item); if (isFinished) throw CUnexpectEnd(); - - m_Signature = ReadUInt32(); + + ReadSignature(); } catch (CUnexpectEnd &) { @@ -1372,17 +1931,18 @@ HRESULT CInArchive::ReadLocals(CObjectVector<CItemEx> &items) throw; } - if (Callback && (items.Size() & 0xFF) == 0) + + if (Callback) + if ((items.Size() & 0xFF) == 0 + || _cnt - progressPrev >= ((UInt32)1 << 22)) { + progressPrev = _cnt; const UInt64 numFiles = items.Size(); - UInt64 numBytes = 0; - // if (!sMultiVol) - numBytes = item.LocalHeaderPos; - RINOK(Callback->SetCompleted(&numFiles, &numBytes)); + RINOK(Callback->SetCompleted(&numFiles, &_cnt)); } } - if (items.Size() == 1 && m_Signature != NSignature::kCentralFileHeader) + if (items.Size() == 1 && _signature != NSignature::kCentralFileHeader) if (IsStrangeItem(items[0])) return S_FALSE; @@ -1402,26 +1962,22 @@ HRESULT CVols::ParseArcName(IArchiveOpenVolumeCallback *volCallback) name = prop.bstrVal; } - UString base = name; int dotPos = name.ReverseFind_Dot(); - if (dotPos < 0) return S_OK; - - base.DeleteFrom(dotPos + 1); - const UString ext = name.Ptr(dotPos + 1); + name.DeleteFrom(dotPos + 1); + StartVolIndex = (Int32)(-1); if (ext.IsEmpty()) return S_OK; - else { wchar_t c = ext[0]; IsUpperCase = (c >= 'A' && c <= 'Z'); if (ext.IsEqualTo_Ascii_NoCase("zip")) { - BaseName = base; + BaseName = name; StartIsZ = true; StartIsZip = true; return S_OK; @@ -1429,8 +1985,13 @@ HRESULT CVols::ParseArcName(IArchiveOpenVolumeCallback *volCallback) else if (ext.IsEqualTo_Ascii_NoCase("exe")) { StartIsExe = true; - BaseName = base; + BaseName = name; StartVolIndex = 0; + /* sfx-zip can use both arc.exe and arc.zip + We can open arc.zip, if it was requesed to open arc.exe. + But it's possible that arc.exe and arc.zip are not parts of same archive. + So we can disable such operation */ + return S_FALSE; // don't open arc.zip instead of arc.exe } else if (ext[0] == 'z' || ext[0] == 'Z') { @@ -1441,7 +2002,7 @@ HRESULT CVols::ParseArcName(IArchiveOpenVolumeCallback *volCallback) if (*end != 0 || volNum < 1 || volNum > ((UInt32)1 << 30)) return S_OK; StartVolIndex = volNum - 1; - BaseName = base; + BaseName = name; StartIsZ = true; } else @@ -1449,9 +2010,11 @@ HRESULT CVols::ParseArcName(IArchiveOpenVolumeCallback *volCallback) } UString volName = BaseName; - volName.AddAscii(IsUpperCase ? "ZIP" : "zip"); - HRESULT result = volCallback->GetStream(volName, &ZipStream); - if (result == S_FALSE || !ZipStream) + volName += (IsUpperCase ? "ZIP" : "zip"); + + HRESULT res = volCallback->GetStream(volName, &ZipStream); + + if (res == S_FALSE || !ZipStream) { if (MissingName.IsEmpty()) { @@ -1461,7 +2024,7 @@ HRESULT CVols::ParseArcName(IArchiveOpenVolumeCallback *volCallback) return S_OK; } - return result; + return res; } @@ -1493,24 +2056,30 @@ HRESULT CInArchive::ReadVols2(IArchiveOpenVolumeCallback *volCallback, { UString volName = Vols.BaseName; { - volName += (wchar_t)(Vols.IsUpperCase ? 'Z' : 'z'); + volName += (char)(Vols.IsUpperCase ? 'Z' : 'z'); + unsigned v = i + 1; + if (v < 10) + volName += '0'; + volName.Add_UInt32(v); + } + + HRESULT res = volCallback->GetStream(volName, &stream); + if (res != S_OK && res != S_FALSE) + return res; + if (res == S_FALSE || !stream) + { + if (i == 0) { - char s[32]; - ConvertUInt32ToString(i + 1, s); - unsigned len = (unsigned)strlen(s); - while (len < 2) - { - volName += (wchar_t)'0'; - len++; - } - volName.AddAscii(s); + UString volName_exe = Vols.BaseName; + volName_exe += (Vols.IsUpperCase ? "EXE" : "exe"); + + HRESULT res2 = volCallback->GetStream(volName_exe, &stream); + if (res2 != S_OK && res2 != S_FALSE) + return res2; + res = res2; } } - - HRESULT result = volCallback->GetStream(volName, &stream); - if (result != S_OK && result != S_FALSE) - return result; - if (result == S_FALSE || !stream) + if (res == S_FALSE || !stream) { if (Vols.MissingName.IsEmpty()) Vols.MissingName = volName; @@ -1524,7 +2093,6 @@ HRESULT CInArchive::ReadVols2(IArchiveOpenVolumeCallback *volCallback, } UInt64 size; - UInt64 pos; RINOK(stream->Seek(0, STREAM_SEEK_CUR, &pos)); RINOK(stream->Seek(0, STREAM_SEEK_END, &size)); @@ -1535,6 +2103,8 @@ HRESULT CInArchive::ReadVols2(IArchiveOpenVolumeCallback *volCallback, CVols::CSubStreamInfo &ss = Vols.Streams[i]; Vols.NumVols++; + Vols.TotalBytesSize += size; + ss.Stream = stream; ss.Size = size; @@ -1559,11 +2129,11 @@ HRESULT CInArchive::ReadVols() RINOK(Vols.ParseArcName(volCallback)); - int startZIndex = Vols.StartVolIndex; + // const int startZIndex = Vols.StartVolIndex; if (!Vols.StartIsZ) { - // if (!Vols.StartIsExe) + if (!Vols.StartIsExe) return S_OK; } @@ -1573,35 +2143,46 @@ HRESULT CInArchive::ReadVols() if (Vols.StartIsZip) Vols.ZipStream = StartStream; - // bool cdOK = false; - if (Vols.ZipStream) { Stream = Vols.ZipStream; + + if (Vols.StartIsZip) + Vols.StreamIndex = -1; + else + { + Vols.StreamIndex = -2; + InitBuf(); + } + HRESULT res = FindCd(true); + CCdInfo &ecd = Vols.ecd; if (res == S_OK) { zipDisk = ecd.ThisDisk; Vols.ecd_wasRead = true; + + // if is not multivol or bad multivol, we return to main single stream code if (ecd.ThisDisk == 0 || ecd.ThisDisk >= ((UInt32)1 << 30) || ecd.ThisDisk < ecd.CdDisk) return S_OK; + cdDisk = ecd.CdDisk; if (Vols.StartVolIndex < 0) Vols.StartVolIndex = ecd.ThisDisk; + else if ((UInt32)Vols.StartVolIndex >= ecd.ThisDisk) + return S_OK; + // Vols.StartVolIndex = ecd.ThisDisk; // Vols.EndVolIndex = ecd.ThisDisk; unsigned numMissingVols; - if (cdDisk == zipDisk) - { - // cdOK = true; - } - else + if (cdDisk != zipDisk) { + // get volumes required for cd. RINOK(ReadVols2(volCallback, cdDisk, zipDisk, zipDisk, 0, numMissingVols)); - if (numMissingVols == 0) + if (numMissingVols != 0) { // cdOK = false; } @@ -1611,25 +2192,50 @@ HRESULT CInArchive::ReadVols() return res; } - if (Vols.Streams.Size() > 0) - IsMultiVol = true; - if (Vols.StartVolIndex < 0) + { + // is not mutivol; return S_OK; + } + /* + if (!Vols.Streams.IsEmpty()) + IsMultiVol = true; + */ + unsigned numMissingVols; if (cdDisk != 0) { - RINOK(ReadVols2(volCallback, 0, cdDisk < 0 ? -1 : cdDisk, zipDisk, 1 << 10, numMissingVols)); + // get volumes that were no requested still + const unsigned kNumMissingVolsMax = 1 << 12; + RINOK(ReadVols2(volCallback, 0, cdDisk < 0 ? -1 : cdDisk, zipDisk, kNumMissingVolsMax, numMissingVols)); + } + + // if (Vols.StartVolIndex >= 0) + { + if (Vols.Streams.IsEmpty()) + if (Vols.StartVolIndex > (1 << 20)) + return S_OK; + if ((unsigned)Vols.StartVolIndex >= Vols.Streams.Size() + || !Vols.Streams[Vols.StartVolIndex].Stream) + { + // we get volumes starting from StartVolIndex, if they we not requested before know the volume index (if FindCd() was ok) + RINOK(ReadVols2(volCallback, Vols.StartVolIndex, zipDisk, zipDisk, 0, numMissingVols)); + } } if (Vols.ZipStream) { + // if there is no another volumes and volumeIndex is too big, we don't use multivol mode if (Vols.Streams.IsEmpty()) if (zipDisk > (1 << 10)) return S_OK; - RINOK(ReadVols2(volCallback, zipDisk, zipDisk + 1, zipDisk, 0, numMissingVols)); + if (zipDisk >= 0) + { + // we create item in Streams for ZipStream, if we know the volume index (if FindCd() was ok) + RINOK(ReadVols2(volCallback, zipDisk, zipDisk + 1, zipDisk, 0, numMissingVols)); + } } if (!Vols.Streams.IsEmpty()) @@ -1639,11 +2245,14 @@ HRESULT CInArchive::ReadVols() if (cdDisk) IsMultiVol = true; */ + const int startZIndex = Vols.StartVolIndex; if (startZIndex >= 0) { - if (Vols.Streams.Size() >= (unsigned)startZIndex) + // if all volumes before start volume are OK, we can start parsing from 0 + // if there are missing volumes before startZIndex, we start parsing in current startZIndex + if ((unsigned)startZIndex < Vols.Streams.Size()) { - for (unsigned i = 0; i < (unsigned)startZIndex; i++) + for (unsigned i = 0; i <= (unsigned)startZIndex; i++) if (!Vols.Streams[i].Stream) { Vols.StartParsingVol = startZIndex; @@ -1658,10 +2267,6 @@ HRESULT CInArchive::ReadVols() - - - - HRESULT CVols::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) @@ -1680,7 +2285,7 @@ HRESULT CVols::Read(void *data, UInt32 size, UInt32 *processedSize) return S_FALSE; if (NeedSeek) { - RINOK(s.Stream->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(s.SeekToStart()); NeedSeek = false; } UInt32 realProcessedSize = 0; @@ -1704,47 +2309,112 @@ STDMETHODIMP CVolStream::Read(void *data, UInt32 size, UInt32 *processedSize) -#define COPY_ECD_ITEM_16(n) if (!isZip64 || ecd. n != 0xFFFF) ecd64. n = ecd. n; -#define COPY_ECD_ITEM_32(n) if (!isZip64 || ecd. n != 0xFFFFFFFF) ecd64. n = ecd. n; +#define COPY_ECD_ITEM_16(n) if (!isZip64 || !ZIP64_IS_16_MAX(ecd. n)) cdInfo. n = ecd. n; +#define COPY_ECD_ITEM_32(n) if (!isZip64 || !ZIP64_IS_32_MAX(ecd. n)) cdInfo. n = ecd. n; -HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items) +HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items) { + if (Buffer.Size() < kSeqBufferSize) + { + InitBuf(); + Buffer.AllocAtLeast(kSeqBufferSize); + if (!Buffer.IsAllocated()) + return E_OUTOFMEMORY; + } + + _inBufMode = false; + HRESULT res = S_OK; bool localsWereRead = false; - UInt64 cdSize = 0, cdRelatOffset = 0, cdAbsOffset = 0; + + /* we try to open archive with the following modes: + 1) CD-MODE : fast mode : we read backward ECD and CD, compare CD items with first Local item. + 2) LOCALS-CD-MODE : slow mode, if CD-MODE fails : we sequentially read all Locals and then CD. + Then we read sequentially ECD64, Locator, ECD again at the end. + + - in LOCALS-CD-MODE we use use the following + variables (with real cd properties) to set Base archive offset + and check real cd properties with values from ECD/ECD64. + */ + + UInt64 cdSize = 0; + UInt64 cdRelatOffset = 0; UInt32 cdDisk = 0; - if (!_inBuffer.Create(1 << 15)) - return E_OUTOFMEMORY; + UInt64 cdAbsOffset = 0; // absolute cd offset, for LOCALS-CD-MODE only. - if (!MarkerIsFound) + if (!MarkerIsFound || !MarkerIsSafe) { IsArc = true; res = ReadCd(items, cdDisk, cdRelatOffset, cdSize); if (res == S_OK) - m_Signature = ReadUInt32(); + ReadSignature(); + else if (res != S_FALSE) + return res; } else { - // m_Signature must be kLocalFileHeader or kEcd - // m_Position points to next byte after signature - RINOK(Stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); + // _signature must be kLocalFileHeader or kEcd or kEcd64 + + SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2 + 4); + + CanStartNewVol = false; + + if (_signature == NSignature::kEcd64) + { + // UInt64 ecd64Offset = GetVirtStreamPos() - 4; + IsZip64 = true; - _inBuffer.SetStream(Stream); + { + const UInt64 recordSize = ReadUInt64(); + if (recordSize < kEcd64_MainSize) + return S_FALSE; + if (recordSize >= ((UInt64)1 << 62)) + return S_FALSE; + + { + const unsigned kBufSize = kEcd64_MainSize; + Byte buf[kBufSize]; + SafeRead(buf, kBufSize); + CCdInfo cdInfo; + cdInfo.ParseEcd64e(buf); + if (!cdInfo.IsEmptyArc()) + return S_FALSE; + } + + RINOK(Skip64(recordSize - kEcd64_MainSize, 0)); + } + + ReadSignature(); + if (_signature != NSignature::kEcd64Locator) + return S_FALSE; - bool needReadCd = true; + { + const unsigned kBufSize = 16; + Byte buf[kBufSize]; + SafeRead(buf, kBufSize); + CLocator locator; + locator.Parse(buf); + if (!locator.IsEmptyArc()) + return S_FALSE; + } - if (m_Signature == NSignature::kEcd) + ReadSignature(); + if (_signature != NSignature::kEcd) + return S_FALSE; + } + + if (_signature == NSignature::kEcd) { // It must be empty archive or backware archive // we don't support backware archive still const unsigned kBufSize = kEcdSize - 4; Byte buf[kBufSize]; - SafeReadBytes(buf, kBufSize); + SafeRead(buf, kBufSize); CEcd ecd; ecd.Parse(buf); // if (ecd.cdSize != 0) @@ -1753,15 +2423,15 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items) return S_FALSE; ArcInfo.Base = ArcInfo.MarkerPos; - needReadCd = false; IsArc = true; // check it: we need more tests? - RINOK(Stream->Seek(ArcInfo.MarkerPos2 + 4, STREAM_SEEK_SET, &m_Position)); - } - if (needReadCd) + RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2)); + ReadSignature(); + } + else { CItemEx firstItem; - // try + try { try { @@ -1776,9 +2446,10 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items) IsArc = true; res = ReadCd(items, cdDisk, cdRelatOffset, cdSize); if (res == S_OK) - m_Signature = ReadUInt32(); + ReadSignature(); } - // catch() { res = S_FALSE; } + catch(CUnexpectEnd &) { res = S_FALSE; } + if (res != S_FALSE && res != S_OK) return res; @@ -1812,52 +2483,93 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items) CObjectVector<CItemEx> cdItems; - bool needSetBase = false; + bool needSetBase = false; // we set needSetBase only for LOCALS_CD_MODE unsigned numCdItems = items.Size(); - if (res == S_FALSE) + #ifdef ZIP_SELF_CHECK + res = S_FALSE; // if uncommented, it uses additional LOCALS-CD-MODE mode to check the code + #endif + + if (res != S_OK) { + // ---------- LOCALS-CD-MODE ---------- // CD doesn't match firstItem, - // so we clear items and read Locals. + // so we clear items and read Locals and CD. + items.Clear(); localsWereRead = true; + + // we can use any mode: with buffer and without buffer + // without buffer : skips packed data : fast for big files : slow for small files + // with buffer : reads packed data : slow for big files : fast for small files + _inBufMode = false; - ArcInfo.Base = ArcInfo.MarkerPos; + // _inBufMode = true; - if (IsMultiVol) + InitBuf(); + + ArcInfo.Base = 0; + + if (!MarkerIsFound) { - Vols.StreamIndex = Vols.StartParsingVol; - if (Vols.StartParsingVol >= (int)Vols.Streams.Size()) + if (!IsMultiVol) return S_FALSE; - Stream = Vols.Streams[Vols.StartParsingVol].Stream; - if (!Stream) + if (Vols.StartParsingVol != 0) return S_FALSE; + // if (StartParsingVol == 0) and we didn't find marker, we use default zero marker. + // so we suppose that there is no sfx stub + RINOK(SeekToVol(0, ArcInfo.MarkerPos2)); } + else + { + if (ArcInfo.MarkerPos != 0) + { + /* + If multi-vol or there is (No)Span-marker at start of stream, we set (Base) as 0. + In another caes: + (No)Span-marker is supposed as false positive. So we set (Base) as main marker (MarkerPos2). + The (Base) can be corrected later after ECD reading. + But sfx volume with stub and (No)Span-marker in (!IsMultiVol) mode will have incorrect (Base) here. + */ + ArcInfo.Base = ArcInfo.MarkerPos2; + } + + RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2)); + } + + _cnt = 0; - RINOK(Stream->Seek(ArcInfo.MarkerPos2, STREAM_SEEK_SET, &m_Position)); - m_Signature = ReadUInt32(); + ReadSignature(); + LocalsWereRead = true; + RINOK(ReadLocals(items)); - if (m_Signature != NSignature::kCentralFileHeader) + if (_signature != NSignature::kCentralFileHeader) { - // if (!UnexpectedEnd) - m_Position -= 4; + // GetVirtStreamPos() - 4 + if (items.IsEmpty()) + return S_FALSE; NoCentralDir = true; HeadersError = true; return S_OK; } _inBufMode = true; - _inBuffer.Init(); - - cdAbsOffset = m_Position - 4; + + cdAbsOffset = GetVirtStreamPos() - 4; cdDisk = Vols.StreamIndex; + #ifdef ZIP_SELF_CHECK + if (!IsMultiVol && _cnt != GetVirtStreamPos() - ArcInfo.MarkerPos2) + return E_FAIL; + #endif + + const UInt64 processedCnt_start = _cnt; + for (;;) { CItemEx cdItem; - CanStartNewVol = true; RINOK(ReadCdItem(cdItem)); @@ -1865,17 +2577,29 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items) if (Callback && (cdItems.Size() & 0xFFF) == 0) { const UInt64 numFiles = items.Size(); - RINOK(Callback->SetCompleted(&numFiles, NULL)); + const UInt64 numBytes = _cnt; + RINOK(Callback->SetCompleted(&numFiles, &numBytes)); } - CanStartNewVol = true; - m_Signature = ReadUInt32(); - if (m_Signature != NSignature::kCentralFileHeader) + ReadSignature(); + if (_signature != NSignature::kCentralFileHeader) break; } - cdSize = (m_Position - 4) - cdAbsOffset; + cdSize = _cnt - processedCnt_start; + + #ifdef ZIP_SELF_CHECK + if (!IsMultiVol) + { + if (_cnt != GetVirtStreamPos() - ArcInfo.MarkerPos2) + return E_FAIL; + if (cdSize != (GetVirtStreamPos() - 4) - cdAbsOffset) + return E_FAIL; + } + #endif + needSetBase = true; numCdItems = cdItems.Size(); + cdRelatOffset = cdAbsOffset - ArcInfo.Base; if (!cdItems.IsEmpty()) { @@ -1886,13 +2610,13 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items) - CCdInfo ecd64; + CCdInfo cdInfo; CLocator locator; bool isZip64 = false; - const UInt64 ecd64AbsOffset = m_Position - 4; + const UInt64 ecd64AbsOffset = GetVirtStreamPos() - 4; int ecd64Disk = -1; - if (m_Signature == NSignature::kEcd64) + if (_signature == NSignature::kEcd64) { ecd64Disk = Vols.StreamIndex; @@ -1900,26 +2624,27 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items) { const UInt64 recordSize = ReadUInt64(); - if (recordSize < kEcd64_MainSize) + if (recordSize < kEcd64_MainSize + || recordSize >= ((UInt64)1 << 62)) { HeadersError = true; return S_OK; } - + { const unsigned kBufSize = kEcd64_MainSize; Byte buf[kBufSize]; - SafeReadBytes(buf, kBufSize); - ecd64.ParseEcd64e(buf); + SafeRead(buf, kBufSize); + cdInfo.ParseEcd64e(buf); } - Skip64(recordSize - kEcd64_MainSize); + RINOK(Skip64(recordSize - kEcd64_MainSize, items.Size())); } - m_Signature = ReadUInt32(); + ReadSignature(); - if (m_Signature != NSignature::kEcd64Locator) + if (_signature != NSignature::kEcd64Locator) { HeadersError = true; return S_OK; @@ -1928,28 +2653,30 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items) { const unsigned kBufSize = 16; Byte buf[kBufSize]; - SafeReadBytes(buf, kBufSize); + SafeRead(buf, kBufSize); locator.Parse(buf); } - m_Signature = ReadUInt32(); + ReadSignature(); } - if (m_Signature != NSignature::kEcd) + if (_signature != NSignature::kEcd) { HeadersError = true; return S_OK; } + CanStartNewVol = false; + // ---------- ECD ---------- CEcd ecd; { const unsigned kBufSize = kEcdSize - 4; Byte buf[kBufSize]; - SafeReadBytes(buf, kBufSize); + SafeRead(buf, kBufSize); ecd.Parse(buf); } @@ -1960,34 +2687,103 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items) COPY_ECD_ITEM_32(Size); COPY_ECD_ITEM_32(Offset); + bool cdOK = true; + + if ((UInt32)cdInfo.Size != (UInt32)cdSize) + { + // return S_FALSE; + cdOK = false; + } + + if (isZip64) + { + if (cdInfo.NumEntries != numCdItems + || cdInfo.Size != cdSize) + { + cdOK = false; + } + } + + if (IsMultiVol) { - if (cdDisk != (int)ecd64.CdDisk) + if (cdDisk != (int)cdInfo.CdDisk) HeadersError = true; } - else if (needSetBase) + else if (needSetBase && cdOK) { + const UInt64 oldBase = ArcInfo.Base; + // localsWereRead == true + // ArcInfo.Base == ArcInfo.MarkerPos2 + // cdRelatOffset == (cdAbsOffset - ArcInfo.Base) + if (isZip64) { if (ecd64Disk == Vols.StartVolIndex) { - ArcInfo.Base = ecd64AbsOffset - locator.Ecd64Offset; - // cdRelatOffset = ecd64.Offset; - needSetBase = false; + const Int64 newBase = (Int64)ecd64AbsOffset - locator.Ecd64Offset; + if (newBase <= (Int64)ecd64AbsOffset) + { + if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2) + { + ArcInfo.Base = newBase; + cdRelatOffset = cdAbsOffset - newBase; + } + else + cdOK = false; + } } } - else + else if (numCdItems != 0) // we can't use ecd.Offset in empty archive? { if ((int)cdDisk == Vols.StartVolIndex) { - ArcInfo.Base = cdAbsOffset - ecd64.Offset; - cdRelatOffset = ecd64.Offset; - needSetBase = false; + const Int64 newBase = (Int64)cdAbsOffset - cdInfo.Offset; + if (newBase <= (Int64)cdAbsOffset) + { + if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2) + { + // cd can be more accurate, when it points before Locals + // so we change Base and cdRelatOffset + ArcInfo.Base = newBase; + cdRelatOffset = cdInfo.Offset; + } + else + { + // const UInt64 delta = ((UInt64)cdRelatOffset - cdInfo.Offset); + const UInt64 delta = ((UInt64)(newBase - ArcInfo.Base)); + if ((UInt32)delta == 0) + { + // we set Overflow32bit mode, only if there is (x<<32) offset + // between real_CD_offset_from_MarkerPos and CD_Offset_in_ECD. + // Base and cdRelatOffset unchanged + Overflow32bit = true; + } + else + cdOK = false; + } + } + else + cdOK = false; + } + } + // cdRelatOffset = cdAbsOffset - ArcInfo.Base; + + if (localsWereRead) + { + const UInt64 delta = oldBase - ArcInfo.Base; + if (delta != 0) + { + FOR_VECTOR (i, items) + items[i].LocalHeaderPos += delta; } } } - EcdVolIndex = ecd64.ThisDisk; + if (!cdOK) + HeadersError = true; + + EcdVolIndex = cdInfo.ThisDisk; if (!IsMultiVol) { @@ -1997,54 +2793,80 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items) Vols.MissingZip = false; } - UseDisk_in_SingleVol = true; - if (localsWereRead) { - if ((UInt64)ArcInfo.Base != ArcInfo.MarkerPos) - { - const UInt64 delta = ArcInfo.MarkerPos - ArcInfo.Base; - FOR_VECTOR (i, items) - items[i].LocalHeaderPos += delta; - } - if (EcdVolIndex != 0) { FOR_VECTOR (i, items) items[i].Disk = EcdVolIndex; } } + + UseDisk_in_SingleVol = true; } if (isZip64) { - if (ecd64.ThisDisk == 0 && ecd64AbsOffset != ArcInfo.Base + locator.Ecd64Offset - // || ecd64.NumEntries_in_ThisDisk != numCdItems - || ecd64.NumEntries != numCdItems - || ecd64.Size != cdSize - || (ecd64.Offset != cdRelatOffset && !items.IsEmpty())) + if (cdInfo.ThisDisk == 0 && ecd64AbsOffset != ArcInfo.Base + locator.Ecd64Offset + // || cdInfo.NumEntries_in_ThisDisk != numCdItems + || cdInfo.NumEntries != numCdItems + || cdInfo.Size != cdSize + || (cdInfo.Offset != cdRelatOffset && !items.IsEmpty())) { HeadersError = true; return S_OK; } } - // ---------- merge Central Directory Items ---------- - - if (!cdItems.IsEmpty()) + if (cdOK && !cdItems.IsEmpty()) { - CObjectVector<CItemEx> items2; + // ---------- merge Central Directory Items ---------- + + CRecordVector<unsigned> items2; + + int nextLocalIndex = 0; + + LocalsCenterMerged = true; FOR_VECTOR (i, cdItems) { + if (Callback) + if ((i & 0x3FFF) == 0) + { + const UInt64 numFiles64 = items.Size() + items2.Size(); + RINOK(Callback->SetCompleted(&numFiles64, &_cnt)); + } + const CItemEx &cdItem = cdItems[i]; - int index = FindItem(items, cdItem); + + int index = -1; + + if (nextLocalIndex != -1) + { + if ((unsigned)nextLocalIndex < items.Size()) + { + CItemEx &item = items[nextLocalIndex]; + if (item.Disk == cdItem.Disk && + (item.LocalHeaderPos == cdItem.LocalHeaderPos + || Overflow32bit && (UInt32)item.LocalHeaderPos == cdItem.LocalHeaderPos)) + index = nextLocalIndex++; + else + nextLocalIndex = -1; + } + } + + if (index == -1) + index = FindItem(items, cdItem); + + // index = -1; + if (index == -1) { - items2.Add(cdItem); + items2.Add(i); HeadersError = true; continue; } + CItemEx &item = items[index]; if (item.Name != cdItem.Name // || item.Name.Len() != cdItem.Name.Len() @@ -2067,10 +2889,10 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items) item.FromCentral = cdItem.FromCentral; } - items += items2; + FOR_VECTOR (k, items2) + items.Add(cdItems[items2[k]]); } - if (ecd.NumEntries < ecd.NumEntries_in_ThisDisk) HeadersError = true; @@ -2083,35 +2905,56 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items) } } - if (ecd.NumEntries > items.Size()) - HeadersError = true; - if (isZip64) { - if (ecd64.NumEntries != items.Size()) + if (cdInfo.NumEntries != items.Size() + || ecd.NumEntries != items.Size() && ecd.NumEntries != 0xFFFF) HeadersError = true; } else { // old 7-zip could store 32-bit number of CD items to 16-bit field. - /* - if ((UInt16)ecd64.NumEntries == (UInt16)items.Size()) + // if (ecd.NumEntries != items.Size()) + if (ecd.NumEntries > items.Size()) HeadersError = true; - */ + + if (cdInfo.NumEntries != numCdItems) + { + if ((UInt16)cdInfo.NumEntries != (UInt16)numCdItems) + HeadersError = true; + else + Cd_NumEntries_Overflow_16bit = true; + } } ReadBuffer(ArcInfo.Comment, ecd.CommentSize); + _inBufMode = false; - _inBuffer.Free(); - if ((UInt16)ecd64.NumEntries != (UInt16)numCdItems - || (UInt32)ecd64.Size != (UInt32)cdSize - || ((UInt32)ecd64.Offset != (UInt32)cdRelatOffset && !items.IsEmpty())) + // DisableBufMode(); + // Buffer.Free(); + /* we can't clear buf varibles. we need them to calculate PhySize of archive */ + + if ((UInt16)cdInfo.NumEntries != (UInt16)numCdItems + || (UInt32)cdInfo.Size != (UInt32)cdSize + || ((UInt32)cdInfo.Offset != (UInt32)cdRelatOffset && !items.IsEmpty())) { // return S_FALSE; HeadersError = true; } - + + #ifdef ZIP_SELF_CHECK + if (localsWereRead) + { + const UInt64 endPos = ArcInfo.MarkerPos2 + _cnt; + if (endPos != (IsMultiVol ? Vols.TotalBytesSize : ArcInfo.FileEndPos)) + { + // there are some data after the end of archive or error in code; + return E_FAIL; + } + } + #endif + // printf("\nOpen OK"); return S_OK; } @@ -2121,40 +2964,47 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items) HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, IArchiveOpenCallback *callback, CObjectVector<CItemEx> &items) { - _inBufMode = false; items.Clear(); Close(); - ArcInfo.Clear(); UInt64 startPos; RINOK(stream->Seek(0, STREAM_SEEK_CUR, &startPos)); RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileEndPos)); - m_Position = ArcInfo.FileEndPos; + _streamPos = ArcInfo.FileEndPos; StartStream = stream; + Stream = stream; Callback = callback; + + DisableBufMode(); bool volWasRequested = false; if (callback && (startPos == 0 || !searchLimit || *searchLimit != 0)) { + // we try to read volumes only if it's first call (offset == 0) or scan is allowed. volWasRequested = true; RINOK(ReadVols()); } - if (IsMultiVol && Vols.StartVolIndex != 0) + if (IsMultiVol && Vols.StartParsingVol == 0 && (unsigned)Vols.StartParsingVol < Vols.Streams.Size()) { - Stream = Vols.Streams[0].Stream; - if (Stream) + // only StartParsingVol = 0 is safe search. + RINOK(SeekToVol(0, 0)); + // if (Stream) { - m_Position = 0; - RINOK(Stream->Seek(0, STREAM_SEEK_SET, NULL)); - UInt64 limit = 0; - HRESULT res = FindMarker(Stream, &limit); + // UInt64 limit = 1 << 22; // for sfx + UInt64 limit = 0; // without sfx + + HRESULT res = FindMarker(&limit); + if (res == S_OK) + { MarkerIsFound = true; + MarkerIsSafe = true; + } else if (res != S_FALSE) return res; } @@ -2162,56 +3012,93 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, else { // printf("\nOpen offset = %u\n", (unsigned)startPos); - RINOK(stream->Seek(startPos, STREAM_SEEK_SET, NULL)); - m_Position = startPos; - HRESULT res = FindMarker(stream, searchLimit); - UInt64 curPos = m_Position; + if (IsMultiVol && (unsigned)Vols.StartParsingVol < Vols.Streams.Size() && Vols.Streams[Vols.StartParsingVol].Stream) + { + RINOK(SeekToVol(Vols.StartParsingVol, Vols.StreamIndex == Vols.StartVolIndex ? startPos : 0)); + } + else + { + RINOK(SeekToVol(-1, startPos)); + } + + // UInt64 limit = 1 << 22; + // HRESULT res = FindMarker(&limit); + + HRESULT res = FindMarker(searchLimit); + + // const UInt64 curPos = GetVirtStreamPos(); + const UInt64 curPos = ArcInfo.MarkerPos2 + 4; + if (res == S_OK) MarkerIsFound = true; - else + else if (!IsMultiVol) { - // if (res != S_FALSE) + /* + // if (startPos != 0), probably CD copuld be already tested with another call with (startPos == 0). + // so we don't want to try to open CD again in that ase. + if (startPos != 0) + return res; + // we can try to open CD, if there is no Marker and (startPos == 0). + // is it OK to open such files as ZIP, or big number of false positive, when CD can be find in end of file ? + */ return res; } - - MarkerIsFound = true; if (ArcInfo.IsSpanMode && !volWasRequested) { RINOK(ReadVols()); + if (IsMultiVol && MarkerIsFound && ArcInfo.MarkerVolIndex < 0) + ArcInfo.MarkerVolIndex = Vols.StartVolIndex; } + + MarkerIsSafe = !IsMultiVol + || (ArcInfo.MarkerVolIndex == 0 && ArcInfo.MarkerPos == 0) + ; - if (IsMultiVol && (unsigned)Vols.StartVolIndex < Vols.Streams.Size()) + + if (IsMultiVol) { - Stream = Vols.Streams[Vols.StartVolIndex].Stream; - if (!Stream) - IsMultiVol = false; - else + if ((unsigned)Vols.StartVolIndex < Vols.Streams.Size()) { - RINOK(Stream->Seek(curPos, STREAM_SEEK_SET, NULL)); - m_Position = curPos; + Stream = Vols.Streams[Vols.StartVolIndex].Stream; + if (Stream) + { + RINOK(Seek_SavePos(curPos)); + } + else + IsMultiVol = false; } + else + IsMultiVol = false; } - else - IsMultiVol = false; if (!IsMultiVol) { - RINOK(stream->Seek(curPos, STREAM_SEEK_SET, NULL)); - m_Position = curPos; + if (Vols.StreamIndex != -1) + { + Stream = StartStream; + Vols.StreamIndex = -1; + InitBuf(); + RINOK(Seek_SavePos(curPos)); + } + + ArcInfo.MarkerVolIndex = -1; StreamRef = stream; Stream = stream; } } + if (!IsMultiVol) + Vols.ClearRefs(); + { HRESULT res; try { - res = ReadHeaders2(items); + res = ReadHeaders(items); } - catch (const CInBufferException &e) { res = e.ErrorCode; } + catch (const CSystemException &e) { res = e.ErrorCode; } catch (const CUnexpectEnd &) { if (items.IsEmpty()) @@ -2221,7 +3108,7 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, } catch (...) { - _inBufMode = false; + DisableBufMode(); throw; } @@ -2229,16 +3116,17 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, { ArcInfo.FinishPos = ArcInfo.FileEndPos; if ((unsigned)Vols.StreamIndex < Vols.Streams.Size()) - if (m_Position < Vols.Streams[Vols.StreamIndex].Size) + if (GetVirtStreamPos() < Vols.Streams[Vols.StreamIndex].Size) ArcInfo.ThereIsTail = true; } else { - ArcInfo.FinishPos = m_Position; - ArcInfo.ThereIsTail = (ArcInfo.FileEndPos > m_Position); + ArcInfo.FinishPos = GetVirtStreamPos(); + ArcInfo.ThereIsTail = (ArcInfo.FileEndPos > ArcInfo.FinishPos); } - _inBufMode = false; + DisableBufMode(); + IsArcOpen = true; if (!IsMultiVol) Vols.Streams.Clear(); diff --git a/CPP/7zip/Archive/Zip/ZipIn.h b/CPP/7zip/Archive/Zip/ZipIn.h index 9b0afe28..a312c36a 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.h +++ b/CPP/7zip/Archive/Zip/ZipIn.h @@ -3,12 +3,11 @@ #ifndef __ZIP_IN_H #define __ZIP_IN_H +#include "../../../Common/MyBuffer2.h" #include "../../../Common/MyCom.h" #include "../../IStream.h" -#include "../../Common/InBuffer.h" - #include "ZipHeader.h" #include "ZipItem.h" @@ -22,8 +21,12 @@ class CItemEx: public CItem public: UInt32 LocalFullHeaderSize; // including Name and Extra + bool DescriptorWasRead; + + CItemEx(): DescriptorWasRead(false) {} + UInt64 GetLocalFullSize() const - { return LocalFullHeaderSize + PackSize + (HasDescriptor() ? kDataDescriptorSize : 0); } + { return LocalFullHeaderSize + GetPackSizeWithDescriptor(); } UInt64 GetDataPosition() const { return LocalHeaderPos + LocalFullHeaderSize; } }; @@ -52,6 +55,10 @@ struct CInArchiveInfo UInt64 FirstItemRelatOffset; /* Relative offset of first local (read from cd) (relative to Base). = 0 in most archives = size of stub for some SFXs */ + + + int MarkerVolIndex; + bool CdWasRead; bool IsSpanMode; bool ThereIsTail; @@ -68,6 +75,7 @@ struct CInArchiveInfo FinishPos(0), FileEndPos(0), FirstItemRelatOffset(0), + MarkerVolIndex(-1), CdWasRead(false), IsSpanMode(false), ThereIsTail(false) @@ -82,6 +90,7 @@ struct CInArchiveInfo MarkerPos2 = 0; FinishPos = 0; FileEndPos = 0; + MarkerVolIndex = -1; ThereIsTail = false; FirstItemRelatOffset = 0; @@ -96,6 +105,10 @@ struct CInArchiveInfo struct CCdInfo { + bool IsFromEcd64; + + UInt16 CommentSize; + // 64 UInt16 VersionMade; UInt16 VersionNeedExtract; @@ -108,39 +121,55 @@ struct CCdInfo UInt64 Size; UInt64 Offset; - UInt16 CommentSize; - - CCdInfo() { memset(this, 0, sizeof(*this)); } + CCdInfo() { memset(this, 0, sizeof(*this)); IsFromEcd64 = false; } void ParseEcd32(const Byte *p); // (p) includes signature void ParseEcd64e(const Byte *p); // (p) exclude signature + + bool IsEmptyArc() const + { + return ThisDisk == 0 + && CdDisk == 0 + && NumEntries_in_ThisDisk == 0 + && NumEntries == 0 + && Size == 0 + && Offset == 0 // test it + ; + } }; -class CVols +struct CVols { -public: - struct CSubStreamInfo { CMyComPtr<IInStream> Stream; UInt64 Size; + HRESULT SeekToStart() const { return Stream->Seek(0, STREAM_SEEK_SET, NULL); } + CSubStreamInfo(): Size(0) {} }; CObjectVector<CSubStreamInfo> Streams; - int StreamIndex; + + int StreamIndex; // -1 for StartStream + // -2 for ZipStream at multivol detection code + // >=0 volume index in multivol + bool NeedSeek; - CMyComPtr<IInStream> ZipStream; - bool StartIsExe; // is .exe bool StartIsZ; // is .zip or .zNN bool StartIsZip; // is .zip bool IsUpperCase; bool MissingZip; - Int32 StartVolIndex; // = (NN - 1), if StartStream is .zNN + + bool ecd_wasRead; + + Int32 StartVolIndex; // -1, if unknown vol index + // = (NN - 1), if StartStream is .zNN + // = 0, if start vol is exe Int32 StartParsingVol; // if we need local parsing, we must use that stream unsigned NumVols; @@ -148,19 +177,27 @@ public: int EndVolIndex; // index of last volume (ecd volume), // -1, if is not multivol - UString BaseName; // including '.' - + UString BaseName; // name of archive including '.' UString MissingName; + CMyComPtr<IInStream> ZipStream; + CCdInfo ecd; - bool ecd_wasRead; + + UInt64 TotalBytesSize; // for MultiVol only + + void ClearRefs() + { + Streams.Clear(); + ZipStream.Release(); + TotalBytesSize = 0; + } void Clear() { StreamIndex = -1; NeedSeek = false; - StartIsExe = false; StartIsZ = false; StartIsZip = false; @@ -177,21 +214,12 @@ public: MissingZip = false; ecd_wasRead = false; - Streams.Clear(); - ZipStream.Release(); + ClearRefs(); } HRESULT ParseArcName(IArchiveOpenVolumeCallback *volCallback); HRESULT Read(void *data, UInt32 size, UInt32 *processedSize); - - UInt64 GetTotalSize() const - { - UInt64 total = 0; - FOR_VECTOR (i, Streams) - total += Streams[i].Size; - return total; - } }; @@ -210,44 +238,69 @@ public: class CInArchive { - CInBuffer _inBuffer; + CMidBuffer Buffer; + size_t _bufPos; + size_t _bufCached; + + UInt64 _streamPos; + UInt64 _cnt; + + size_t GetAvail() const { return _bufCached - _bufPos; } + + void InitBuf() { _bufPos = 0; _bufCached = 0; } + void DisableBufMode() { InitBuf(); _inBufMode = false; } + + void SkipLookahed(size_t skip) + { + _bufPos += skip; + _cnt += skip; + } + + UInt64 GetVirtStreamPos() { return _streamPos - _bufCached + _bufPos; } + bool _inBufMode; - UInt32 m_Signature; - UInt64 m_Position; - UInt64 _processedCnt; - + bool IsArcOpen; bool CanStartNewVol; + UInt32 _signature; + CMyComPtr<IInStream> StreamRef; IInStream *Stream; IInStream *StartStream; + IArchiveOpenCallback *Callback; - bool IsArcOpen; + HRESULT Seek_SavePos(UInt64 offset); + HRESULT SeekToVol(int volIndex, UInt64 offset); + + HRESULT ReadFromCache(Byte *data, unsigned size, unsigned &processed); HRESULT ReadVols2(IArchiveOpenVolumeCallback *volCallback, unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsigned &numMissingVols); HRESULT ReadVols(); - HRESULT Seek(UInt64 offset); - HRESULT FindMarker(IInStream *stream, const UInt64 *searchLimit); - HRESULT IncreaseRealPosition(Int64 addValue, bool &isFinished); + HRESULT FindMarker(const UInt64 *searchLimit); + HRESULT IncreaseRealPosition(UInt64 addValue, bool &isFinished); - HRESULT ReadBytes(void *data, UInt32 size, UInt32 *processedSize); - void SafeReadBytes(void *data, unsigned size); + HRESULT LookAhead(size_t minRequiredInBuffer); + void SafeRead(Byte *data, unsigned size); void ReadBuffer(CByteBuffer &buffer, unsigned size); - Byte ReadByte(); - UInt16 ReadUInt16(); + // Byte ReadByte(); + // UInt16 ReadUInt16(); UInt32 ReadUInt32(); UInt64 ReadUInt64(); - void Skip(unsigned num); - void Skip64(UInt64 num); - void ReadFileName(unsigned nameSize, AString &dest); - bool ReadExtra(unsigned extraSize, CExtraBlock &extraBlock, - UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber); + void ReadSignature(); + + void Skip(size_t num); + HRESULT Skip64(UInt64 num, unsigned numFiles); + + bool ReadFileName(unsigned nameSize, AString &dest); + + bool ReadExtra(unsigned extraSize, CExtraBlock &extra, + UInt64 &unpackSize, UInt64 &packSize, UInt64 &localOffset, UInt32 &disk); bool ReadLocalItem(CItemEx &item); - HRESULT ReadLocalItemDescriptor(CItemEx &item); + HRESULT FindDescriptor(CItemEx &item, unsigned numFiles); HRESULT ReadCdItem(CItemEx &item); HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo); HRESULT FindCd(bool checkOffsetMode); @@ -255,21 +308,28 @@ class CInArchive HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize); HRESULT ReadLocals(CObjectVector<CItemEx> &localItems); - HRESULT ReadHeaders2(CObjectVector<CItemEx> &items); + HRESULT ReadHeaders(CObjectVector<CItemEx> &items); HRESULT GetVolStream(unsigned vol, UInt64 pos, CMyComPtr<ISequentialInStream> &stream); + public: CInArchiveInfo ArcInfo; bool IsArc; bool IsZip64; + bool HeadersError; bool HeadersWarning; bool ExtraMinorError; bool UnexpectedEnd; + bool LocalsWereRead; + bool LocalsCenterMerged; bool NoCentralDir; + bool Overflow32bit; // = true, if zip without Zip64 extension support and it has some fields values truncated to 32-bits. + bool Cd_NumEntries_Overflow_16bit; // = true, if no Zip64 and 16-bit ecd:NumEntries was overflowed. bool MarkerIsFound; + bool MarkerIsSafe; bool IsMultiVol; bool UseDisk_in_SingleVol; @@ -277,9 +337,7 @@ public: CVols Vols; - IArchiveOpenCallback *Callback; - - CInArchive(): Stream(NULL), Callback(NULL), IsArcOpen(false) {} + CInArchive(): Stream(NULL), StartStream(NULL), Callback(NULL), IsArcOpen(false) {} UInt64 GetPhySize() const { @@ -301,7 +359,6 @@ public: void ClearRefs(); void Close(); HRESULT Open(IInStream *stream, const UInt64 *searchLimit, IArchiveOpenCallback *callback, CObjectVector<CItemEx> &items); - HRESULT ReadHeaders(CObjectVector<CItemEx> &items); bool IsOpen() const { return IsArcOpen; } @@ -329,7 +386,8 @@ public: } - HRESULT ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail); + HRESULT CheckDescriptor(const CItemEx &item); + HRESULT ReadLocalItemAfterCdItem(CItemEx &item, bool &isAvail, bool &headersError); HRESULT ReadLocalItemAfterCdItemFull(CItemEx &item); HRESULT GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr<ISequentialInStream> &stream); diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp index e732df7c..4fc59f79 100644 --- a/CPP/7zip/Archive/Zip/ZipItem.cpp +++ b/CPP/7zip/Archive/Zip/ZipItem.cpp @@ -5,9 +5,12 @@ #include "../../../../C/CpuArch.h" #include "../../../../C/7zCrc.h" +#include "../../../Common/IntToString.h" #include "../../../Common/MyLinux.h" #include "../../../Common/StringConvert.h" +#include "../../../Windows/PropVariantUtils.h" + #include "../Common/ItemNameUtils.h" #include "ZipItem.h" @@ -17,6 +20,62 @@ namespace NZip { using namespace NFileHeader; +static const CUInt32PCharPair g_ExtraTypes[] = +{ + { NExtraID::kZip64, "Zip64" }, + { NExtraID::kNTFS, "NTFS" }, + { NExtraID::kStrongEncrypt, "StrongCrypto" }, + { NExtraID::kUnixTime, "UT" }, + { NExtraID::kUnixExtra, "UX" }, + { NExtraID::kIzUnicodeComment, "uc" }, + { NExtraID::kIzUnicodeName, "up" }, + { NExtraID::kWzAES, "WzAES" } +}; + +void CExtraSubBlock::PrintInfo(AString &s) const +{ + for (unsigned i = 0; i < ARRAY_SIZE(g_ExtraTypes); i++) + { + const CUInt32PCharPair &pair = g_ExtraTypes[i]; + if (pair.Value == ID) + { + s += pair.Name; + return; + } + } + { + char sz[32]; + sz[0] = '0'; + sz[1] = 'x'; + ConvertUInt32ToHex(ID, sz + 2); + s += sz; + } +} + + +void CExtraBlock::PrintInfo(AString &s) const +{ + if (Error) + s.Add_OptSpaced("Extra_ERROR"); + + if (MinorError) + s.Add_OptSpaced("Minor_Extra_ERROR"); + + if (IsZip64 || IsZip64_Error) + { + s.Add_OptSpaced("Zip64"); + if (IsZip64_Error) + s += "_ERROR"; + } + + FOR_VECTOR (i, SubBlocks) + { + s.Add_Space_if_NotEmpty(); + SubBlocks[i].PrintInfo(s); + } +} + + bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const { ft.dwHighDateTime = ft.dwLowDateTime = 0; @@ -83,6 +142,19 @@ bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res } +bool CExtraSubBlock::ExtractUnixExtraTime(unsigned index, UInt32 &res) const +{ + res = 0; + const size_t size = Data.Size(); + unsigned offset = index * 4; + if (ID != NExtraID::kUnixExtra || size < offset + 4) + return false; + const Byte *p = (const Byte *)Data + offset; + res = GetUi32(p); + return true; +} + + bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const { FOR_VECTOR (i, SubBlocks) @@ -96,11 +168,29 @@ bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const { - FOR_VECTOR (i, SubBlocks) { - const CExtraSubBlock &sb = SubBlocks[i]; - if (sb.ID == NFileHeader::NExtraID::kUnixTime) - return sb.ExtractUnixTime(isCentral, index, res); + FOR_VECTOR (i, SubBlocks) + { + const CExtraSubBlock &sb = SubBlocks[i]; + if (sb.ID == NFileHeader::NExtraID::kUnixTime) + return sb.ExtractUnixTime(isCentral, index, res); + } + } + + switch (index) + { + case NUnixTime::kMTime: index = NUnixExtra::kMTime; break; + case NUnixTime::kATime: index = NUnixExtra::kATime; break; + default: return false; + } + + { + FOR_VECTOR (i, SubBlocks) + { + const CExtraSubBlock &sb = SubBlocks[i]; + if (sb.ID == NFileHeader::NExtraID::kUnixExtra) + return sb.ExtractUnixExtraTime(index, res); + } } return false; } diff --git a/CPP/7zip/Archive/Zip/ZipItem.h b/CPP/7zip/Archive/Zip/ZipItem.h index c134ec79..0cf9bd09 100644 --- a/CPP/7zip/Archive/Zip/ZipItem.h +++ b/CPP/7zip/Archive/Zip/ZipItem.h @@ -22,11 +22,12 @@ struct CVersion struct CExtraSubBlock { - UInt16 ID; + UInt32 ID; CByteBuffer Data; bool ExtractNtfsTime(unsigned index, FILETIME &ft) const; bool ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const; + bool ExtractUnixExtraTime(unsigned index, UInt32 &res) const; bool ExtractIzUnicode(UInt32 crc, AString &name) const { @@ -44,6 +45,8 @@ struct CExtraSubBlock return false; return CheckUTF8(name, false); } + + void PrintInfo(AString &s) const; }; const unsigned k_WzAesExtra_Size = 7; @@ -129,11 +132,22 @@ struct CStrongCryptoExtra bool CertificateIsUsed() const { return (Flags > 0x0001); } }; + struct CExtraBlock { CObjectVector<CExtraSubBlock> SubBlocks; + bool Error; + bool MinorError; + bool IsZip64; + bool IsZip64_Error; - void Clear() { SubBlocks.Clear(); } + CExtraBlock(): Error(false), MinorError(false), IsZip64(false), IsZip64_Error(false) {} + + void Clear() + { + SubBlocks.Clear(); + IsZip64 = false; + } size_t GetSize() const { @@ -176,6 +190,8 @@ struct CExtraBlock bool GetNtfsTime(unsigned index, FILETIME &ft) const; bool GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const; + void PrintInfo(AString &s) const; + void RemoveUnknownSubBlocks() { for (unsigned i = SubBlocks.Size(); i != 0;) @@ -206,12 +222,19 @@ public: CExtraBlock LocalExtra; + unsigned GetDescriptorSize() const { return LocalExtra.IsZip64 ? kDataDescriptorSize64 : kDataDescriptorSize32; } + + UInt64 GetPackSizeWithDescriptor() const + { return PackSize + (HasDescriptor() ? GetDescriptorSize() : 0); } + bool IsUtf8() const { return (Flags & NFileHeader::NFlags::kUtf8) != 0; } bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kEncrypted) != 0; } bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; } bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || Method == NFileHeader::NCompressionMethod::kWzAES); } bool IsLzmaEOS() const { return (Flags & NFileHeader::NFlags::kLzmaEOS) != 0; } bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; } + + unsigned GetDeflateLevel() const { return (Flags >> 1) & 3; } bool IsDir() const; diff --git a/CPP/7zip/Archive/Zip/ZipOut.cpp b/CPP/7zip/Archive/Zip/ZipOut.cpp index 2a1ba2c4..1fdc24f8 100644 --- a/CPP/7zip/Archive/Zip/ZipOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipOut.cpp @@ -21,48 +21,20 @@ HRESULT COutArchive::Create(IOutStream *outStream) return m_Stream->Seek(0, STREAM_SEEK_CUR, &m_Base); } -void COutArchive::MoveCurPos(UInt64 distanceToMove) -{ - m_CurPos += distanceToMove; // test overflow -} - -void COutArchive::SeekToRelatPos(UInt64 offset) +void COutArchive::SeekToCurPos() { - HRESULT res = m_Stream->Seek(m_Base + offset, STREAM_SEEK_SET, NULL); + HRESULT res = m_Stream->Seek(m_Base + m_CurPos, STREAM_SEEK_SET, NULL); if (res != S_OK) throw CSystemException(res); } -void COutArchive::PrepareWriteCompressedDataZip64(unsigned fileNameLen, bool isZip64, bool aesEncryption) -{ - m_IsZip64 = isZip64; - m_ExtraSize = isZip64 ? (4 + 8 + 8) : 0; - if (aesEncryption) - m_ExtraSize += 4 + k_WzAesExtra_Size; - m_LocalFileHeaderSize = kLocalHeaderSize + fileNameLen + m_ExtraSize; -} - -void COutArchive::PrepareWriteCompressedData(unsigned fileNameLen, UInt64 unPackSize, bool aesEncryption) -{ - // We use Zip64, if unPackSize size is larger than 0xF8000000 to support - // cases when compressed size can be about 3% larger than uncompressed size - - PrepareWriteCompressedDataZip64(fileNameLen, unPackSize >= (UInt32)0xF8000000, aesEncryption); -} - #define DOES_NEED_ZIP64(v) (v >= (UInt32)0xFFFFFFFF) +// #define DOES_NEED_ZIP64(v) (v >= 0) -void COutArchive::PrepareWriteCompressedData2(unsigned fileNameLen, UInt64 unPackSize, UInt64 packSize, bool aesEncryption) -{ - bool isZip64 = - DOES_NEED_ZIP64(unPackSize) || - DOES_NEED_ZIP64(packSize); - PrepareWriteCompressedDataZip64(fileNameLen, isZip64, aesEncryption); -} -void COutArchive::WriteBytes(const void *buffer, UInt32 size) +void COutArchive::WriteBytes(const void *data, size_t size) { - m_OutBuffer.WriteBytes(buffer, size); + m_OutBuffer.WriteBytes(data, size); m_CurPos += size; } @@ -74,11 +46,8 @@ void COutArchive::Write8(Byte b) void COutArchive::Write16(UInt16 val) { - for (int i = 0; i < 2; i++) - { - Write8((Byte)val); - val >>= 8; - } + Write8((Byte)val); + Write8((Byte)(val >> 8)); } void COutArchive::Write32(UInt32 val) @@ -101,15 +70,12 @@ void COutArchive::Write64(UInt64 val) void COutArchive::WriteExtra(const CExtraBlock &extra) { - if (extra.SubBlocks.Size() != 0) + FOR_VECTOR (i, extra.SubBlocks) { - FOR_VECTOR (i, extra.SubBlocks) - { - const CExtraSubBlock &subBlock = extra.SubBlocks[i]; - Write16(subBlock.ID); - Write16((UInt16)subBlock.Data.Size()); - WriteBytes(subBlock.Data, (UInt32)subBlock.Data.Size()); - } + const CExtraSubBlock &subBlock = extra.SubBlocks[i]; + Write16((UInt16)subBlock.ID); + Write16((UInt16)subBlock.Data.Size()); + WriteBytes(subBlock.Data, (UInt16)subBlock.Data.Size()); } } @@ -125,40 +91,65 @@ void COutArchive::WriteCommonItemInfo(const CLocalItem &item, bool isZip64) Write16(item.Flags); Write16(item.Method); Write32(item.Time); - Write32(item.Crc); } + #define WRITE_32_VAL_SPEC(__v, __isZip64) Write32((__isZip64) ? 0xFFFFFFFF : (UInt32)(__v)); -void COutArchive::WriteLocalHeader(const CLocalItem &item) + +void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck) { - SeekToCurPos(); + m_LocalHeaderPos = m_CurPos; + item.LocalHeaderPos = m_CurPos; - bool isZip64 = m_IsZip64 || + bool isZip64 = DOES_NEED_ZIP64(item.PackSize) || DOES_NEED_ZIP64(item.Size); - + + if (needCheck && m_IsZip64) + isZip64 = true; + + const UInt32 localExtraSize = (UInt32)((isZip64 ? (4 + 8 + 8): 0) + item.LocalExtra.GetSize()); + if ((UInt16)localExtraSize != localExtraSize) + throw CSystemException(E_FAIL); + if (needCheck && m_ExtraSize != localExtraSize) + throw CSystemException(E_FAIL); + + m_IsZip64 = isZip64; + m_ExtraSize = localExtraSize; + + item.LocalExtra.IsZip64 = isZip64; + Write32(NSignature::kLocalFileHeader); + WriteCommonItemInfo(item, isZip64); + + Write32(item.HasDescriptor() ? 0 : item.Crc); - WRITE_32_VAL_SPEC(item.PackSize, isZip64); - WRITE_32_VAL_SPEC(item.Size, isZip64); - - Write16((UInt16)item.Name.Len()); + UInt64 packSize = item.PackSize; + UInt64 size = item.Size; + + if (item.HasDescriptor()) { - UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 8 + 8): 0) + item.LocalExtra.GetSize()); - if (localExtraSize != m_ExtraSize) - throw CSystemException(E_FAIL); + packSize = 0; + size = 0; } - Write16((UInt16)m_ExtraSize); - WriteBytes((const char *)item.Name, item.Name.Len()); + + WRITE_32_VAL_SPEC(packSize, isZip64); + WRITE_32_VAL_SPEC(size, isZip64); + + Write16((UInt16)item.Name.Len()); + + Write16((UInt16)localExtraSize); + + WriteBytes((const char *)item.Name, (UInt16)item.Name.Len()); if (isZip64) { Write16(NFileHeader::NExtraID::kZip64); Write16(8 + 8); - Write64(item.Size); - Write64(item.PackSize); + Write64(size); + Write64(packSize); } WriteExtra(item.LocalExtra); @@ -166,10 +157,57 @@ void COutArchive::WriteLocalHeader(const CLocalItem &item) // Why don't we write NTFS timestamps to local header? // Probably we want to reduce size of archive? + const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos); + if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize) + throw CSystemException(E_FAIL); + m_LocalFileHeaderSize = localFileHeaderSize; + m_OutBuffer.FlushWithCheck(); - MoveCurPos(item.PackSize); } + +void COutArchive::WriteLocalHeader_Replace(CItemOut &item) +{ + m_CurPos = m_LocalHeaderPos + m_LocalFileHeaderSize + item.PackSize; + + if (item.HasDescriptor()) + { + WriteDescriptor(item); + m_OutBuffer.FlushWithCheck(); + } + + const UInt64 nextPos = m_CurPos; + m_CurPos = m_LocalHeaderPos; + SeekToCurPos(); + WriteLocalHeader(item, true); + m_CurPos = nextPos; + SeekToCurPos(); +} + + +void COutArchive::WriteDescriptor(const CItemOut &item) +{ + Byte buf[kDataDescriptorSize64]; + SetUi32(buf, NSignature::kDataDescriptor); + SetUi32(buf + 4, item.Crc); + unsigned descriptorSize; + if (m_IsZip64) + { + SetUi64(buf + 8, item.PackSize); + SetUi64(buf + 16, item.Size); + descriptorSize = kDataDescriptorSize64; + } + else + { + SetUi32(buf + 8, (UInt32)item.PackSize); + SetUi32(buf + 12, (UInt32)item.Size); + descriptorSize = kDataDescriptorSize32; + } + WriteBytes(buf, descriptorSize); +} + + + void COutArchive::WriteCentralHeader(const CItemOut &item) { bool isUnPack64 = DOES_NEED_ZIP64(item.Size); @@ -182,6 +220,7 @@ void COutArchive::WriteCentralHeader(const CItemOut &item) Write8(item.MadeByVersion.HostOS); WriteCommonItemInfo(item, isZip64); + Write32(item.Crc); WRITE_32_VAL_SPEC(item.PackSize, isPack64); WRITE_32_VAL_SPEC(item.Size, isUnPack64); @@ -196,7 +235,10 @@ void COutArchive::WriteCentralHeader(const CItemOut &item) item.CentralExtra.GetSize()); Write16(centralExtraSize); // test it; - Write16((UInt16)item.Comment.Size()); + + const UInt16 commentSize = (UInt16)item.Comment.Size(); + + Write16(commentSize); Write16(0); // DiskNumberStart; Write16(item.InternalAttrib); Write32(item.ExternalAttrib); @@ -228,14 +270,12 @@ void COutArchive::WriteCentralHeader(const CItemOut &item) } WriteExtra(item.CentralExtra); - if (item.Comment.Size() > 0) - WriteBytes(item.Comment, (UInt32)item.Comment.Size()); + if (commentSize != 0) + WriteBytes(item.Comment, commentSize); } void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment) { - SeekToCurPos(); - UInt64 cdOffset = GetCurPos(); FOR_VECTOR (i, items) WriteCentralHeader(items[i]); @@ -252,6 +292,11 @@ void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CB { Write32(NSignature::kEcd64); Write64(kEcd64_MainSize); + + // to test extra block: + // const UInt32 extraSize = 1 << 26; + // Write64(kEcd64_MainSize + extraSize); + Write16(45); // made by version Write16(45); // extract version Write32(0); // ThisDiskNumber = 0; @@ -261,6 +306,8 @@ void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CB Write64((UInt64)cdSize); Write64((UInt64)cdOffset); + // for (UInt32 iii = 0; iii < extraSize; iii++) Write8(1); + Write32(NSignature::kEcd64Locator); Write32(0); // number of the disk with the start of the zip64 end of central directory Write64(cd64EndOffset); @@ -276,37 +323,23 @@ void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CB WRITE_32_VAL_SPEC(cdSize, cdSize64); WRITE_32_VAL_SPEC(cdOffset, cdOffset64); - UInt32 commentSize = (UInt32)(comment ? comment->Size() : 0); + const UInt16 commentSize = (UInt16)(comment ? comment->Size() : 0); Write16((UInt16)commentSize); - if (commentSize > 0) + if (commentSize != 0) WriteBytes((const Byte *)*comment, commentSize); m_OutBuffer.FlushWithCheck(); } -void COutArchive::CreateStreamForCompressing(IOutStream **outStream) +void COutArchive::CreateStreamForCompressing(CMyComPtr<IOutStream> &outStream) { COffsetOutStream *streamSpec = new COffsetOutStream; - CMyComPtr<IOutStream> tempStream(streamSpec); - streamSpec->Init(m_Stream, m_Base + m_CurPos + m_LocalFileHeaderSize); - *outStream = tempStream.Detach(); -} - -/* -void COutArchive::SeekToPackedDataPosition() -{ - SeekTo(m_BasePosition + m_LocalFileHeaderSize); -} -*/ - -void COutArchive::SeekToCurPos() -{ - SeekToRelatPos(m_CurPos); + outStream = streamSpec; + streamSpec->Init(m_Stream, m_Base + m_CurPos); } -void COutArchive::CreateStreamForCopying(ISequentialOutStream **outStream) +void COutArchive::CreateStreamForCopying(CMyComPtr<ISequentialOutStream> &outStream) { - CMyComPtr<ISequentialOutStream> tempStream(m_Stream); - *outStream = tempStream.Detach(); + outStream = m_Stream; } }} diff --git a/CPP/7zip/Archive/Zip/ZipOut.h b/CPP/7zip/Archive/Zip/ZipOut.h index 056d0d09..0a0ac0c8 100644 --- a/CPP/7zip/Archive/Zip/ZipOut.h +++ b/CPP/7zip/Archive/Zip/ZipOut.h @@ -5,7 +5,6 @@ #include "../../../Common/MyCom.h" -#include "../../IStream.h" #include "../../Common/OutBuffer.h" #include "ZipItem.h" @@ -13,8 +12,6 @@ namespace NArchive { namespace NZip { -// can throw CSystemException and COutBufferException - class CItemOut: public CItem { public: @@ -28,21 +25,23 @@ public: CItemOut(): NtfsTimeIsDefined(false) {} }; + +// COutArchive can throw CSystemException and COutBufferException + class COutArchive { - CMyComPtr<IOutStream> m_Stream; COutBuffer m_OutBuffer; + CMyComPtr<IOutStream> m_Stream; - UInt64 m_Base; // Base of arc (offset in output Stream) + UInt64 m_Base; // Base of archive (offset in output Stream) UInt64 m_CurPos; // Curent position in archive (relative from m_Base) + UInt64 m_LocalHeaderPos; // LocalHeaderPos (relative from m_Base) for last WriteLocalHeader() call UInt32 m_LocalFileHeaderSize; UInt32 m_ExtraSize; bool m_IsZip64; - void SeekToRelatPos(UInt64 offset); - - void WriteBytes(const void *buffer, UInt32 size); + void WriteBytes(const void *data, size_t size); void Write8(Byte b); void Write16(UInt16 val); void Write32(UInt32 val); @@ -57,30 +56,26 @@ class COutArchive void WriteCommonItemInfo(const CLocalItem &item, bool isZip64); void WriteCentralHeader(const CItemOut &item); - void PrepareWriteCompressedDataZip64(unsigned fileNameLen, bool isZip64, bool aesEncryption); - + void SeekToCurPos(); public: HRESULT Create(IOutStream *outStream); - void MoveCurPos(UInt64 distanceToMove); UInt64 GetCurPos() const { return m_CurPos; } - void SeekToCurPos(); - - void PrepareWriteCompressedData(unsigned fileNameLen, UInt64 unPackSize, bool aesEncryption); - void PrepareWriteCompressedData2(unsigned fileNameLen, UInt64 unPackSize, UInt64 packSize, bool aesEncryption); - void WriteLocalHeader(const CLocalItem &item); - - void WriteLocalHeader_And_SeekToNextFile(const CLocalItem &item) + void MoveCurPos(UInt64 distanceToMove) { - WriteLocalHeader(item); - SeekToCurPos(); + m_CurPos += distanceToMove; } + void WriteLocalHeader(CItemOut &item, bool needCheck = false); + void WriteLocalHeader_Replace(CItemOut &item); + + void WriteDescriptor(const CItemOut &item); + void WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment); - void CreateStreamForCompressing(IOutStream **outStream); - void CreateStreamForCopying(ISequentialOutStream **outStream); + void CreateStreamForCompressing(CMyComPtr<IOutStream> &outStream); + void CreateStreamForCopying(CMyComPtr<ISequentialOutStream> &outStream); }; }} diff --git a/CPP/7zip/Archive/Zip/ZipRegister.cpp b/CPP/7zip/Archive/Zip/ZipRegister.cpp index 6674189f..e6929f1b 100644 --- a/CPP/7zip/Archive/Zip/ZipRegister.cpp +++ b/CPP/7zip/Archive/Zip/ZipRegister.cpp @@ -10,13 +10,14 @@ namespace NArchive { namespace NZip { static const Byte k_Signature[] = { - 4, 0x50, 0x4B, 0x03, 0x04, - 4, 0x50, 0x4B, 0x05, 0x06, - 6, 0x50, 0x4B, 0x07, 0x08, 0x50, 0x4B, - 6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B }; + 4, 0x50, 0x4B, 0x03, 0x04, // Local + 4, 0x50, 0x4B, 0x05, 0x06, // Ecd + 4, 0x50, 0x4B, 0x06, 0x06, // Ecd64 + 6, 0x50, 0x4B, 0x07, 0x08, 0x50, 0x4B, // Span / Descriptor + 6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B }; // NoSpan REGISTER_ARC_IO( - "zip", "zip z01 zipx jar xpi odt ods docx xlsx epub", 0, 1, + "zip", "zip z01 zipx jar xpi odt ods docx xlsx epub ipa apk appx", 0, 1, k_Signature, 0, NArcInfoFlags::kFindSignature | diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index bc50c1d7..81f48a2a 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -42,32 +42,38 @@ static const Byte kHostOS = static const Byte kMadeByHostOS = kHostOS; static const Byte kExtractHostOS = kHostOS; -static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStored; +static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStore; -static HRESULT CopyBlockToArchive(ISequentialInStream *inStream, UInt64 size, - COutArchive &outArchive, ICompressProgressInfo *progress) + +static void AddAesExtra(CItem &item, Byte aesKeyMode, UInt16 method) { - CMyComPtr<ISequentialOutStream> outStream; - outArchive.CreateStreamForCopying(&outStream); - return NCompress::CopyStream_ExactSize(inStream, outStream, size, progress); + CWzAesExtra wzAesField; + wzAesField.Strength = aesKeyMode; + wzAesField.Method = method; + item.Method = NFileHeader::NCompressionMethod::kWzAES; + item.Crc = 0; + CExtraSubBlock sb; + wzAesField.SetSubBlock(sb); + item.LocalExtra.SubBlocks.Add(sb); + item.CentralExtra.SubBlocks.Add(sb); } + static void SetFileHeader( - COutArchive &archive, const CCompressionMethodMode &options, const CUpdateItem &ui, // bool isSeqMode, CItemOut &item) { item.Size = ui.Size; - bool isDir; + bool isDir = ui.IsDir; item.ClearFlags(); if (ui.NewProps) { - isDir = ui.IsDir; item.Name = ui.Name; + item.Comment = ui.Comment; item.SetUtf8(ui.IsUtf8); item.ExternalAttrib = ui.Attrib; item.Time = ui.Time; @@ -76,10 +82,11 @@ static void SetFileHeader( item.Ntfs_CTime = ui.Ntfs_CTime; item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined; } + /* else isDir = item.IsDir(); + */ - item.LocalHeaderPos = archive.GetCurPos(); item.MadeByVersion.HostOS = kMadeByHostOS; item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion; @@ -97,14 +104,32 @@ static void SetFileHeader( item.Size = 0; item.Crc = 0; } + + item.LocalExtra.Clear(); + item.CentralExtra.Clear(); + + if (isDir) + { + item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir; + item.Method = kMethodForDirectory; + item.PackSize = 0; + item.Size = 0; + item.Crc = 0; + } + else if (options.IsRealAesMode()) + AddAesExtra(item, options.AesKeyMode, (Byte)(options.MethodSequence.IsEmpty() ? 8 : options.MethodSequence[0])); } +// we call SetItemInfoFromCompressingResult() after SetFileHeader() + static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult, bool isAesMode, Byte aesKeyMode, CItem &item) { item.ExtractVersion.Version = compressingResult.ExtractVersion; item.Method = compressingResult.Method; + if (compressingResult.Method == NFileHeader::NCompressionMethod::kLZMA && compressingResult.LzmaEos) + item.Flags |= NFileHeader::NFlags::kLzmaEOS; item.Crc = compressingResult.CRC; item.Size = compressingResult.UnpackSize; item.PackSize = compressingResult.PackSize; @@ -113,17 +138,7 @@ static void SetItemInfoFromCompressingResult(const CCompressingResult &compressi item.CentralExtra.Clear(); if (isAesMode) - { - CWzAesExtra wzAesField; - wzAesField.Strength = aesKeyMode; - wzAesField.Method = compressingResult.Method; - item.Method = NFileHeader::NCompressionMethod::kWzAES; - item.Crc = 0; - CExtraSubBlock sb; - wzAesField.SetSubBlock(sb); - item.LocalExtra.SubBlocks.Add(sb); - item.CentralExtra.SubBlocks.Add(sb); - } + AddAesExtra(item, aesKeyMode, compressingResult.Method); } @@ -151,6 +166,7 @@ struct CThreadInfo HRESULT Result; CCompressingResult CompressingResult; + bool SeqMode; bool IsFree; UInt32 UpdateIndex; UInt32 FileTime; @@ -160,6 +176,7 @@ struct CThreadInfo ProgressSpec(0), OutStreamSpec(0), Coder(options), + SeqMode(false), FileTime(0) {} @@ -193,7 +210,7 @@ void CThreadInfo::WaitAndCode() Result = Coder.Compress( EXTERNAL_CODECS_LOC_VARS - InStream, OutStream, FileTime, Progress, CompressingResult); + InStream, OutStream, SeqMode, FileTime, Progress, CompressingResult); if (Result == S_OK && Progress) Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize); @@ -342,6 +359,8 @@ static HRESULT UpdateItemOldData( NUpdateNotifyOp::kReplicate)) } + UInt64 rangeSize; + if (ui.NewProps) { if (item.HasDescriptor()) @@ -349,14 +368,11 @@ static HRESULT UpdateItemOldData( // use old name size. - CMyComPtr<ISequentialInStream> packStream; - RINOK(inArchive->GetItemStream(itemEx, true, packStream)); - if (!packStream) - return E_NOTIMPL; - // we keep ExternalAttrib and some another properties from old archive // item.ExternalAttrib = ui.Attrib; + // if we don't change Comment, we keep Comment from OldProperties + item.Comment = ui.Comment; item.Name = ui.Name; item.SetUtf8(ui.IsUtf8); item.Time = ui.Time; @@ -367,46 +383,37 @@ static HRESULT UpdateItemOldData( item.CentralExtra.RemoveUnknownSubBlocks(); item.LocalExtra.RemoveUnknownSubBlocks(); - item.LocalHeaderPos = archive.GetCurPos(); - archive.PrepareWriteCompressedData2(item.Name.Len(), item.Size, item.PackSize, item.LocalExtra.HasWzAes()); archive.WriteLocalHeader(item); - - RINOK(CopyBlockToArchive(packStream, itemEx.PackSize, archive, progress)); - - complexity += itemEx.PackSize; + rangeSize = item.GetPackSizeWithDescriptor(); } else { - CMyComPtr<ISequentialInStream> packStream; - RINOK(inArchive->GetItemStream(itemEx, false, packStream)); - if (!packStream) - return E_NOTIMPL; - - // set new header position item.LocalHeaderPos = archive.GetCurPos(); - - const UInt64 rangeSize = itemEx.GetLocalFullSize(); - - RINOK(CopyBlockToArchive(packStream, rangeSize, archive, progress)); - - complexity += rangeSize; - archive.MoveCurPos(rangeSize); + rangeSize = itemEx.GetLocalFullSize(); } - return S_OK; + CMyComPtr<ISequentialInStream> packStream; + + RINOK(inArchive->GetItemStream(itemEx, ui.NewProps, packStream)); + if (!packStream) + return E_NOTIMPL; + + complexity += rangeSize; + + CMyComPtr<ISequentialOutStream> outStream; + archive.CreateStreamForCopying(outStream); + HRESULT res = NCompress::CopyStream_ExactSize(packStream, outStream, rangeSize, progress); + archive.MoveCurPos(rangeSize); + return res; } static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options, const CUpdateItem &ui, CItemOut &item) { - SetFileHeader(archive, *options, ui, item); - archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, - // options->IsRealAesMode() - false // fixed 9.31 - ); - archive.WriteLocalHeader_And_SeekToNextFile(item); + SetFileHeader(*options, ui, item); + archive.WriteLocalHeader(item); } @@ -490,6 +497,8 @@ static HRESULT Update2St( if (!ui.NewProps || !ui.NewData) { + // Note: for (ui.NewProps && !ui.NewData) it copies Props from old archive, + // But we will rewrite all important properties later. But we can keep some properties like Comment itemEx = inputItems[ui.IndexInArc]; if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK) return E_NOTIMPL; @@ -498,7 +507,8 @@ static HRESULT Update2St( if (ui.NewData) { - bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); + // bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); + bool isDir = ui.IsDir; if (isDir) { WriteDirHeader(archive, options, ui, item); @@ -517,28 +527,39 @@ static HRESULT Update2St( if (!fileInStream) return E_INVALIDARG; - // bool isSeqMode = false; - /* + bool seqMode; { CMyComPtr<IInStream> inStream2; fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2); - isSeqMode = (inStream2 == NULL); + seqMode = (inStream2 == NULL); } - */ + // seqMode = true; // to test seqMode UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity); - SetFileHeader(archive, *options, ui, item); + SetFileHeader(*options, ui, item); + + item.SetDescriptorMode(seqMode); // file Size can be 64-bit !!! - archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode()); + CCompressingResult compressingResult; + + RINOK(compressor.Set_Pre_CompressionResult( + seqMode, + ui.Size, + compressingResult)); + + SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); + + archive.WriteLocalHeader(item); + CMyComPtr<IOutStream> outStream; - archive.CreateStreamForCompressing(&outStream); + archive.CreateStreamForCompressing(outStream); RINOK(compressor.Compress( EXTERNAL_CODECS_LOC_VARS fileInStream, outStream, - ui.Time, + seqMode, ui.Time, progress, compressingResult)); if (compressingResult.FileTimeWasUsed) @@ -551,7 +572,9 @@ static HRESULT Update2St( } SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); - archive.WriteLocalHeader_And_SeekToNextFile(item); + + archive.WriteLocalHeader_Replace(item); + RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); unpackSizeTotal += item.Size; packSizeTotal += item.PackSize; @@ -561,7 +584,9 @@ static HRESULT Update2St( { UInt64 complexity = 0; lps->SendRatio = false; + RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity)); + lps->SendRatio = true; lps->ProgressOffset += complexity; } @@ -591,6 +616,7 @@ static HRESULT Update2( CMyComPtr<IArchiveUpdateCallbackFile> opCallback; updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + bool unknownComplexity = false; UInt64 complexity = 0; UInt64 numFilesToCompress = 0; UInt64 numBytesToCompress = 0; @@ -602,7 +628,10 @@ static HRESULT Update2( const CUpdateItem &ui = updateItems[i]; if (ui.NewData) { - complexity += ui.Size; + if (ui.Size == (UInt64)(Int64)-1) + unknownComplexity = true; + else + complexity += ui.Size; numBytesToCompress += ui.Size; numFilesToCompress++; /* @@ -625,19 +654,49 @@ static HRESULT Update2( if (comment) complexity += comment->Size(); complexity++; // end of central - updateCallback->SetTotal(complexity); + + if (!unknownComplexity) + updateCallback->SetTotal(complexity); UInt64 totalComplexity = complexity; - CAddCommon compressor(options); + CCompressionMethodMode options2 = options; + + if (options2._methods.IsEmpty()) + { + // we need method item, if default method was used + options2._methods.AddNew(); + } + + CAddCommon compressor(options2); complexity = 0; - CCompressionMethodMode options2 = options; + const Byte method = options.MethodSequence.Front(); + + COneMethodInfo *oneMethodMain = NULL; + if (!options2._methods.IsEmpty()) + oneMethodMain = &options2._methods[0]; + + { + FOR_VECTOR (mi, options2._methods) + { + options2.SetGlobalLevelTo(options2._methods[mi]); + } + } + + if (oneMethodMain) + { + // appnote recommends to use EOS marker for LZMA. + if (method == NFileHeader::NCompressionMethod::kLZMA) + oneMethodMain->AddProp_EndMarker_if_NotFound(true); + } + #ifndef _7ZIP_ST - UInt32 numThreads = options.NumThreads; + UInt32 numThreads = options._numThreads; + const UInt32 kNumMaxThreads = 64; if (numThreads > kNumMaxThreads) numThreads = kNumMaxThreads; @@ -646,7 +705,6 @@ static HRESULT Update2( if (numThreads < 1) numThreads = 1; - const size_t kMemPerThread = (1 << 25); const size_t kBlockSize = 1 << 16; @@ -655,44 +713,69 @@ static HRESULT Update2( if (numFilesToCompress <= 1) mtMode = false; - Byte method = options.MethodSequence.Front(); - if (!mtMode) { - if (options2.MethodInfo.FindProp(NCoderPropID::kNumThreads) < 0) + FOR_VECTOR (mi, options2._methods) { - // fixed for 9.31. bzip2 default is just one thread. - if (options2.NumThreadsWasChanged || method == NFileHeader::NCompressionMethod::kBZip2) - options2.MethodInfo.AddProp_NumThreads(numThreads); + COneMethodInfo &onem = options2._methods[mi]; + + if (onem.FindProp(NCoderPropID::kNumThreads) < 0) + { + // fixed for 9.31. bzip2 default is just one thread. + onem.AddProp_NumThreads(numThreads); + } } } else { - if (method == NFileHeader::NCompressionMethod::kStored && !options.PasswordIsDefined) + if (method == NFileHeader::NCompressionMethod::kStore && !options.PasswordIsDefined) numThreads = 1; + + if (oneMethodMain) + { + if (method == NFileHeader::NCompressionMethod::kBZip2) { bool fixedNumber; - UInt32 numBZip2Threads = options2.MethodInfo.Get_BZip2_NumThreads(fixedNumber); + UInt32 numBZip2Threads = oneMethodMain->Get_BZip2_NumThreads(fixedNumber); if (!fixedNumber) { - UInt64 averageSize = numBytesToCompress / numFilesToCompress; - UInt32 blockSize = options2.MethodInfo.Get_BZip2_BlockSize(); - UInt64 averageNumberOfBlocks = averageSize / blockSize + 1; + const UInt64 averageSize = numBytesToCompress / numFilesToCompress; + const UInt32 blockSize = oneMethodMain->Get_BZip2_BlockSize(); + const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1; numBZip2Threads = 32; - if (averageNumberOfBlocks < numBZip2Threads) + if (numBZip2Threads > averageNumberOfBlocks) numBZip2Threads = (UInt32)averageNumberOfBlocks; - options2.MethodInfo.AddProp_NumThreads(numBZip2Threads); + oneMethodMain->AddProp_NumThreads(numBZip2Threads); } numThreads /= numBZip2Threads; } - if (method == NFileHeader::NCompressionMethod::kLZMA) + + if (method == NFileHeader::NCompressionMethod::kXz) { bool fixedNumber; + UInt32 numLzma2Threads = oneMethodMain->Get_Lzma2_NumThreads(fixedNumber); + if (!fixedNumber) + { + const UInt64 averageSize = numBytesToCompress / numFilesToCompress; + const UInt64 blockSize = oneMethodMain->Get_Lzma2_BlockSize(); + const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1; + numLzma2Threads = 2; + if (numLzma2Threads > averageNumberOfBlocks) + numLzma2Threads = (UInt32)averageNumberOfBlocks; + oneMethodMain->AddProp_NumThreads(numLzma2Threads); + } + numThreads /= numLzma2Threads; + } + + if (method == NFileHeader::NCompressionMethod::kLZMA) + { // we suppose that default LZMA is 2 thread. So we don't change it - UInt32 numLZMAThreads = options2.MethodInfo.Get_Lzma_NumThreads(fixedNumber); + UInt32 numLZMAThreads = oneMethodMain->Get_Lzma_NumThreads(); numThreads /= numLZMAThreads; } + } + if (numThreads > numFilesToCompress) numThreads = (UInt32)numFilesToCompress; if (numThreads <= 1) @@ -747,6 +830,7 @@ static HRESULT Update2( threadInfo.ProgressSpec = new CMtCompressProgress(); threadInfo.Progress = threadInfo.ProgressSpec; threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i); + threadInfo.SeqMode = false; // fix it ! threadInfo.FileTime = 0; // fix it ! RINOK(threadInfo.CreateThread()); } @@ -777,7 +861,9 @@ static HRESULT Update2( if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK) return E_NOTIMPL; (CItem &)item = itemEx; - if (item.IsDir()) + if (item.IsDir() != ui.IsDir) + return E_NOTIMPL; + if (ui.IsDir) continue; } @@ -849,7 +935,8 @@ static HRESULT Update2( if (ui.NewData) { - bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); + // bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); + bool isDir = ui.IsDir; if (isDir) { @@ -857,39 +944,51 @@ static HRESULT Update2( } else { - if (lastRealStreamItemIndex < (int)itemIndex) - { - lastRealStreamItemIndex = itemIndex; - SetFileHeader(archive, options, ui, item); - // file Size can be 64-bit !!! - archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options.IsRealAesMode()); - } - CMemBlocks2 &memRef = refs.Refs[itemIndex]; if (memRef.Defined) { - CMyComPtr<IOutStream> outStream; - archive.CreateStreamForCompressing(&outStream); - memRef.WriteToStream(memManager.GetBlockSize(), outStream); - SetFileHeader(archive, options, ui, item); + if (lastRealStreamItemIndex < (int)itemIndex) + lastRealStreamItemIndex = itemIndex; + + SetFileHeader(options, ui, item); // the BUG was fixed in 9.26: // SetItemInfoFromCompressingResult must be after SetFileHeader // to write correct Size. SetItemInfoFromCompressingResult(memRef.CompressingResult, options.IsRealAesMode(), options.AesKeyMode, item); - archive.WriteLocalHeader_And_SeekToNextFile(item); + archive.WriteLocalHeader(item); // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); + CMyComPtr<ISequentialOutStream> outStream; + archive.CreateStreamForCopying(outStream); + memRef.WriteToStream(memManager.GetBlockSize(), outStream); + archive.MoveCurPos(item.PackSize); memRef.FreeOpt(&memManager); } else { + if (lastRealStreamItemIndex < (int)itemIndex) + { + lastRealStreamItemIndex = itemIndex; + SetFileHeader(options, ui, item); + + CCompressingResult compressingResult; + RINOK(compressor.Set_Pre_CompressionResult( + false, // seqMode + ui.Size, + compressingResult)); + SetItemInfoFromCompressingResult(compressingResult, options.IsRealAesMode(), options.AesKeyMode, item); + + // file Size can be 64-bit !!! + archive.WriteLocalHeader(item); + } + { CThreadInfo &thread = threads.Threads[threadIndices.Front()]; if (!thread.OutStreamSpec->WasUnlockEventSent()) { CMyComPtr<IOutStream> outStream; - archive.CreateStreamForCompressing(&outStream); + archive.CreateStreamForCompressing(outStream); thread.OutStreamSpec->SetOutStream(outStream); thread.OutStreamSpec->SetRealStreamMode(); } @@ -918,10 +1017,10 @@ static HRESULT Update2( { RINOK(threadInfo.OutStreamSpec->WriteToRealStream()); threadInfo.OutStreamSpec->ReleaseOutStream(); - SetFileHeader(archive, options, ui, item); + SetFileHeader(options, ui, item); SetItemInfoFromCompressingResult(threadInfo.CompressingResult, options.IsRealAesMode(), options.AesKeyMode, item); - archive.WriteLocalHeader_And_SeekToNextFile(item); + archive.WriteLocalHeader_Replace(item); } else { diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.h b/CPP/7zip/Archive/Zip/ZipUpdate.h index 15cbf69d..d5fda855 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.h +++ b/CPP/7zip/Archive/Zip/ZipUpdate.h @@ -14,6 +14,7 @@ namespace NArchive { namespace NZip { +/* struct CUpdateRange { UInt64 Position; @@ -22,6 +23,7 @@ struct CUpdateRange // CUpdateRange() {}; CUpdateRange(UInt64 position, UInt64 size): Position(position), Size(size) {}; }; +*/ struct CUpdateItem { @@ -36,12 +38,23 @@ struct CUpdateItem UInt32 Time; UInt64 Size; AString Name; + CByteBuffer Comment; // bool Commented; // CUpdateRange CommentRange; FILETIME Ntfs_MTime; FILETIME Ntfs_ATime; FILETIME Ntfs_CTime; + void Clear() + { + IsDir = false; + NtfsTimeIsDefined = false; + IsUtf8 = false; + Size = 0; + Name.Empty(); + Comment.Free(); + } + CUpdateItem(): NtfsTimeIsDefined(false), IsUtf8(false), Size(0) {} }; |