diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index d46c6ff7..9fecf825 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -1,5 +1,6 @@ name: Ubuntu on: + pull_request: push: paths-ignore: - 'README.md' @@ -42,6 +43,6 @@ jobs: - name: check run: | cd ./check - bash check.sh `pwd`/../bin/7za + bash check.sh `pwd`/../bin/7z cd .. diff --git a/C/7zVersion.h b/C/7zVersion.h index 527bd5d7..4a82cf65 100644 --- a/C/7zVersion.h +++ b/C/7zVersion.h @@ -1,14 +1,14 @@ -#define MY_VER_MAJOR 16 +#define MY_VER_MAJOR 17 #define MY_VER_MINOR 02 #define MY_VER_BUILD 0 -#define MY_VERSION_NUMBERS "17.01" -#define MY_VERSION "17.01" -#define MY_DATE "2020-04-20" +#define MY_VERSION_NUMBERS "17.02 beta" +#define MY_VERSION "17.02" +#define MY_DATE "2017-08-28" #undef MY_COPYRIGHT #undef MY_VERSION_COPYRIGHT_DATE #define MY_AUTHOR_NAME "Igor Pavlov" #define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" -#define MY_COPYRIGHT_CR "Copyright (c) 1999-2016 Igor Pavlov" +#define MY_COPYRIGHT_CR "Copyright (c) 1999-2020 Igor Pavlov" #ifdef USE_COPYRIGHT_CR #define MY_COPYRIGHT MY_COPYRIGHT_CR @@ -18,5 +18,5 @@ #define MY_VERSION_COPYRIGHT_DATE MY_VERSION " : " MY_COPYRIGHT " : " MY_DATE -#define P7ZIP_VERSION "17.01" +#define P7ZIP_VERSION "17.02" diff --git a/C/README.md b/C/README.md deleted file mode 100644 index 2b729f7b..00000000 --- a/C/README.md +++ /dev/null @@ -1,123 +0,0 @@ - -# A new p7zip fork with additional codecs and improvements (forked from https://sourceforge.net/projects/p7zip/). - -This is the place for the active development of p7zip to include major modern codecs such as LZ4 and Zstd. In order to support multithreading for those addional codecs, this project depends on the [Multithreading Library](/~https://github.com/mcmilk/zstdmt). - -# status -| [Ubuntu][ubuntu-link]| -|---------------| -| ![ubuntu-badge] | - -[ubuntu-link]: /~https://github.com/2273816832/test_github_action/actions?query=workflow%3AUbuntu "UbuntuAction" -[ubuntu-badge]: /~https://github.com/2273816832/test_github_action/workflows/Ubuntu/badge.svg "Ubuntu" - -## Codec overview -1. [Zstandard] v1.4.4 is a real-time compression algorithm, providing high compression ratios. It offers a very wide range of compression / speed trade-off, while being backed by a very fast decoder. - - Levels: 1..22 - -2. [LZ4] v1.9.2 is lossless compression algorithm, providing compression speed at 400 MB/s per core (0.16 Bytes/cycle). It features an extremely fast decoder, with speed in multiple GB/s per core (0.71 Bytes/cycle). A high compression derivative, called LZ4_HC, is available, trading customizable CPU time for compression ratio. - - Levels: 1..12 - -## Benchmark -We use [silesia](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia) files(total size 211938580 Byte) for packaging. - -|format|method|encode_size(Byte)|encode_time(ms)|encode_speed(M/s)|decode_time(ms)|decode_speed(M/s)|compression_ratio| -|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:| -|7z-zip|deflaut-9|64727443|60637 ms|3.33|1751|115.43|3.27| -|7z-7z|lzma-9|48752532|92016 ms|2.20|3832|52.75|4.35| -|7z-7z|lzma2-9|48749158|91595 ms|2.21|3837|52.67|4.35| -|7z-7z|zstd-22|52739890|145423 ms|1.39|1063|190.14|4.02| -|7z-7z|lz4-12|77788397|3632 ms|55.65|452|447.17|2.72| - -## install CLI -### (Currently only supports CLI, if you want to do GUI please contact us) -1. git clone /~https://github.com/szcnick/p7zip.git -2. cd p7zip && make 7z . (OR make 7za) -3. ./bin/7z i . (OR 7za i) - -The output should look like this: -``` -7-Zip (a) [64] 17.01 : Copyright (c) 1999-2016 Igor Pavlov -p7zip Version 17.01 (locale=zh_CN.UTF-8,Utf16=on,HugeFiles=on,64 bits,12 CPUs x64) - -Formats: -... - 0 CK xz xz txz (.tar) FD 7 z X Z 00 - 0 Z z taz (.tar) 1F 9D - 0 CK zstd zst tzstd (.tar) 0 x F D 2 F B 5 2 5 . . 0 x F D 2 F B 5 2 8 00 - 0 C F 7z 7z 7 z BC AF ' 1C - 0 F Cab cab M S C F 00 00 00 00 -... - -Codecs: - 0 4ED 303011B BCJ2 - 0 ED 3030103 BCJ - 0 ED 3030205 PPC - 0 ED 3030401 IA64 - 0 ED 3030501 ARM - 0 ED 3030701 ARMT - 0 ED 3030805 SPARC - 0 ED 20302 Swap2 - 0 ED 20304 Swap4 - 0 ED 40202 BZip2 - 0 ED 0 Copy - 0 ED 40109 Deflate64 - 0 ED 40108 Deflate - 0 ED 3 Delta - 0 ED 21 LZMA2 - 0 ED 30101 LZMA - 0 ED 30401 PPMD - 0 D 40301 Rar1 - 0 D 40302 Rar2 - 0 D 40303 Rar3 - 0 D 40305 Rar5 - 0 ED 4F71104 LZ4 - 0 ED 4F71101 ZSTD - 0 ED 6F10701 7zAES - 0 ED 6F00181 AES256CBC - 1 3ED 4F712FF RawSplitter - -Hashers: - 0 4 1 CRC32 - 0 20 201 SHA1 - 0 32 A SHA256 - 0 8 4 CRC64 - 0 32 202 BLAKE2sp -``` - -## Usage (codec plugin) - -- compression and decompression for [LZ4] and [Zstandard] within the p7-Zip container format -- you can only create `.7z` files, the files like `.lz4` and `.zst` are not covered by the plugins -- when compressing binaries (*.exe, *.dll), you have to explicitly disable the bcj2 filter via `-m0=bcj`. -- so the usage should look like this: -``` -7z a archiv.7z -m0=bcj -m1=zstd -mx1 Fast mode, with BCJ preprocessor on executables -7z a archiv.7z -m0=bcj -m1=zstd -mx.. ... -7z a archiv.7z -m0=bcj -m1=zstd -mx21 2nd Slowest Mode, with BCJ preprocessor on executables -7z a archiv.7z -m0=bcj -m1=zstd -mx22 Ultra Mode, with BCJ preprocessor on executables -7z a archiv.7z -m0=bcj -m1=lz4 -mxN ... -``` - -## License and redistribution - -- the same as the Mainline [p7-Zip], which means GNU LGPL - -## Links - -- [7-Zip Homepage](https://www.7-zip.org/) -- [Request for inclusion](https://sourceforge.net/p/sevenzip/discussion/45797/thread/a7e4f3f3/) into the mainline 7-Zip: - - result, will currently not included :( - -## Version Information - -- p7zip Version 17.01 - - [LZ4] Version 1.9.2 - - [Zstandard] Version 1.4.4 - -## Working Plan - - [check here](/~https://github.com/szcnick/p7zip/tree/dev/DOC) - -[p7-Zip]:https://www.7-zip.org/ -[LZ4]:/~https://github.com/lz4/lz4/ -[Zstandard]:/~https://github.com/facebook/zstd/ diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.h b/CPP/7zip/Archive/7z/7zCompressionMode.h index 768022e4..8105ff04 100644 --- a/CPP/7zip/Archive/7z/7zCompressionMode.h +++ b/CPP/7zip/Archive/7z/7zCompressionMode.h @@ -13,9 +13,6 @@ struct CMethodFull: public CMethodProps { CMethodId Id; UInt32 NumStreams; - int CodecIndex; - - CMethodFull(): CodecIndex(-1) {} bool IsSimpleCoder() const { return NumStreams == 1; } }; 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 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 @@ class CDecoder , 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 29ead4df..8700d721 100644 --- a/CPP/7zip/Archive/7z/7zEncode.cpp +++ b/CPP/7zip/Archive/7z/7zEncode.cpp @@ -154,22 +154,10 @@ HRESULT CEncoder::CreateMixerCoder( CCreatedCoder cod; - // RINOK(CreateCoder( - // EXTERNAL_CODECS_LOC_VARS - // methodFull.Id, true, cod)); - - if (methodFull.CodecIndex >= 0) - { - RINOK(CreateCoder_Index( - EXTERNAL_CODECS_LOC_VARS - methodFull.CodecIndex, true, cod)); - } - else - { - RINOK(CreateCoder_Id( + RINOK(CreateCoder( EXTERNAL_CODECS_LOC_VARS methodFull.Id, true, cod)); - } + if (cod.NumStreams != methodFull.NumStreams) return E_FAIL; if (!cod.Coder && !cod.Coder2) @@ -345,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. @@ -382,6 +370,17 @@ HRESULT CEncoder::Encode( resetInitVector->ResetInitVector(); } + { + CMyComPtr optProps; + coder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps); + if (optProps) + { + PROPID propID = NCoderPropID::kExpectedDataSize; + NWindows::NCOM::CPropVariant prop = (UInt64)unpackSize; + RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1)); + } + } + CMyComPtr writeCoderProperties; coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties); @@ -392,7 +391,7 @@ HRESULT CEncoder::Encode( CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream; CMyComPtr dynOutStream(outStreamSpec); outStreamSpec->Init(); - writeCoderProperties->WriteCoderProperties(dynOutStream); + RINOK(writeCoderProperties->WriteCoderProperties(dynOutStream)); outStreamSpec->CopyToBuffer(props); } else @@ -441,10 +440,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/7zFolderInStream.cpp b/CPP/7zip/Archive/7z/7zFolderInStream.cpp index 14cdc436..a68edf4e 100644 --- a/CPP/7zip/Archive/7z/7zFolderInStream.cpp +++ b/CPP/7zip/Archive/7z/7zFolderInStream.cpp @@ -80,14 +80,17 @@ STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSiz { if (_stream) { - UInt32 processed2; - RINOK(_stream->Read(data, size, &processed2)); - if (processed2 != 0) + UInt32 cur = size; + const UInt32 kMax = (UInt32)1 << 20; + if (cur > kMax) + cur = kMax; + RINOK(_stream->Read(data, cur, &cur)); + if (cur != 0) { - _crc = CrcUpdate(_crc, data, processed2); - _pos += processed2; + _crc = CrcUpdate(_crc, data, cur); + _pos += cur; if (processedSize) - *processedSize = processed2; + *processedSize = cur; return S_OK; } diff --git a/CPP/7zip/Archive/7z/7zHandler.cpp b/CPP/7zip/Archive/7z/7zHandler.cpp index c1d60fc2..49b4e25b 100644 --- a/CPP/7zip/Archive/7z/7zHandler.cpp +++ b/CPP/7zip/Archive/7z/7zHandler.cpp @@ -450,24 +450,25 @@ HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const GetStringForSizeValue(dest, GetUi32(props + 1)); } } - else if (id == k_Delta) + else if (id == k_LZ4) { - name = "Delta"; - if (propsSize == 1) - ConvertUInt32ToString((UInt32)props[0] + 1, s); - } - else if (id == k_BCJ2) name = "BCJ2"; - else if (id == k_BCJ) name = "BCJ"; - else if (id == k_AES) - { - name = "7zAES"; - if (propsSize >= 1) + name = "LZ4"; + if (propsSize == 3 || propsSize == 5) { - Byte firstByte = props[0]; - UInt32 numCyclesPower = firstByte & 0x3F; - ConvertUInt32ToString(numCyclesPower, s); + char *dest = s; + *dest++ = 'v'; + ConvertUInt32ToString(props[0], dest); + dest += MyStringLen(dest); + *dest++ = '.'; + ConvertUInt32ToString(props[1], dest); + dest += MyStringLen(dest); + *dest++ = ','; + *dest++ = 'l'; + ConvertUInt32ToString(props[2], dest); + dest += MyStringLen(dest); } - }else if (id == k_ZSTD) // 增加 zstd 算法的设置 + } + else if (id == k_ZSTD) { name = "ZSTD"; if (propsSize == 3 || propsSize == 5) @@ -492,6 +493,24 @@ HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const dest += MyStringLen(dest); } } + else if (id == k_Delta) + { + name = "Delta"; + if (propsSize == 1) + ConvertUInt32ToString((UInt32)props[0] + 1, s); + } + else if (id == k_BCJ2) name = "BCJ2"; + else if (id == k_BCJ) name = "BCJ"; + else if (id == k_AES) + { + name = "7zAES"; + if (propsSize >= 1) + { + Byte firstByte = props[0]; + UInt32 numCyclesPower = firstByte & 0x3F; + ConvertUInt32ToString(numCyclesPower, s); + } + } } if (name) @@ -564,7 +583,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) { @@ -599,7 +618,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 @@ class COutHandler: public CMultiMethodProps 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 4873cfde..6e8de0ba 100644 --- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp +++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp @@ -18,13 +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_ZSTD_Name = "ZSTD"; -//static const char *kDefaultMethodName = "ZSTD"; -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 = @@ -42,11 +41,9 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m) { - dest.CodecIndex = FindMethod_Index( + if (!FindMethod( EXTERNAL_CODECS_VARS - m.MethodName, true, - dest.Id, dest.NumStreams); - if (dest.CodecIndex < 0) + m.MethodName, dest.Id, dest.NumStreams)) return E_INVALIDARG; (CProps &)dest = (CProps &)m; return S_OK; @@ -57,10 +54,9 @@ HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod) if (!_compressHeaders) return S_OK; COneMethodInfo m; - m.MethodName = k_LZMA_Name; // k_ZSTD_Name zstd compress rate lower than lzma + m.MethodName = k_LZMA_Name; m.AddProp_Ascii(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders); m.AddProp_Level(k_Level_ForHeaders); - // m.AddProp_Level(22); // zstd level set m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders); m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders); m.AddProp_NumThreads(1); @@ -118,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)); @@ -287,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++) { @@ -312,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) { @@ -339,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)); @@ -543,14 +543,14 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt CCompressionMethodMode methodMode, headerMethod; - HRESULT res = SetMainMethod(methodMode // 设置主压缩算法 + HRESULT res = SetMainMethod(methodMode #ifndef _7ZIP_ST , _numThreads #endif ); RINOK(res); - RINOK(SetHeaderMethod(headerMethod)); // 设置尾部头压缩算法 + RINOK(SetHeaderMethod(headerMethod)); #ifndef _7ZIP_ST methodMode.NumThreads = _numThreads; @@ -612,7 +612,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt options.Method = &methodMode; options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL; options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted); - options.MaxFilter = (level >= 8); + // options.MaxFilter = (level >= 8); options.AnalysisLevel = GetAnalysisLevel(); options.HeaderOptions.CompressMainHeader = compressMainHeader; @@ -620,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; @@ -711,6 +712,7 @@ void COutHandler::InitProps() Write_CTime.Init(); Write_ATime.Init(); Write_MTime.Init(); + Write_Attrib.Init(); _useMultiThreadMixer = true; @@ -836,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/7zHeader.h b/CPP/7zip/Archive/7z/7zHeader.h index b4166064..4306b05c 100644 --- a/CPP/7zip/Archive/7z/7zHeader.h +++ b/CPP/7zip/Archive/7z/7zHeader.h @@ -119,9 +119,11 @@ const UInt32 k_ARM = 0x3030501; const UInt32 k_ARMT = 0x3030701; const UInt32 k_SPARC = 0x3030805; +const UInt32 k_ZSTD = 0x4F71001; +const UInt32 k_LZ4 = 0x4F71001; + const UInt32 k_AES = 0x6F10701; -const UInt32 k_ZSTD = 0x4F71101; static inline bool IsFilterMethod(UInt64 m) { diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp index 53ab8542..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 outStream = outStreamSpec; outStreamSpec->Init(data, unpackSize); + bool dataAfterEnd_Error = false; + HRESULT result = decoder.Decode( EXTERNAL_CODECS_LOC_VARS _stream, baseOffset + dataOffset, @@ -1083,23 +1110,31 @@ 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(); } - if(folders.PackPositions){ + + if (folders.PackPositions) HeadersSize += folders.PackPositions[folders.NumPackStreams]; - } + return S_OK; } @@ -1147,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()) @@ -1168,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; @@ -1196,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); @@ -1215,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++) @@ -1263,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; @@ -1313,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()); @@ -1358,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]; @@ -1384,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); @@ -1465,6 +1484,7 @@ void CDbEx::FillLinks() } } + HRESULT CInArchive::ReadDatabase2( DECL_EXTERNAL_CODECS_LOC_VARS CDbEx &db @@ -1609,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 @@ struct CFolder } }; + 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..aa977292 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 &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]); } @@ -520,7 +515,7 @@ HRESULT COutArchive::EncodeStream( outFolders.FolderUnpackCRCs.Vals.Add(CrcCalc(data, data.Size())); // outFolders.NumUnpackStreamsVector.Add(1); UInt64 dataSize64 = data.Size(); - UInt64 unpackSize; + UInt64 unpackSize = data.Size(); RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS stream, @@ -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 @@ class CWriteBufferLoc 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 PackSizes; @@ -123,10 +132,11 @@ struct CArchiveDatabaseOut: public COutFolders CUInt64DefVector ATime; CUInt64DefVector MTime; CUInt64DefVector StartPos; - CRecordVector IsAnti; + CUInt32DefVector Attrib; + CBoolVector IsAnti; /* - CRecordVector IsAux; + CBoolVector IsAux; CByteBuffer SecureBuf; CRecordVector 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 &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 ec70d107..1cc999b0 100644 --- a/CPP/7zip/Archive/7z/7zUpdate.cpp +++ b/CPP/7zip/Archive/7z/7zUpdate.cpp @@ -21,10 +21,6 @@ #include "7zOut.h" #include "7zUpdate.h" -#ifndef WIN32 -#include "Windows/FileIO.h" -#endif - namespace NArchive { namespace N7z { @@ -42,7 +38,7 @@ struct CFilterMode { if (Id == k_IA64) Delta = 16; - else if (Id == k_ARM || Id == k_PPC || Id == k_PPC) + else if (Id == k_ARM || Id == k_PPC || Id == k_SPARC) Delta = 4; else if (Id == k_ARMT) Delta = 2; @@ -562,7 +558,7 @@ static int CompareEmptyItems(const unsigned *p1, const unsigned *p2, void *param } static const char *g_Exts = - " 7z xz lzma ace arc arj bz tbz bz2 tbz2 cab deb gz tgz ha lha lzh lzo lzx pak rar rpm sit zoo" + " 7z xz lzma ace arc arj bz tbz bz2 tbz2 cab deb gz tgz ha lha lz4 tlz4 lzh lzo lzx pak rar rpm sit zoo zst" " zip jar ear war msi" " 3gp avi mov mpeg mpg mpe wmv" " aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav" @@ -783,7 +779,7 @@ struct CSolidGroup CRecordVector folderRefs; }; -static const char *g_ExeExts[] = +static const char * const g_ExeExts[] = { "dll" , "exe" @@ -800,41 +796,6 @@ static bool IsExeExt(const wchar_t *ext) return false; } -#ifndef _WIN32 -static bool IsExeFile(const CUpdateItem &ui) -{ - int dotPos = ui.Name.ReverseFind(L'.'); - if (dotPos >= 0) - if (IsExeExt(ui.Name.Ptr(dotPos + 1)) ) return true; - - if (ui.Attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) { - unsigned short st_mode = ui.Attrib >> 16; - if ((st_mode & 00111) && (ui.Size >= 2048)) - { - // file has the execution flag and it's big enought - // try to find if the file is a script - NWindows::NFile::NIO::CInFile file; - if (file.Open(ui.Name)) - { - char buffer[2048]; - UINT32 processedSize; - if (file.Read(buffer,sizeof(buffer),processedSize)) - { - for(UInt32 i = 0; i < processedSize ; i++) - { - if (buffer[i] == 0) - { - return true; // this file is not a text (ascii, utf8, ...) ! - } - } - } - } - } - } - return false; -} -#endif - struct CAnalysis { CMyComPtr Callback; @@ -893,11 +854,7 @@ HRESULT CAnalysis::GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMo } } -#ifdef _WIN32 if (IsExeExt(ext)) -#else - if (IsExeFile(ui)) -#endif { needReadFile = true; #ifdef _WIN32 @@ -1131,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; @@ -1150,6 +1112,8 @@ static void FromUpdateItemToFileItem(const CUpdateItem &ui, // file.IsAltStream = ui.IsAltStream; } + + class CRepackInStreamWithSizes: public ISequentialInStream, public ICompressGetSubStreamSize, @@ -1480,6 +1444,7 @@ class CThreadDecoder #ifndef _7ZIP_ST + bool dataAfterEnd_Error; HRESULT Result; CMyComPtr InStream; @@ -1522,7 +1487,9 @@ void CThreadDecoder::Execute() bool passwordIsDefined = false; UString password; #endif - + + dataAfterEnd_Error = false; + Result = Decoder.Decode( EXTERNAL_CODECS_LOC_VARS InStream, @@ -1534,12 +1501,15 @@ void CThreadDecoder::Execute() Fos, NULL, // compressProgress + NULL // *inStreamMainRes + , dataAfterEnd_Error _7Z_DECODER_CRYPRO_VARS #ifndef _7ZIP_ST , MtMode, NumThreads #endif + ); } catch(...) @@ -1584,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); } @@ -1880,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); } @@ -1930,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 @@ -1994,7 +1966,7 @@ HRESULT Update( method.Password.Empty(); } - CEncoder encoder(method); // 生成对应算法的 encoder 对象 + CEncoder encoder(method); // ---------- Repack and copy old solid blocks ---------- @@ -2150,6 +2122,8 @@ HRESULT Update( #endif CMyComPtr decodedStream; + bool dataAfterEnd_Error = false; + HRESULT res = threadDecoder.Decoder.Decode( EXTERNAL_CODECS_LOC_VARS inStream, @@ -2160,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); @@ -2194,6 +2171,7 @@ HRESULT Update( #endif } + curUnpackSize = sizeToEncode; HRESULT encodeRes = encoder.Encode( EXTERNAL_CODECS_LOC_VARS @@ -2218,16 +2196,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) @@ -2267,12 +2248,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]; @@ -2281,17 +2257,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) @@ -2335,7 +2315,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) @@ -2380,6 +2360,8 @@ HRESULT Update( unsigned startPackIndex = newDatabase.PackSizes.Size(); UInt64 curFolderUnpackSize = totalSize; + // curFolderUnpackSize = (UInt64)(Int64)-1; + RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS solidInStream, @@ -2410,7 +2392,7 @@ HRESULT Update( UString name; if (ui.NewProps) { - FromUpdateItemToFileItem(ui, file, file2); + UpdateItem_To_FileItem(ui, file, file2); name = ui.Name; } else @@ -2429,7 +2411,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/Common/CoderMixer2.cpp b/CPP/7zip/Archive/Common/CoderMixer2.cpp index 7ca353dc..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 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 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; @@ -1003,7 +1078,7 @@ HRESULT CMixerMT::Code( if (i != MainCoderIndex) _coders[i].Start(); - _coders[MainCoderIndex].Code(progress); // code Enter + _coders[MainCoderIndex].Code(progress); for (i = 0; i < _coders.Size(); i++) if (i != MainCoderIndex) @@ -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 @@ class CCoder CRecordVector PackSizes; CRecordVector 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 @@ class CMixer public: unsigned MainCoderIndex; + // bool InternalPackSizeError; + CMixer(bool encodeMode): EncodeMode(encodeMode), MainCoderIndex(0) + // , InternalPackSizeError(false) {} /* @@ -273,11 +280,12 @@ class CMixer 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 @@ class CMixerST: 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 @@ class CMixerMT: 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 35d58211..ea320e66 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.cpp +++ b/CPP/7zip/Archive/Common/HandlerOut.cpp @@ -27,20 +27,12 @@ void CMultiMethodProps::SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level); } -void CMultiMethodProps::SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo - #ifndef _7ZIP_ST - , UInt32 numThreads - #endif - ) +#ifndef _7ZIP_ST +void CMultiMethodProps::SetMethodThreadsTo(COneMethodInfo &oneMethodInfo, UInt32 numThreads) { - UInt32 level = _level; - if (level != (UInt32)(Int32)-1) - SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level); - - #ifndef _7ZIP_ST SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); - #endif } +#endif void CMultiMethodProps::Init() { @@ -80,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 ef5b3e50..e24686da 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.h +++ b/CPP/7zip/Archive/Common/HandlerOut.h @@ -22,14 +22,13 @@ class CMultiMethodProps COneMethodInfo _filterMethod; bool _autoFilter; - + void SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const; - void SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo - #ifndef _7ZIP_ST - , UInt32 numThreads - #endif - ); + #ifndef _7ZIP_ST + static void SetMethodThreadsTo(COneMethodInfo &oneMethodInfo, UInt32 numThreads); + #endif + unsigned GetNumEmptyMethods() const { 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 _inStream; CObjectVector _files; bool _masterCrcError; + bool _headersError; UInt64 _startPos; UInt64 _phySize; + + AString _name; #ifdef DMG_SHOW_RAW CObjectVector _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 = " 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 1c3c7c45..62674774 100644 --- a/CPP/7zip/Archive/ElfHandler.cpp +++ b/CPP/7zip/Archive/ElfHandler.cpp @@ -156,23 +156,23 @@ bool CHeader::Parse(const Byte *p) #define PT_PHDR 6 -static const char *g_SegnmentTypes[] = +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,21 +596,60 @@ static const CUInt32PCharPair g_OS[] = { 255, "Standalone" } }; +#define k_Machine_MIPS 8 +#define k_Machine_ARM 40 + +/* +#define EF_ARM_ABIMASK 0xFF000000 +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_GCCMASK 0x00400FFF +#define EF_ARM_ABI_FLOAT_SOFT 0x00000200 +#define EF_ARM_ABI_FLOAT_HARD 0x00000400 +*/ + +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 #define ET_DYN 3 #define ET_CORE 4 -static const char *g_Types[] = +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" }; + + + class CHandler: public IInArchive, public IArchiveAllowTail, @@ -622,8 +703,7 @@ static const Byte kArcProps[] = kpidBigEndian, kpidHostOS, kpidCharacts, - kpidHeadersSize, - kpidName + kpidHeadersSize }; enum @@ -659,7 +739,57 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break; case kpidBigEndian: if (_header.Be) prop = _header.Be; break; case kpidShortComment: - case kpidCpu: PAIR_TO_PROP(g_Machines, _header.Machine, prop); break; + + case kpidCpu: + { + 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) + { + 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:"; + 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; + } + } + prop = s; + break; + } + case kpidHostOS: PAIR_TO_PROP(g_OS, _header.Os, prop); break; case kpidCharacts: TYPE_TO_PROP(g_Types, _header.Type, prop); break; case kpidExtension: diff --git a/CPP/7zip/Archive/ExtHandler.cpp b/CPP/7zip/Archive/ExtHandler.cpp index 6c2cd726..d8417fe5 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 }; @@ -480,8 +461,8 @@ bool CHeader::Parse(const Byte *p) if (Is64Bit()) { - HI_32(150, NumBlocks); - // HI_32(154, NumBlocksSuper); + HI_32(0x150, NumBlocks); + // HI_32(0x154, NumBlocksSuper); HI_32(0x158, NumFreeBlocks); } @@ -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/FlvHandler.cpp b/CPP/7zip/Archive/FlvHandler.cpp index 72ccd993..1f52f60b 100644 --- a/CPP/7zip/Archive/FlvHandler.cpp +++ b/CPP/7zip/Archive/FlvHandler.cpp @@ -93,7 +93,7 @@ static const Byte kProps[] = IMP_IInArchive_Props IMP_IInArchive_ArcProps_NO_Table -static const char *g_AudioTypes[16] = +static const char * const g_AudioTypes[16] = { "pcm" , "adpcm" @@ -113,7 +113,7 @@ static const char *g_AudioTypes[16] = , "audio15" }; -static const char *g_VideoTypes[16] = +static const char * const g_VideoTypes[16] = { "video0" , "jpeg" @@ -133,7 +133,7 @@ static const char *g_VideoTypes[16] = , "video15" }; -static const char *g_Rates[4] = +static const char * const g_Rates[4] = { "5.5 kHz" , "11 kHz" diff --git a/CPP/7zip/Archive/GptHandler.cpp b/CPP/7zip/Archive/GptHandler.cpp index 53e941c7..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); } @@ -244,9 +222,31 @@ HRESULT CHandler::Open2(IInStream *stream) _items.Add(item); } - UInt64 end = (backupLba + 1) * kSectorSize; - if (_totalSize < end) - _totalSize = end; + { + const UInt64 end = (backupLba + 1) * kSectorSize; + if (_totalSize < end) + _totalSize = end; + } + + { + UInt64 fileEnd; + RINOK(stream->Seek(0, STREAM_SEEK_END, &fileEnd)); + + if (_totalSize < fileEnd) + { + const UInt64 rem = fileEnd - _totalSize; + const UInt64 kRemMax = 1 << 22; + if (rem <= kRemMax) + { + RINOK(stream->Seek(_totalSize, STREAM_SEEK_SET, NULL)); + bool areThereNonZeros = false; + UInt64 numZeros = 0; + if (ReadZeroTail(stream, areThereNonZeros, numZeros, kRemMax) == S_OK) + if (!areThereNonZeros) + _totalSize += numZeros; + } + } + } return S_OK; } @@ -306,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; } @@ -342,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; @@ -372,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; @@ -382,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 abf8bef6..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,17 +497,20 @@ 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); FirstLeafNode = Get32(p + 0xA); // LastLeafNode = Get32(p + 0xE); - UInt32 nodeSize = Get16(p + 0x12); + const UInt32 nodeSize = Get16(p + 0x12); unsigned i; for (i = 9; ((UInt32)1 << i) != nodeSize; i++) @@ -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) @@ -583,9 +587,9 @@ HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjec for (unsigned i = 0; i < desc.NumRecords; i++) { - UInt32 nodeSize = (UInt32)1 << hr.NodeSizeLog; - UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2); - UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2); + const UInt32 nodeSize = (UInt32)1 << hr.NodeSizeLog; + const UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2); + const UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2); if (offs > nodeSize || offsNext > nodeSize) return S_FALSE; UInt32 recSize = offsNext - offs; @@ -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; @@ -727,12 +728,12 @@ HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpe for (unsigned i = 0; i < desc.NumRecords; i++) { - UInt32 nodeSize = (1 << hr.NodeSizeLog); - UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2); - UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2); + const UInt32 nodeSize = (1 << hr.NodeSizeLog); + const UInt32 offs = Get16(p + nodeOffset + nodeSize - (i + 1) * 2); + const UInt32 offsNext = Get16(p + nodeOffset + nodeSize - (i + 2) * 2); UInt32 recSize = offsNext - offs; if (offs >= nodeSize - || offsNext >= nodeSize + || offsNext > nodeSize || offsNext < offs) return S_FALSE; @@ -876,13 +877,10 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector> hr.NodeSizeLog) < hr.TotalNodes) - return S_FALSE; - CByteBuffer usedBuf(hr.TotalNodes); memset(usedBuf, 0, hr.TotalNodes); @@ -898,7 +896,7 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector= nodeSize - || offs >= nodeSize + || offsNext > nodeSize || offsNext < offs || recSize < 6) return S_FALSE; @@ -966,13 +964,13 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector> 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,8 +220,8 @@ struct CItem AString GetName() const { - AString dirName = GetDirName(); - const char kDirSeparator = CHAR_PATH_SEPARATOR; // '\\'; + AString dirName (GetDirName()); + const char kDirSeparator = '\\'; // check kDirSeparator in Linux dirName.Replace((char)(unsigned char)0xFF, kDirSeparator); if (!dirName.IsEmpty() && dirName.Back() != 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 @@ class COutStreamWithCRC: STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); private: - CCRC _crc; + UInt32 _crc; CMyComPtr _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 @@ -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/MachoHandler.cpp b/CPP/7zip/Archive/MachoHandler.cpp index 9dae1e70..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" }, @@ -75,7 +78,7 @@ static const CUInt32PCharPair g_CpuPairs[] = #define SECT_ATTR_ZEROFILL 1 -static const char *g_SectTypes[] = +static const char * const g_SectTypes[] = { "REGULAR" , "ZEROFILL" @@ -108,7 +111,7 @@ enum EFileType kType_DSYM }; -static const char *g_FileTypes[] = +static const char * const g_FileTypes[] = { "0" , "OBJECT" @@ -124,7 +127,7 @@ static const char *g_FileTypes[] = }; -static const char *g_ArcFlags[] = +static const char * const g_ArcFlags[] = { "NOUNDEFS" , "INCRLINK" @@ -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/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp index 93e9f88f..0eebf005 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; @@ -341,15 +341,19 @@ bool CVolInfo::Parse(const Byte *p, unsigned size) struct CAttr { UInt32 Type; + + Byte NonResident; + + // Non-Resident + Byte CompressionUnit; + // UInt32 Len; UString2 Name; // UInt16 Flags; // UInt16 Instance; CByteBuffer Data; - Byte NonResident; // Non-Resident - Byte CompressionUnit; UInt64 LowVcn; UInt64 HighVcn; UInt64 AllocatedSize; @@ -394,7 +398,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); } @@ -408,15 +412,16 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size) return 8; // required size is 4, but attributes are 8 bytes aligned. So we return 8 if (size < 0x18) return 0; + PRF(printf(" T=%2X", Type)); - UInt32 len = Get32(p + 0x04); + UInt32 len = Get32(p + 4); PRF(printf(" L=%3d", len)); if (len > size) return 0; if ((len & 7) != 0) return 0; - NonResident = p[0x08]; + NonResident = p[8]; { unsigned nameLen = p[9]; UInt32 nameOffset = Get16(p + 0x0A); @@ -437,6 +442,7 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size) UInt32 dataSize; UInt32 offs; + if (NonResident) { if (len < 0x40) @@ -472,16 +478,19 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size) { if (len < 0x18) return 0; + G32(p + 0x10, dataSize); + G16(p + 0x14, offs); + // G16(p + 0x16, ResidentFlags); PRF(printf(" RES")); - dataSize = Get32(p + 0x10); PRF(printf(" dataSize=%3d", dataSize)); - offs = Get16(p + 0x14); - // G16(p + 0x16, ResidentFlags); // PRF(printf(" ResFlags=%4X", ResidentFlags)); } + if (offs > len || dataSize > len || len - dataSize < offs) return 0; + Data.CopyFrom(p + offs, dataSize); + #ifdef SHOW_DEBUG_INFO PRF(printf(" : ")); for (unsigned i = 0; i < Data.Size(); i++) @@ -489,16 +498,19 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size) PRF(printf(" %02X", (unsigned)Data[i])); } #endif + return len; } + bool CAttr::ParseExtents(CRecordVector &extents, UInt64 numClustersMax, unsigned compressionUnit) const { const Byte *p = Data; unsigned size = (unsigned)Data.Size(); UInt64 vcn = LowVcn; UInt64 lcn = 0; - UInt64 highVcn1 = HighVcn + 1; + const UInt64 highVcn1 = HighVcn + 1; + if (LowVcn != extents.Back().Virt || highVcn1 > (UInt64)1 << 63) return false; @@ -528,15 +540,30 @@ bool CAttr::ParseExtents(CRecordVector &extents, UInt64 numClustersMax, if ((highVcn1 - vcn) < vSize) return false; + CExtent e; + e.Virt = vcn; + vcn += vSize; + num = (b >> 4) & 0xF; if (num > 8 || num > size) return false; - CExtent e; - e.Virt = vcn; + if (num == 0) { + // Sparse + + /* if Unit is compressed, it can have many Elements for each compressed Unit: + and last Element for unit MUST be without LCN. + Element 0: numCompressedClusters2, LCN_0 + Element 1: numCompressedClusters2, LCN_1 + ... + Last Element : (16 - total_clusters_in_previous_elements), no LCN + */ + + // sparse is not allowed for (compressionUnit == 0) ? Why ? if (compressionUnit == 0) return false; + e.Phy = kEmptyExtent; } else @@ -553,9 +580,10 @@ bool CAttr::ParseExtents(CRecordVector &extents, UInt64 numClustersMax, return false; e.Phy = lcn; } + extents.Add(e); - vcn += vSize; } + CExtent e; e.Phy = kEmptyExtent; e.Virt = vcn; @@ -563,10 +591,11 @@ bool CAttr::ParseExtents(CRecordVector &extents, UInt64 numClustersMax, return (highVcn1 == vcn); } + static const UInt64 kEmptyTag = (UInt64)(Int64)-1; static const unsigned kNumCacheChunksLog = 1; -static const size_t kNumCacheChunks = (1 << kNumCacheChunksLog); +static const size_t kNumCacheChunks = (size_t)1 << kNumCacheChunksLog; class CInStream: public IInStream, @@ -734,24 +763,27 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) while (_curRem == 0) { - UInt64 cacheTag = _virtPos >> _chunkSizeLog; - UInt32 cacheIndex = (UInt32)cacheTag & (kNumCacheChunks - 1); + const UInt64 cacheTag = _virtPos >> _chunkSizeLog; + const size_t cacheIndex = (size_t)cacheTag & (kNumCacheChunks - 1); + if (_tags[cacheIndex] == cacheTag) { - UInt32 chunkSize = (UInt32)1 << _chunkSizeLog; - UInt32 offset = (UInt32)_virtPos & (chunkSize - 1); - UInt32 cur = MyMin(chunkSize - offset, size); + const size_t chunkSize = (size_t)1 << _chunkSizeLog; + const size_t offset = (size_t)_virtPos & (chunkSize - 1); + size_t cur = chunkSize - offset; + if (cur > size) + cur = size; memcpy(data, _outBuf + (cacheIndex << _chunkSizeLog) + offset, cur); - *processedSize = cur; + *processedSize = (UInt32)cur; _virtPos += cur; return S_OK; } PRF2(printf("\nVirtPos = %6d", _virtPos)); - UInt32 comprUnitSize = (UInt32)1 << CompressionUnit; - UInt64 virtBlock = _virtPos >> BlockSizeLog; - UInt64 virtBlock2 = virtBlock & ~((UInt64)comprUnitSize - 1); + const UInt32 comprUnitSize = (UInt32)1 << CompressionUnit; + const UInt64 virtBlock = _virtPos >> BlockSizeLog; + const UInt64 virtBlock2 = virtBlock & ~((UInt64)comprUnitSize - 1); unsigned left = 0, right = Extents.Size(); for (;;) @@ -766,7 +798,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) } bool isCompressed = false; - UInt64 virtBlock2End = virtBlock2 + comprUnitSize; + const UInt64 virtBlock2End = virtBlock2 + comprUnitSize; if (CompressionUnit != 0) for (unsigned i = left; i < Extents.Size(); i++) { @@ -802,7 +834,9 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) _curRem = next - _virtPos; break; } + bool thereArePhy = false; + for (unsigned i2 = left; i2 < Extents.Size(); i2++) { const CExtent &e = Extents[i2]; @@ -814,6 +848,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) break; } } + if (!thereArePhy) { _curRem = (Extents[i + 1].Virt << BlockSizeLog) - _virtPos; @@ -823,6 +858,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) size_t offs = 0; UInt64 curVirt = virtBlock2; + for (i = left; i < Extents.Size(); i++) { const CExtent &e = Extents[i]; @@ -845,6 +881,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) _physPos += compressed; offs += compressed; } + size_t destLenMax = GetCuSize(); size_t destLen = destLenMax; const UInt64 rem = Size - (virtBlock2 << BlockSizeLog); @@ -863,6 +900,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) return S_FALSE; } } + if (size > _curRem) size = (UInt32)_curRem; HRESULT res = S_OK; @@ -913,6 +951,12 @@ static HRESULT DataParseExtents(unsigned clusterSizeLog, const CObjectVector> clusterSizeLog)) + { + } + */ + if (attr0.AllocatedSize < attr0.Size || (attrs[attrIndexLim - 1].HighVcn + 1) != (attr0.AllocatedSize >> clusterSizeLog) || (attr0.AllocatedSize & ((1 << clusterSizeLog) - 1)) != 0) @@ -2157,7 +2201,7 @@ STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data return S_OK; const CItem &item = Items[index]; const CMftRec &rec = Recs[item.RecIndex]; - if (rec.SiAttr.SecurityId >= 0) + if (rec.SiAttr.SecurityId > 0) { UInt64 offset; UInt32 size; @@ -2169,6 +2213,7 @@ STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data } } } + return S_OK; } @@ -2339,7 +2384,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]; @@ -2349,12 +2394,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; } @@ -2721,18 +2763,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 51087166..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 { @@ -321,7 +315,7 @@ bool COptHeader::Parse(const Byte *p, UInt32 size) if (NumDirItems > (1 << 16)) return false; pos += 4; - if (pos + 8 * NumDirItems != size) + if (pos + 8 * NumDirItems > size) return false; for (UInt32 i = 0; i < NumDirItems && i < kNumDirItemsMax; i++) DirItems[i].Parse(p + pos + i * 8); @@ -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 5404f959..35090e7f 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 _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 @@ struct CRangeDecoder extern "C" { +#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(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size) { - CRangeDecoder *p = (CRangeDecoder *)pp; + GET_RangeDecoder start *= p->Range; p->Low += start; p->Code -= start; @@ -269,15 +277,15 @@ static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size) 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->s, 0, size0); + Range_Decode(&p->vt, 0, size0); return 0; } else { - Range_Decode(&p->s, size0, (1 << 14) - size0); + Range_Decode(&p->vt, size0, (1 << 14) - size0); return 1; } } @@ -286,9 +294,9 @@ static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *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 @@ -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 5e0028fa..c4225426 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[] = { - { 0, "Volume" }, - { 1, "VolumeField" }, - { 2, "Solid" }, - { 3, "Recovery" }, - { 4, "Lock" } + "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" + , "UnixSymLink" + , "WinSymLink" + , "WinJunction" + , "HardLink" + , "FileCopy" +}; + + +static const char g_ExtraTimeFlags[] = { 'u', 'M', 'C', 'A', 'n' }; + template 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; } @@ -231,6 +401,18 @@ bool CItem::Is_CopyLink() const return FindExtra_Link(link) && link.Type == NLinkType::kFileCopy; } +bool CItem::Is_HardLink() const +{ + CLinkInfo link; + return FindExtra_Link(link) && link.Type == NLinkType::kHardLink; +} + +bool CItem::Is_CopyLink_or_HardLink() const +{ + CLinkInfo link; + return FindExtra_Link(link) && (link.Type == NLinkType::kFileCopy || link.Type == NLinkType::kHardLink); +} + void CItem::Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const { CLinkInfo link; @@ -263,7 +445,7 @@ 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); @@ -566,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; @@ -589,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; @@ -917,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) { @@ -1011,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) @@ -1178,10 +1360,10 @@ static const Byte kProps[] = kpidCRC, kpidHostOS, kpidMethod, - + kpidCharacts, kpidSymLink, kpidHardLink, - kpidCopyLink, + kpidCopyLink }; @@ -1296,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; } @@ -1327,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; } @@ -1440,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; @@ -1458,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; @@ -1525,12 +1718,12 @@ 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); @@ -1611,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) @@ -1633,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++ = ':'; @@ -1654,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]; @@ -1776,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); @@ -2587,7 +2821,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { if (testMode) { - if (item->Is_CopyLink() && item->PackSize == 0) + if (item->NeedUse_as_CopyLink_or_HardLink()) { RINOK(extractCallback->PrepareOperation(askMode)); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); @@ -2599,6 +2833,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (item->IsService()) continue; + if (item->NeedUse_as_HardLink()) + continue; + bool needDecode = false; for (unsigned n = i + 1; n < _refs.Size(); n++) @@ -2639,7 +2876,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; } - if (item->Is_CopyLink() && item->PackSize == 0) + if (item->NeedUse_as_CopyLink()) { RINOK(extractCallback->SetOperationResult( realOutStream ? diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.h b/CPP/7zip/Archive/Rar/Rar5Handler.h index cf741c7c..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,19 +265,15 @@ 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; + bool Is_HardLink() const; + bool Is_CopyLink_or_HardLink() const; bool NeedUse_as_CopyLink() const { return PackSize == 0 && Is_CopyLink(); } + bool NeedUse_as_HardLink() const { return PackSize == 0 && Is_HardLink(); } + bool NeedUse_as_CopyLink_or_HardLink() const { return PackSize == 0 && Is_CopyLink_or_HardLink(); } bool GetAltStreamName(AString &name) const; @@ -309,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 52724eb6..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 _unicodeNameBuffer; + UString _unicodeNameBuffer; CByteBuffer _comment; CByteBuffer m_FileHeaderData; NHeader::NBlock::CBlock m_BlockHeader; NCrypto::NRar3::CDecoder *m_RarAESSpec; CMyComPtr m_RarAES; - CBuffer 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; } @@ -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 @@ class CVolumeName } else if (ext.IsEqualTo_Ascii_NoCase("exe")) { - _after.SetFromAscii(".rar"); + _after = ".rar"; base.DeleteFrom(dotPos); } else if (!newStyle) @@ -76,8 +76,8 @@ class CVolumeName _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 _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 5ddfae3f..61fd9d41 100644 --- a/CPP/7zip/Archive/SquashfsHandler.cpp +++ b/CPP/7zip/Archive/SquashfsHandler.cpp @@ -6,11 +6,13 @@ #include "../../../C/Alloc.h" #include "../../../C/CpuArch.h" #include "../../../C/Xz.h" +#include "../../../C/lz4/lz4.h" #include "../../Common/ComTry.h" #include "../../Common/MyLinux.h" #include "../../Common/IntToString.h" #include "../../Common/StringConvert.h" +#include "../../Common/UTFConvert.h" #include "../../Windows/PropVariantUtils.h" #include "../../Windows/TimeUtils.h" @@ -25,6 +27,7 @@ #include "../Compress/CopyCoder.h" #include "../Compress/ZlibDecoder.h" #include "../Compress/LzmaDecoder.h" +#include "../Compress/ZstdDecoder.h" namespace NArchive { namespace NSquashfs { @@ -59,19 +62,24 @@ UInt64 Get64b(const Byte *p, bool be) { return be ? GetBe64(p) : GetUi64(p); } static const UInt32 kSignature32_LE = 0x73717368; static const UInt32 kSignature32_BE = 0x68737173; static const UInt32 kSignature32_LZ = 0x71736873; +static const UInt32 kSignature32_B2 = 0x73687371; #define kMethod_ZLIB 1 #define kMethod_LZMA 2 #define kMethod_LZO 3 #define kMethod_XZ 4 +#define kMethod_LZ4 5 +#define kMethod_ZSTD 6 static const char * const k_Methods[] = { - "Unknown" + "0" , "ZLIB" , "LZMA" , "LZO" , "XZ" + , "LZ4" + , "ZSTD" }; static const UInt32 kMetadataBlockSizeLog = 13; @@ -109,16 +117,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); @@ -224,6 +232,7 @@ struct CHeader case kSignature32_LE: break; case kSignature32_BE: be = true; break; case kSignature32_LZ: SeveralMethods = true; break; + case kSignature32_B2: SeveralMethods = true; be = true; break; default: return false; } GET_32 (4, NumInodes); @@ -841,6 +850,8 @@ class CHandler: CHeader _h; bool _noPropsLZMA; bool _needCheckLzma; + + UInt32 _openCodePage; CMyComPtr _stream; UInt64 _sizeCalculated; @@ -868,6 +879,9 @@ class CHandler: NCompress::NZlib::CDecoder *_zlibDecoderSpec; CMyComPtr _zlibDecoder; + NCompress::NZSTD::CDecoder *_zstdDecoderSpec; + CMyComPtr _zstdDecoder; + CXzUnpacker _xz; CByteBuffer _inputBuffer; @@ -944,7 +958,8 @@ static const Byte kArcProps[] = kpidClusterSize, kpidBigEndian, kpidCTime, - kpidCharacts + kpidCharacts, + kpidCodePage // kpidNumBlocks }; @@ -959,7 +974,7 @@ static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *src *srcLen = 0; const Byte *destStart = dest; const Byte *srcStart = src; - unsigned mode = 2; + unsigned mode = 0; { if (srcRem == 0) @@ -970,7 +985,7 @@ static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *src src++; srcRem--; b -= 17; - mode = (b < 4 ? 0 : 1); + mode = (b < 4 ? 1 : 4); if (b > srcRem || b > destRem) return S_FALSE; srcRem -= b; @@ -988,6 +1003,7 @@ static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *src UInt32 b = *src++; srcRem--; UInt32 len, back; + if (b >= 64) { srcRem--; @@ -996,7 +1012,7 @@ static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *src } else if (b < 16) { - if (mode == 2) + if (mode == 0) { if (b == 0) { @@ -1013,21 +1029,23 @@ static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *src } } } + b += 3; if (b > srcRem || b > destRem) return S_FALSE; srcRem -= b; destRem -= b; - mode = 1; + mode = 4; do *dest++ = *src++; while (--b); continue; } + srcRem--; back = (b >> 2) + (*src++ << 2); len = 2; - if (mode == 1) + if (mode == 4) { back += (1 << 11); len = 3; @@ -1038,6 +1056,7 @@ static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *src UInt32 bOld = b; b = (b < 32 ? 7 : 31); len = bOld & b; + if (len == 0) { for (len = b;; len += 255) @@ -1053,6 +1072,7 @@ static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *src } } } + len += 2; if (srcRem < 2) return S_FALSE; @@ -1062,38 +1082,39 @@ static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *src srcRem -= 2; if (bOld < 32) { + back += ((bOld & 8) << 11); if (back == 0) { *destLen = dest - destStart; *srcLen = src - srcStart; return S_OK; } - back += ((bOld & 8) << 11) + (1 << 14) - 1; + back += (1 << 14) - 1; } } + back++; if (len > destRem || (size_t)(dest - destStart) < back) return S_FALSE; destRem -= len; Byte *destTemp = dest - back; dest += len; + do { *(destTemp + back) = *destTemp; destTemp++; } while (--len); + b &= 3; + mode = b; if (b == 0) - { - mode = 2; continue; - } if (b > srcRem || b > destRem) return S_FALSE; srcRem -= b; destRem -= b; - mode = 0; *dest++ = *src++; if (b > 1) { @@ -1104,6 +1125,22 @@ static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *src } } +static HRESULT Lz4Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen) +{ + const char *Src = (const char *)src; + char *Dst = (char *)dest; + int compressedSize = (int)*srcLen; + int dstCapacity = (int)*destLen; + // int LZ4_decompress_safe (const char* src, char* dst, int compressedSize, int dstCapacity); + int rv = LZ4_decompress_safe(Src, Dst, compressedSize, dstCapacity); + if (rv == 0) + return S_FALSE; + + *destLen = rv; + return S_OK; +} + + HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize, UInt32 inSize, UInt32 outSizeMax) { if (outBuf) @@ -1144,8 +1181,19 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool if (inSize != _zlibDecoderSpec->GetInputProcessedSize()) return S_FALSE; } - else if (method == kMethod_LZMA) + else if (method == kMethod_ZSTD) { + if (!_zstdDecoder) + { + _zstdDecoderSpec = new NCompress::NZSTD::CDecoder(); + _zstdDecoder = _zstdDecoderSpec; + } + RINOK(_zstdDecoder->Code(_limitedInStream, outStream, NULL, NULL, NULL)); + if (inSize != _zstdDecoderSpec->GetInputProcessedSize()) + return S_FALSE; + } + else if (method == kMethod_LZMA) // lzma + { if (!_lzmaDecoder) { _lzmaDecoderSpec = new NCompress::NLzma::CDecoder(); @@ -1194,6 +1242,10 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool { RINOK(LzoDecode(dest, &destLen, _inputBuffer, &srcLen)); } + else if (method == kMethod_LZ4) + { + RINOK(Lz4Decode(dest, &destLen, _inputBuffer, &srcLen)); + } else { ECoderStatus status; @@ -1327,6 +1379,8 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned return S_FALSE; rem = fileSize; + AString tempString; + CRecordVector tempItems; while (rem != 0) { @@ -1392,7 +1446,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()) @@ -1426,6 +1480,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; @@ -1474,6 +1536,8 @@ HRESULT CHandler::Open2(IInStream *inStream) case kMethod_LZMA: case kMethod_LZO: case kMethod_XZ: + case kMethod_LZ4: + case kMethod_ZSTD: break; default: return E_NOTIMPL; @@ -1700,6 +1764,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb STDMETHODIMP CHandler::Close() { + _openCodePage = CP_UTF8; _sizeCalculated = 0; _limitedInStreamSpec->ReleaseStream(); @@ -1823,6 +1888,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { case kpidMethod: { + char sz[16]; const char *s; if (_noPropsLZMA) s = "LZMA Spec"; @@ -1830,25 +1896,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; } @@ -1869,6 +1937,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; @@ -1886,7 +1972,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; @@ -2114,6 +2210,15 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { CMyComPtr inSeqStream; HRESULT hres = GetStream(index, &inSeqStream); + + { + const CItem &item = _items[index]; + const CNode &node = _nodes[item.Node]; + if (node.IsLink()){ + extractCallback->SetFileSymLinkAttrib(); + } + } + if (hres == S_FALSE || !inSeqStream) { if (hres == E_OUTOFMEMORY) @@ -2206,7 +2311,8 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) static const Byte k_Signature[] = { 4, 'h', 's', 'q', 's', 4, 's', 'q', 's', 'h', - 4, 's', 'h', 's', 'q' }; + 4, 's', 'h', 's', 'q', + 4, 'q', 's', 'h', 's' }; REGISTER_ARC_I( "SquashFS", "squashfs", 0, 0xD2, diff --git a/CPP/7zip/Archive/SwfHandler.cpp b/CPP/7zip/Archive/SwfHandler.cpp index 77d2ad7d..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; @@ -646,7 +646,7 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -static const char *g_TagDesc[92] = +static const char * const g_TagDesc[92] = { "End" , "ShowFrame" @@ -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 31ac4f9b..09b6321a 100644 --- a/CPP/7zip/Archive/Tar/TarHandler.cpp +++ b/CPP/7zip/Archive/Tar/TarHandler.cpp @@ -470,7 +470,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (item->IsSymLink()) { RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len())); - RINOK(extractCallback->SetTarFileSymLinkAttrib()); + RINOK(extractCallback->SetFileSymLinkAttrib()); } else { diff --git a/CPP/7zip/Archive/UefiHandler.cpp b/CPP/7zip/Archive/UefiHandler.cpp index 80692493..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) @@ -225,7 +270,7 @@ enum FV_FILETYPE_FFS_PAD = 0xF0 }; -static const char *g_FileTypes[] = +static const char * const g_FileTypes[] = { "ALL" , "RAW" @@ -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 @@ class CFfsFileHeader 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 @@ class CFfsFileHeader }; #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 inStream = inStreamSpec; - inStreamSpec->Init(src, packSize); CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; CMyComPtr 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 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/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp index 06fbe22f..0baa254d 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; @@ -35,17 +36,22 @@ static const UInt32 kLzmaHeaderSize = 4 + kLzmaPropsSize; class CLzmaEncoder: public ICompressCoder, public ICompressSetCoderProperties, + public ICompressSetCoderPropertiesOpt, public CMyUnknownImp { +public: NCompress::NLzma::CEncoder *EncoderSpec; CMyComPtr 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); + STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); - MY_UNKNOWN_IMP1(ICompressSetCoderProperties) + MY_UNKNOWN_IMP2( + ICompressSetCoderProperties, + ICompressSetCoderPropertiesOpt) }; STDMETHODIMP CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) @@ -69,6 +75,11 @@ STDMETHODIMP CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPV return S_OK; } +STDMETHODIMP CLzmaEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) +{ + return EncoderSpec->SetCoderPropertiesOpt(propIDs, props, numProps); +} + STDMETHODIMP CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) { @@ -81,7 +92,8 @@ CAddCommon::CAddCommon(const CCompressionMethodMode &options): _options(options), _copyCoderSpec(NULL), _cryptoStreamSpec(NULL), - _buf(NULL) + _buf(NULL), + _isLzmaEos(false) {} CAddCommon::~CAddCommon() @@ -114,70 +126,146 @@ HRESULT CAddCommon::CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultC } } + +HRESULT CAddCommon::Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, 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.DescriptorMode = outSeqMode; + + if (_options.PasswordIsDefined) + { + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_ZipCrypto; + if (_options.IsAesMode) + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes; + else + { + if (inSeqMode) + opRes.DescriptorMode = 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 inSeqMode, bool outSeqMode, + UInt32 fileTime, UInt64 expectedDataSize, 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 inCrcStream; + CSequentialInStreamWithCRC *inSecCrcStreamSpec = new CSequentialInStreamWithCRC; + CMyComPtr inCrcStream = inSecCrcStreamSpec; + + CMyComPtr inStream2; + if (!inSeqMode) { - CMyComPtr inStream2; - inStream->QueryInterface(IID_IInStream, (void **)&inStream2); - - if (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(); - */ + // inSeqMode = true; + // inSeqMode must be correct before + return E_FAIL; } } + inSecCrcStreamSpec->SetStream(inStream); + inSecCrcStreamSpec->Init(); + unsigned numTestMethods = _options.MethodSequence.Size(); - - if (numTestMethods > 1 && !inCrcStreamSpec) - numTestMethods = 1; + + bool descriptorMode = outSeqMode; + if (!outSeqMode) + if (inSeqMode && _options.PasswordIsDefined && !_options.IsAesMode) + descriptorMode = true; + opRes.DescriptorMode = descriptorMode; + + if (numTestMethods > 1) + if (inSeqMode || outSeqMode || !inStream2) + numTestMethods = 1; UInt32 crc = 0; bool crc_IsCalculated = false; Byte method = 0; CFilterCoder::C_OutStream_Releaser outStreamReleaser; - opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default; - opRes.FileTimeWasUsed = false; + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; for (unsigned i = 0; i < numTestMethods; i++) { - opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default; - if (inCrcStreamSpec) - RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL)); - RINOK(outStream->SetSize(0)); - RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL)); + opRes.LzmaEos = false; + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; + + if (i != 0) + { + if (inStream2) + { + 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 +275,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 +294,22 @@ HRESULT CAddCommon::Compress( UInt32 check; - // if (inCrcStreamSpec) + if (descriptorMode) + { + // it's Info-ZIP modification for stream_mode descriptor_mode (bit 3 of the general purpose bit flag is set) + check = (fileTime & 0xFFFF); + } + else { 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,9 +323,15 @@ HRESULT CAddCommon::Compress( switch (method) { - case NFileHeader::NCompressionMethod::kStored: + case NCompressionMethod::kStore: { - if (_copyCoderSpec == NULL) + if (descriptorMode) + { + // we still can create descriptor_mode archives with "Store" method, but they are not good for 100% + return E_NOTIMPL; + } + + if (!_copyCoderSpec) { _copyCoderSpec = new NCompress::CCopyCoder; _copyCoder = _copyCoderSpec; @@ -256,15 +349,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 = NFileHeader::NCompressionMethod::kExtractVersion_PPMd; + _compressExtractVersion = NCompressionMethod::kExtractVersion_Xz; + NCompress::NXz::CEncoder *encoder = new NCompress::NXz::CEncoder(); + _compressEncoder = encoder; + } + else if (method == NCompressionMethod::kPPMd) + { + _compressExtractVersion = NCompressionMethod::kExtractVersion_PPMd; NCompress::NPpmdZip::CEncoder *encoder = new NCompress::NPpmdZip::CEncoder(); _compressEncoder = encoder; } @@ -273,14 +373,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 +390,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 +403,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 outStreamNew; if (_options.PasswordIsDefined) outStreamNew = _cryptoStream; @@ -315,6 +426,18 @@ HRESULT CAddCommon::Compress( outStreamNew = outStream; if (_compressExtractVersion > opRes.ExtractVersion) opRes.ExtractVersion = _compressExtractVersion; + + { + CMyComPtr optProps; + _compressEncoder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps); + if (optProps) + { + PROPID propID = NCoderPropID::kExpectedDataSize; + NWindows::NCOM::CPropVariant prop = (UInt64)expectedDataSize; + RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1)); + } + } + RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress)); break; } @@ -332,18 +455,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..ff3251db 100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.h +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.h @@ -26,7 +26,8 @@ struct CCompressingResult UInt32 CRC; UInt16 Method; Byte ExtractVersion; - bool FileTimeWasUsed; + bool DescriptorMode; + bool LzmaEos; }; class CAddCommon @@ -37,6 +38,7 @@ class CAddCommon CMyComPtr _compressEncoder; Byte _compressExtractVersion; + bool _isLzmaEos; CFilterCoder *_cryptoStreamSpec; CMyComPtr _cryptoStream; @@ -50,11 +52,16 @@ class CAddCommon public: CAddCommon(const CCompressionMethodMode &options); ~CAddCommon(); + + HRESULT Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, UInt64 unpackSize, + CCompressingResult &opRes) const; + HRESULT Compress( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, IOutStream *outStream, - UInt32 fileTime, - ICompressProgressInfo *progress, CCompressingResult &operationResult); + bool inSeqMode, bool outSeqMode, + UInt32 fileTime, UInt64 expectedDataSize, + 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 4a7d8709..927b3749 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" @@ -31,7 +31,6 @@ #include "../Common/ItemNameUtils.h" #include "../Common/OutStreamWithCRC.h" -#include "../XzHandler.h" #include "ZipHandler.h" @@ -40,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" @@ -67,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 { @@ -92,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[] = { @@ -117,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++) { @@ -128,6 +148,7 @@ const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id) return NULL; } + static const Byte kProps[] = { kpidPath, @@ -143,9 +164,11 @@ static const Byte kProps[] = kpidComment, kpidCRC, kpidMethod, + kpidCharacts, kpidHostOS, kpidUnpackVer, - kpidVolumeIndex + kpidVolumeIndex, + kpidOffset }; static const Byte kArcProps[] = @@ -153,6 +176,7 @@ static const Byte kArcProps[] = kpidEmbeddedStubSize, kpidBit64, kpidComment, + kpidCharacts, kpidTotalPhySize, kpidIsVolume, kpidVolumeIndex, @@ -194,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; @@ -209,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; } @@ -280,7 +338,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } 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: @@ -300,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; } @@ -376,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; } } @@ -395,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"; @@ -412,41 +491,97 @@ 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) { - ConvertUInt32ToString(id, temp); - s = temp; + if (level & 1) + m += ":eos"; + level &= ~1; + } + else if (id == NFileHeader::NCompressionMethod::kDeflate) + { + 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) { - ConvertUInt32ToString(hostOS, temp); - s = temp; + s.Add_OptSpaced("Local"); + + item.LocalExtra.PrintInfo(s); + + if (item.FromCentral) + { + s.Add_OptSpaced(":"); + s.Add_OptSpaced("Central"); + } + } + + if (item.FromCentral) + { + item.CentralExtra.PrintInfo(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()) + { + if (!s.IsEmpty()) + s.Add_OptSpaced(":"); + s.Add_OptSpaced(s2); + } } - prop = s; + + 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; } @@ -457,6 +592,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); @@ -476,7 +615,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; } @@ -494,16 +633,24 @@ STDMETHODIMP CHandler::Close() class CLzmaDecoder: public ICompressCoder, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, public CMyUnknownImp { +public: NCompress::NLzma::CDecoder *DecoderSpec; CMyComPtr 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() @@ -512,42 +659,43 @@ 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); +} + +STDMETHODIMP CLzmaDecoder::SetFinishMode(UInt32 finishMode) +{ + DecoderSpec->FinishStream = (finishMode != 0); + return S_OK; +} + +STDMETHODIMP CLzmaDecoder::GetInStreamProcessedSize(UInt64 *value) +{ + *value = DecoderSpec->GetInputProcessedSize() + kZipLzmaPropsSize; + return S_OK; } -// class CXzDecoder: -// public ICompressCoder, -// public CMyUnknownImp -// { -// NArchive::NXz::CDecoder _decoder; -// public: -// STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, -// const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); -// MY_UNKNOWN_IMP -// }; -// HRESULT CXzDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, -// const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) -// { -// 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; -// return S_OK; -// } struct CMethodItem @@ -573,12 +721,15 @@ class CZipDecoder CMyComPtr getTextPassword; CObjectVector methodItems; + CLzmaDecoder *lzmaDecoderSpec; public: CZipDecoder(): _zipCryptoDecoderSpec(0), _pkAesDecoderSpec(0), _wzAesDecoderSpec(0), - filterStreamSpec(0) {} + filterStreamSpec(0), + lzmaDecoderSpec(0) + {} HRESULT Decode( DECL_EXTERNAL_CODECS_LOC_VARS @@ -593,19 +744,18 @@ class CZipDecoder }; -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; } } @@ -621,12 +771,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()) @@ -634,27 +787,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 outStream = outStreamSpec; outStreamSpec->SetStream(realOutStream); @@ -682,6 +831,9 @@ HRESULT CZipDecoder::Decode( limitedStreamSpec->SetStream(packStream); limitedStreamSpec->Init(packSize); } + + + res = NExtract::NOperationResult::kDataError; CMyComPtr cryptoFilter; @@ -726,6 +878,8 @@ HRESULT CZipDecoder::Decode( CMyComPtr cryptoSetPassword; RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)); + if (!cryptoSetPassword) + return E_FAIL; if (!getTextPassword) extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); @@ -737,39 +891,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)); } } @@ -782,14 +932,17 @@ 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 NCompress::NXz::CComDecoder; else if (id == NFileHeader::NCompressionMethod::kPPMd) @@ -811,7 +964,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; @@ -843,9 +996,17 @@ HRESULT CZipDecoder::Decode( } #endif + CMyComPtr 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 inStreamNew; if (item.IsEncrypted()) { if (!filterStream) @@ -854,6 +1015,7 @@ HRESULT CZipDecoder::Decode( filterStream = filterStreamSpec; } + filterReleaser.FilterCoder = filterStreamSpec; filterStreamSpec->Filter = cryptoFilter; if (wzAesMode) @@ -870,6 +1032,7 @@ HRESULT CZipDecoder::Decode( } else if (pkAesMode) { + isFullStreamExpected = false; result =_pkAesDecoderSpec->ReadHeader(inStream, item.Crc, item.Size); if (result == S_OK) { @@ -927,7 +1090,70 @@ HRESULT CZipDecoder::Decode( inStreamNew = inStream; if (result == S_OK) - result = coder->Code(inStreamNew, outStream, NULL, &item.Size, compressProgress); + { + CMyComPtr 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 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; @@ -948,19 +1174,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; } @@ -1027,11 +1274,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) @@ -1070,12 +1319,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 e61d2bc5..c9caa7bc 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 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)); @@ -154,6 +197,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt } NItemName::ReplaceSlashes_OsToUnix(name); + bool needSlash = ui.IsDir; const wchar_t kSlash = L'/'; if (!name.IsEmpty()) @@ -194,11 +238,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) @@ -211,6 +281,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt ui.Commented = false; */ } + + if (IntToBool(newData)) { UInt64 size = 0; @@ -226,12 +298,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt largestSizeDefined = true; } ui.Size = size; - - // ui.Size -= ui.Size / 2; } + updateItems.Add(ui); } + CMyComPtr getTextPassword; { CMyComPtr udateCallBack2(callback); @@ -267,48 +339,67 @@ 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 m_Items, updateItems, outStream, m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock, - &options, callback); + options, callback); 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++) { @@ -319,82 +410,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; @@ -403,13 +439,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)); @@ -439,9 +468,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 c71c40fd..9e9918dc 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) { - return Stream->Seek(offset, STREAM_SEEK_SET, NULL); + // 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) +{ + 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 (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 (value == NSignature::kEcd) + 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) @@ -267,7 +459,16 @@ API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size) extraSize -= 4; p += 4; if (dataSize > extraSize) - return k_IsArc_Res_NO; + { + // It can be error on header. + // We want to support such rare case bad archives. + // We use additional checks to reduce false-positive probability. + if (nameSize == 0 + || nameSize > (1 << 9) + || extraSize > (1 << 9)) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; + } if (dataSize > size) return k_IsArc_Res_NEED_MORE; size -= dataSize; @@ -288,398 +489,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; + } +} + + +/* +---------- 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(IInStream *stream, const UInt64 *searchLimit) +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)); + + const size_t avail = GetAvail(); - size_t limit = numBytesInBuffer;; + 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 (searchLimit) + { + if (_cnt > *searchLimit) + break; + UInt64 rem = *searchLimit - _cnt; + if (limitPos > rem) + limitPos = (size_t)rem + 1; + } - if (limit < 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) + while (num != 0) { - size_t skip = _inBuffer.Skip(num); - m_Position += skip; - _processedCnt += skip; - if (skip != num) - throw CUnexpectEnd(); - } - else - { - 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) { - for (UInt64 i = 0; i < num; i++) - ReadByte(); + const UInt64 numFiles64 = numFiles; + return Callback->SetCompleted(&numFiles64, &_cnt); +} +*/ + +HRESULT CInArchive::Skip64(UInt64 num, unsigned numFiles) +{ + 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; } - SafeReadBytes(s.GetBuf(size), size); + char *p = s.GetBuf(size); + SafeRead((Byte *)p, size); + unsigned i = size; + do + { + if (p[i - 1] != 0) + break; + } + 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(); - - UInt32 remain = extraSize; + extra.Clear(); - 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 +1056,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 +1074,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 +1085,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 +1104,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 +1123,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 +1170,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 +1198,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 +1213,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 +1233,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 +1256,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 +1275,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,50 +1287,199 @@ 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; + + // 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; - // !!!! It must be fixed for Zip64 archives - if (Get32(buf + i) == NSignature::kDataDescriptor) + + 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; } @@ -961,32 +1490,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 +1506,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 +1545,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 +1570,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 +1630,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 +1730,25 @@ HRESULT CInArchive::TryReadCd(CObjectVector &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; - } - - _inBuffer.SetStream(stream); + RINOK(SeekToVol(IsMultiVol ? cdInfo.CdDisk : -1, cdOffset)); - _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 +1757,24 @@ HRESULT CInArchive::TryReadCd(CObjectVector &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 +1806,12 @@ HRESULT CInArchive::ReadCd(CObjectVector &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 +1855,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 &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 +1940,18 @@ HRESULT CInArchive::ReadLocals(CObjectVector &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 +1971,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 +1994,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 +2011,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,16 +2019,21 @@ 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()) + { + MissingZip = true; MissingName = volName; + } return S_OK; } - return result; + return res; } @@ -1490,24 +2065,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; @@ -1521,7 +2102,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)); @@ -1532,6 +2112,8 @@ HRESULT CInArchive::ReadVols2(IArchiveOpenVolumeCallback *volCallback, CVols::CSubStreamInfo &ss = Vols.Streams[i]; Vols.NumVols++; + Vols.TotalBytesSize += size; + ss.Stream = stream; ss.Size = size; @@ -1556,11 +2138,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; } @@ -1570,35 +2152,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; } @@ -1608,25 +2201,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()) @@ -1636,11 +2254,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; @@ -1655,10 +2276,6 @@ HRESULT CInArchive::ReadVols() - - - - HRESULT CVols::Read(void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) @@ -1677,7 +2294,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; @@ -1701,47 +2318,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 &items) +HRESULT CInArchive::ReadHeaders(CObjectVector &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 - _inBuffer.SetStream(Stream); + SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2 + 4); - bool needReadCd = true; + CanStartNewVol = false; - if (m_Signature == NSignature::kEcd) + if (_signature == NSignature::kEcd64) + { + // UInt64 ecd64Offset = GetVirtStreamPos() - 4; + IsZip64 = true; + + { + 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; + + { + const unsigned kBufSize = 16; + Byte buf[kBufSize]; + SafeRead(buf, kBufSize); + CLocator locator; + locator.Parse(buf); + if (!locator.IsEmptyArc()) + return S_FALSE; + } + + 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) @@ -1750,15 +2432,15 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector &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 { @@ -1773,9 +2455,10 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector &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; @@ -1809,52 +2492,93 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector &items) CObjectVector 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)); } - RINOK(Stream->Seek(ArcInfo.MarkerPos2, STREAM_SEEK_SET, &m_Position)); - m_Signature = ReadUInt32(); + _cnt = 0; + + 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)); @@ -1862,17 +2586,29 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector &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()) { @@ -1883,13 +2619,13 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector &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; @@ -1897,26 +2633,27 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector &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; @@ -1925,28 +2662,30 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector &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); } @@ -1957,85 +2696,186 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector &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) { - UseDisk_in_SingleVol = true; + if (EcdVolIndex == 0 && Vols.MissingZip && Vols.StartIsExe) + { + Vols.MissingName.Empty(); + Vols.MissingZip = false; + } 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 items2; + // ---------- merge Central Directory Items ---------- + + CRecordVector 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() @@ -2058,10 +2898,10 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector &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; @@ -2074,35 +2914,56 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector &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; } @@ -2112,40 +2973,47 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector &items) HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, IArchiveOpenCallback *callback, CObjectVector &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; } @@ -2153,56 +3021,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()) @@ -2212,7 +3117,7 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, } catch (...) { - _inBufMode = false; + DisableBufMode(); throw; } @@ -2220,16 +3125,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 9b10905e..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,38 +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 Stream; UInt64 Size; + HRESULT SeekToStart() const { return Stream->Seek(0, STREAM_SEEK_SET, NULL); } + CSubStreamInfo(): Size(0) {} }; CObjectVector Streams; - int StreamIndex; + + int StreamIndex; // -1 for StartStream + // -2 for ZipStream at multivol detection code + // >=0 volume index in multivol + bool NeedSeek; - CMyComPtr ZipStream; - bool StartIsExe; // is .exe bool StartIsZ; // is .zip or .zNN bool StartIsZip; // is .zip bool IsUpperCase; - Int32 StartVolIndex; // = (NN - 1), if StartStream is .zNN + bool MissingZip; + + 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; @@ -147,19 +177,27 @@ class CVols 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 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; @@ -173,23 +211,15 @@ class CVols BaseName.Empty(); MissingName.Empty(); + 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; - } }; @@ -208,44 +238,69 @@ class CVolStream: 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 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); @@ -253,21 +308,28 @@ class CInArchive HRESULT ReadCd(CObjectVector &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize); HRESULT ReadLocals(CObjectVector &localItems); - HRESULT ReadHeaders2(CObjectVector &items); + HRESULT ReadHeaders(CObjectVector &items); HRESULT GetVolStream(unsigned vol, UInt64 pos, CMyComPtr &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; @@ -275,9 +337,7 @@ class CInArchive CVols Vols; - IArchiveOpenCallback *Callback; - - CInArchive(): Stream(NULL), Callback(NULL), IsArcOpen(false) {} + CInArchive(): Stream(NULL), StartStream(NULL), Callback(NULL), IsArcOpen(false) {} UInt64 GetPhySize() const { @@ -299,7 +359,6 @@ class CInArchive void ClearRefs(); void Close(); HRESULT Open(IInStream *stream, const UInt64 *searchLimit, IArchiveOpenCallback *callback, CObjectVector &items); - HRESULT ReadHeaders(CObjectVector &items); bool IsOpen() const { return IsArcOpen; } @@ -327,7 +386,8 @@ class CInArchive } - 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 &stream); diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp index 12bc8ad7..885a43cd 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; } @@ -176,13 +266,29 @@ UInt32 CItem::GetWinAttrib() const if (FromCentral) winAttrib = ExternalAttrib; break; -#ifdef FILE_ATTRIBUTE_UNIX_EXTENSION - case NFileHeader::NHostOS::kUnix: - winAttrib = (ExternalAttrib & 0xFFFF0000) | FILE_ATTRIBUTE_UNIX_EXTENSION; - if (winAttrib & (MY_LIN_S_IFDIR << 16)) - winAttrib |= FILE_ATTRIBUTE_DIRECTORY; - return winAttrib; -#endif + case NHostOS::kUnix: + // do we need to clear 16 low bits in this case? + if (FromCentral) + { + /* + Some programs write posix attributes in high 16 bits of ExternalAttrib + Also some programs can write additional marker flag: + 0x8000 - p7zip + 0x4000 - Zip in MacOS + no marker - Info-Zip + + Client code has two options to detect posix field: + 1) check 0x8000 marker. In that case we must add 0x8000 marker here. + 2) check that high 4 bits (file type bits in posix field) of attributes are not zero. + */ + + winAttrib = ExternalAttrib & 0xFFFF0000; + + // #ifndef _WIN32 + winAttrib |= 0x8000; // add posix mode marker + // #endif + } + break; } if (IsDir()) // test it; winAttrib |= FILE_ATTRIBUTE_DIRECTORY; 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 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 @@ class CLocalItem 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..945bd020 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,60 @@ 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(); + return; + // we don't replace local header, if we write Descriptor. + // so local header with Descriptor flag must be written to local header before. + } + + 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 +223,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 +238,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 +273,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 &items, const CByteBuffer *comment) { - SeekToCurPos(); - UInt64 cdOffset = GetCurPos(); FOR_VECTOR (i, items) WriteCentralHeader(items[i]); @@ -252,6 +295,11 @@ void COutArchive::WriteCentralDir(const CObjectVector &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 +309,8 @@ void COutArchive::WriteCentralDir(const CObjectVector &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 +326,23 @@ void COutArchive::WriteCentralDir(const CObjectVector &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 &outStream) { COffsetOutStream *streamSpec = new COffsetOutStream; - CMyComPtr 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 &outStream) { - CMyComPtr 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 @@ class CItemOut: public CItem CItemOut(): NtfsTimeIsDefined(false) {} }; + +// COutArchive can throw CSystemException and COutBufferException + class COutArchive { - CMyComPtr m_Stream; COutBuffer m_OutBuffer; + CMyComPtr 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 &items, const CByteBuffer *comment); - void CreateStreamForCompressing(IOutStream **outStream); - void CreateStreamForCopying(ISequentialOutStream **outStream); + void CreateStreamForCompressing(CMyComPtr &outStream); + void CreateStreamForCopying(CMyComPtr &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 77df016b..24730256 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 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, + bool useDescriptor, 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; @@ -87,7 +94,19 @@ static void SetFileHeader( item.InternalAttrib = 0; // test it item.SetEncrypted(!isDir && options.PasswordIsDefined); - // item.SetDescriptorMode(isSeqMode); + item.SetDescriptorMode(useDescriptor); + + if (isDir) + { + item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir; + item.Method = kMethodForDirectory; + item.PackSize = 0; + item.Size = 0; + item.Crc = 0; + } + + item.LocalExtra.Clear(); + item.CentralExtra.Clear(); if (isDir) { @@ -97,14 +116,20 @@ static void SetFileHeader( 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,16 +166,22 @@ struct CThreadInfo HRESULT Result; CCompressingResult CompressingResult; + bool InSeqMode; + bool OutSeqMode; bool IsFree; UInt32 UpdateIndex; UInt32 FileTime; + UInt64 ExpectedDataSize; CThreadInfo(const CCompressionMethodMode &options): ExitThread(false), ProgressSpec(0), OutStreamSpec(0), Coder(options), - FileTime(0) + InSeqMode(false), + OutSeqMode(false), + FileTime(0), + ExpectedDataSize((UInt64)(Int64)-1) {} HRESULT CreateEvents(CSynchro *sync) @@ -193,7 +214,9 @@ void CThreadInfo::WaitAndCode() Result = Coder.Compress( EXTERNAL_CODECS_LOC_VARS - InStream, OutStream, FileTime, Progress, CompressingResult); + InStream, OutStream, + InSeqMode, OutSeqMode, FileTime, ExpectedDataSize, + Progress, CompressingResult); if (Result == S_OK && Progress) Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize); @@ -220,10 +243,13 @@ class CThreads struct CMemBlocks2: public CMemLockBlocks { - CCompressingResult CompressingResult; - bool Defined; bool Skip; - CMemBlocks2(): Defined(false), Skip(false) {} + bool InSeqMode; + bool PreDescriptorMode; + bool Finished; + CCompressingResult CompressingResult; + + CMemBlocks2(): Skip(false), InSeqMode(false), PreDescriptorMode(false), Finished(false) {} }; class CMemRefs @@ -342,6 +368,8 @@ static HRESULT UpdateItemOldData( NUpdateNotifyOp::kReplicate)) } + UInt64 rangeSize; + if (ui.NewProps) { if (item.HasDescriptor()) @@ -349,14 +377,11 @@ static HRESULT UpdateItemOldData( // use old name size. - CMyComPtr 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 +392,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 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 packStream; + + RINOK(inArchive->GetItemStream(itemEx, ui.NewProps, packStream)); + if (!packStream) + return E_NOTIMPL; + + complexity += rangeSize; + + CMyComPtr 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, false, item); + archive.WriteLocalHeader(item); } @@ -464,7 +480,7 @@ static HRESULT Update2St( CInArchive *inArchive, const CObjectVector &inputItems, CObjectVector &updateItems, - const CCompressionMethodMode *options, + const CCompressionMethodMode *options, bool outSeqMode, const CByteBuffer *comment, IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity, @@ -490,6 +506,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 +516,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,41 +536,49 @@ static HRESULT Update2St( if (!fileInStream) return E_INVALIDARG; - // bool isSeqMode = false; - /* + bool inSeqMode = false; + if (!inSeqMode) { CMyComPtr inStream2; fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2); - isSeqMode = (inStream2 == NULL); + inSeqMode = (inStream2 == NULL); } - */ + // seqMode = true; // to test seqMode UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity); - SetFileHeader(archive, *options, ui, item); - // file Size can be 64-bit !!! - archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode()); CCompressingResult compressingResult; + + RINOK(compressor.Set_Pre_CompressionResult( + inSeqMode, outSeqMode, + ui.Size, + compressingResult)); + + SetFileHeader(*options, ui, compressingResult.DescriptorMode, item); + + // file Size can be 64-bit !!! + + SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); + + archive.WriteLocalHeader(item); + CMyComPtr outStream; - archive.CreateStreamForCompressing(&outStream); + archive.CreateStreamForCompressing(outStream); RINOK(compressor.Compress( EXTERNAL_CODECS_LOC_VARS fileInStream, outStream, - ui.Time, + inSeqMode, outSeqMode, + ui.Time, ui.Size, progress, compressingResult)); - if (compressingResult.FileTimeWasUsed) - { - /* - if (!item.HasDescriptor()) - return E_FAIL; - */ - item.SetDescriptorMode(true); - } + if (item.HasDescriptor() != compressingResult.DescriptorMode) + return E_FAIL; 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 +588,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; } @@ -584,13 +613,14 @@ static HRESULT Update2( CInArchive *inArchive, const CObjectVector &inputItems, CObjectVector &updateItems, - const CCompressionMethodMode *options, + const CCompressionMethodMode &options, bool outSeqMode, const CByteBuffer *comment, IArchiveUpdateCallback *updateCallback) { CMyComPtr opCallback; updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + bool unknownComplexity = false; UInt64 complexity = 0; UInt64 numFilesToCompress = 0; UInt64 numBytesToCompress = 0; @@ -602,7 +632,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,21 +658,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; - if (options != 0) - 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; @@ -648,70 +709,102 @@ static HRESULT Update2( if (numThreads < 1) numThreads = 1; - const size_t kMemPerThread = (1 << 25); const size_t kBlockSize = 1 << 16; - bool mtMode = ((options != 0) && (numThreads > 1)); + bool mtMode = (numThreads > 1); 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; - numBZip2Threads = 32; - if (averageNumberOfBlocks < numBZip2Threads) + const UInt64 averageSize = numBytesToCompress / numFilesToCompress; + const UInt32 blockSize = oneMethodMain->Get_BZip2_BlockSize(); + const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1; + numBZip2Threads = 64; + if (numBZip2Threads > averageNumberOfBlocks) numBZip2Threads = (UInt32)averageNumberOfBlocks; - options2.MethodInfo.AddProp_NumThreads(numBZip2Threads); + if (numBZip2Threads > numThreads) + numBZip2Threads = numThreads; + oneMethodMain->AddProp_NumThreads(numBZip2Threads); } numThreads /= numBZip2Threads; } - if (method == NFileHeader::NCompressionMethod::kLZMA) + else if (method == NFileHeader::NCompressionMethod::kXz) + { + UInt32 numLzmaThreads = 1; + int numXzThreads = oneMethodMain->Get_Xz_NumThreads(numLzmaThreads); + if (numXzThreads < 0) + { + const UInt64 averageSize = numBytesToCompress / numFilesToCompress; + const UInt64 blockSize = oneMethodMain->Get_Xz_BlockSize(); + UInt64 averageNumberOfBlocks = 1; + if (blockSize != (UInt64)(Int64)-1) + averageNumberOfBlocks = averageSize / blockSize + 1; + UInt32 t = 256; + if (t > averageNumberOfBlocks) + t = (UInt32)averageNumberOfBlocks; + t *= numLzmaThreads; + if (t > numThreads) + t = numThreads; + oneMethodMain->AddProp_NumThreads(t); + numXzThreads = t; + } + numThreads /= (unsigned)numXzThreads; + } + else if (method == NFileHeader::NCompressionMethod::kLZMA) { - bool fixedNumber; // 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) mtMode = false; } + // mtMode = true; // to test mtMode for seqMode + if (!mtMode) #endif return Update2St( EXTERNAL_CODECS_LOC_VARS archive, inArchive, - inputItems, updateItems, &options2, comment, updateCallback, totalComplexity, opCallback); + inputItems, updateItems, &options2, outSeqMode, comment, updateCallback, totalComplexity, opCallback); #ifndef _7ZIP_ST - // Warning : before memManager, threads and compressingCompletedEvents +// Warning : before memManager, threads and compressingCompletedEvents // in order to have a "good" order for the destructor NWindows::NSynchronization::CSynchro synchroForCompressingCompletedEvents; synchroForCompressingCompletedEvents.Create(); @@ -735,7 +828,7 @@ static HRESULT Update2( CUIntVector threadIndices; // list threads in order of updateItems { - RINOK(memManager.AllocateSpaceAlways(&synchroForOutStreamSpec,(size_t)numThreads * (kMemPerThread / kBlockSize))); + RINOK(memManager.AllocateSpaceAlways(&synchroForOutStreamSpec, (size_t)numThreads * (kMemPerThread / kBlockSize))); for (i = 0; i < updateItems.Size(); i++) refs.Refs.Add(CMemBlocks2()); @@ -756,7 +849,10 @@ static HRESULT Update2( threadInfo.ProgressSpec = new CMtCompressProgress(); threadInfo.Progress = threadInfo.ProgressSpec; threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i); - threadInfo.FileTime = 0; // fix it ! + threadInfo.InSeqMode = false; + threadInfo.OutSeqMode = false; + threadInfo.FileTime = 0; + threadInfo.ExpectedDataSize = (UInt64)(Int64)-1; RINOK(threadInfo.CreateThread()); } } @@ -765,10 +861,15 @@ static HRESULT Update2( unsigned itemIndex = 0; int lastRealStreamItemIndex = -1; + while (itemIndex < updateItems.Size()) { if (threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size()) { + // we start ahead the threads for compressing + // also we set refs.Refs[itemIndex].SeqMode that is used later + // don't move that code block + CUpdateItem &ui = updateItems[mtItemIndex++]; if (!ui.NewData) continue; @@ -786,12 +887,16 @@ 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; } CMyComPtr fileInStream; + CMemBlocks2 &memRef2 = refs.Refs[mtItemIndex - 1]; + { NWindows::NSynchronization::CCriticalSectionLock lock(mtProgressMixerSpec->Mixer2->CriticalSection); HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); @@ -801,7 +906,7 @@ static HRESULT Update2( complexity += kLocalHeaderSize; mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); - refs.Refs[mtItemIndex - 1].Skip = true; + memRef2.Skip = true; continue; } RINOK(res); @@ -811,26 +916,46 @@ static HRESULT Update2( RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } - for (UInt32 k = 0; k < numThreads; k++) + UInt32 k; + for (k = 0; k < numThreads; k++) + if (threads.Threads[k].IsFree) + break; + + if (k == numThreads) + return E_FAIL; { - CThreadInfo &threadInfo = threads.Threads[k]; - if (threadInfo.IsFree) { + CThreadInfo &threadInfo = threads.Threads[k]; threadInfo.IsFree = false; threadInfo.InStream = fileInStream; + bool inSeqMode = false; + + if (!inSeqMode) + { + CMyComPtr inStream2; + fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2); + inSeqMode = (inStream2 == NULL); + } + memRef2.InSeqMode = inSeqMode; + // !!!!! we must release ref before sending event // BUG was here in v4.43 and v4.44. It could change ref counter in two threads in same time fileInStream.Release(); threadInfo.OutStreamSpec->Init(); threadInfo.ProgressSpec->Reinit(); - threadInfo.CompressEvent.Set(); + threadInfo.UpdateIndex = mtItemIndex - 1; - + threadInfo.InSeqMode = inSeqMode; + threadInfo.OutSeqMode = outSeqMode; + threadInfo.FileTime = ui.Time; // FileTime is used for ZipCrypto only in seqMode + threadInfo.ExpectedDataSize = ui.Size; + + threadInfo.CompressEvent.Set(); + compressingCompletedEvents.Add(threadInfo.CompressionCompletedEvent); threadIndices.Add(k); - break; } } @@ -858,47 +983,71 @@ 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) { - WriteDirHeader(archive, options, ui, item); + WriteDirHeader(archive, &options, ui, item); } 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) + if (memRef.Finished) { - CMyComPtr outStream; - archive.CreateStreamForCompressing(&outStream); - memRef.WriteToStream(memManager.GetBlockSize(), outStream); - SetFileHeader(archive, *options, ui, item); + if (lastRealStreamItemIndex < (int)itemIndex) + lastRealStreamItemIndex = itemIndex; + + SetFileHeader(options, ui, memRef.CompressingResult.DescriptorMode, 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); + options.IsRealAesMode(), options.AesKeyMode, item); + archive.WriteLocalHeader(item); // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); + CMyComPtr outStream; + archive.CreateStreamForCopying(outStream); + memRef.WriteToStream(memManager.GetBlockSize(), outStream); + archive.MoveCurPos(item.PackSize); memRef.FreeOpt(&memManager); } else { + // current file was not finished + + if (lastRealStreamItemIndex < (int)itemIndex) + { + // LocalHeader was not written for current itemIndex still + + lastRealStreamItemIndex = itemIndex; + + // thread was started before for that item already, and memRef.SeqMode was set + + CCompressingResult compressingResult; + RINOK(compressor.Set_Pre_CompressionResult( + memRef.InSeqMode, outSeqMode, + ui.Size, + compressingResult)); + + memRef.PreDescriptorMode = compressingResult.DescriptorMode; + SetFileHeader(options, ui, compressingResult.DescriptorMode, item); + + 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 outStream; - archive.CreateStreamForCompressing(&outStream); + archive.CreateStreamForCompressing(outStream); thread.OutStreamSpec->SetOutStream(outStream); thread.OutStreamSpec->SetRealStreamMode(); } @@ -912,7 +1061,7 @@ static HRESULT Update2( DWORD lastError = GetLastError(); return lastError != 0 ? lastError : E_FAIL; } -#endif +#endif unsigned t = (unsigned)(result - WAIT_OBJECT_0); if (t >= compressingCompletedEvents.Size()) return E_FAIL; @@ -926,19 +1075,29 @@ static HRESULT Update2( if (t == 0) { + // if thread for current file was finished. + if (threadInfo.UpdateIndex != itemIndex) + return E_FAIL; + + if (memRef.PreDescriptorMode != threadInfo.CompressingResult.DescriptorMode) + return E_FAIL; + RINOK(threadInfo.OutStreamSpec->WriteToRealStream()); threadInfo.OutStreamSpec->ReleaseOutStream(); - SetFileHeader(archive, *options, ui, item); + SetFileHeader(options, ui, threadInfo.CompressingResult.DescriptorMode, item); SetItemInfoFromCompressingResult(threadInfo.CompressingResult, - options->IsRealAesMode(), options->AesKeyMode, item); - archive.WriteLocalHeader_And_SeekToNextFile(item); + options.IsRealAesMode(), options.AesKeyMode, item); + + archive.WriteLocalHeader_Replace(item); } else { + // it's not current file. So we must store information in array CMemBlocks2 &memRef2 = refs.Refs[threadInfo.UpdateIndex]; threadInfo.OutStreamSpec->DetachData(memRef2); memRef2.CompressingResult = threadInfo.CompressingResult; - memRef2.Defined = true; + // memRef2.SeqMode = threadInfo.SeqMode; // it was set before + memRef2.Finished = true; continue; } } @@ -971,6 +1130,7 @@ class CCacheOutStream: public CMyUnknownImp { CMyComPtr _stream; + CMyComPtr _seqStream; Byte *_cache; UInt64 _virtPos; UInt64 _virtSize; @@ -986,10 +1146,10 @@ class CCacheOutStream: } HRESULT FlushCache(); public: - CCacheOutStream(): _cache(0) {} + CCacheOutStream(): _cache(NULL) {} ~CCacheOutStream(); bool Allocate(); - HRESULT Init(IOutStream *stream); + HRESULT Init(ISequentialOutStream *seqStream, IOutStream *stream); MY_UNKNOWN_IMP @@ -1005,13 +1165,19 @@ bool CCacheOutStream::Allocate() return (_cache != NULL); } -HRESULT CCacheOutStream::Init(IOutStream *stream) +HRESULT CCacheOutStream::Init(ISequentialOutStream *seqStream, IOutStream *stream) { - _virtPos = _phyPos = 0; + _virtPos = 0; + _phyPos = 0; + _virtSize = 0; + _seqStream = seqStream; _stream = stream; - RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos)); - RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize)); - RINOK(_stream->Seek(_virtPos, STREAM_SEEK_SET, &_virtPos)); + if (_stream) + { + RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos)); + RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize)); + RINOK(_stream->Seek(_virtPos, STREAM_SEEK_SET, &_virtPos)); + } _phyPos = _virtPos; _phySize = _virtSize; _cachedPos = 0; @@ -1025,12 +1191,14 @@ HRESULT CCacheOutStream::MyWrite(size_t size) { if (_phyPos != _cachedPos) { + if (!_stream) + return E_FAIL; RINOK(_stream->Seek(_cachedPos, STREAM_SEEK_SET, &_phyPos)); } size_t pos = (size_t)_cachedPos & kCacheMask; size_t curSize = MyMin(kCacheSize - pos, _cachedSize); curSize = MyMin(curSize, size); - RINOK(WriteStream(_stream, _cache + pos, curSize)); + RINOK(WriteStream(_seqStream, _cache + pos, curSize)); _phyPos += curSize; if (_phySize < _phyPos) _phySize = _phyPos; @@ -1049,10 +1217,13 @@ HRESULT CCacheOutStream::FlushCache() CCacheOutStream::~CCacheOutStream() { FlushCache(); - if (_virtSize != _phySize) - _stream->SetSize(_virtSize); - if (_virtPos != _phyPos) - _stream->Seek(_virtPos, STREAM_SEEK_SET, NULL); + if (_stream) + { + if (_virtSize != _phySize) + _stream->SetSize(_virtSize); + if (_virtPos != _phyPos) + _stream->Seek(_virtPos, STREAM_SEEK_SET, NULL); + } ::MidFree(_cache); } @@ -1161,6 +1332,8 @@ STDMETHODIMP CCacheOutStream::SetSize(UInt64 newSize) _virtSize = newSize; if (newSize < _phySize) { + if (!_stream) + return E_NOTIMPL; RINOK(_stream->SetSize(newSize)); _phySize = newSize; } @@ -1181,7 +1354,7 @@ HRESULT Update( CObjectVector &updateItems, ISequentialOutStream *seqOutStream, CInArchive *inArchive, bool removeSfx, - CCompressionMethodMode *compressionMethodMode, + const CCompressionMethodMode &compressionMethodMode, IArchiveUpdateCallback *updateCallback) { if (inArchive) @@ -1192,11 +1365,14 @@ HRESULT Update( CMyComPtr outStream; + bool outSeqMode; { CMyComPtr outStreamReal; seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal); if (!outStreamReal) - return E_NOTIMPL; + { + // return E_NOTIMPL; + } if (inArchive) { @@ -1204,7 +1380,7 @@ HRESULT Update( { IInStream *baseStream = inArchive->GetBaseStream(); RINOK(baseStream->Seek(0, STREAM_SEEK_SET, NULL)); - RINOK(NCompress::CopyStream_ExactSize(baseStream, outStreamReal, inArchive->ArcInfo.Base, NULL)); + RINOK(NCompress::CopyStream_ExactSize(baseStream, seqOutStream, inArchive->ArcInfo.Base, NULL)); } } @@ -1212,7 +1388,8 @@ HRESULT Update( outStream = cacheStream; if (!cacheStream->Allocate()) return E_OUTOFMEMORY; - RINOK(cacheStream->Init(outStreamReal)); + RINOK(cacheStream->Init(seqOutStream, outStreamReal)); + outSeqMode = (outStreamReal == NULL); } COutArchive outArchive; @@ -1234,7 +1411,7 @@ HRESULT Update( EXTERNAL_CODECS_LOC_VARS outArchive, inArchive, inputItems, updateItems, - compressionMethodMode, + compressionMethodMode, outSeqMode, inArchive ? &inArchive->ArcInfo.Comment : NULL, updateCallback); } diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.h b/CPP/7zip/Archive/Zip/ZipUpdate.h index 054db668..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) {} }; @@ -51,7 +64,7 @@ HRESULT Update( CObjectVector &updateItems, ISequentialOutStream *seqOutStream, CInArchive *inArchive, bool removeSfx, - CCompressionMethodMode *compressionMethodMode, + const CCompressionMethodMode &compressionMethodMode, IArchiveUpdateCallback *updateCallback); }} diff --git a/CPP/7zip/Bundles/Alone/makefile.list b/CPP/7zip/Bundles/Alone/makefile.list index f6aec651..ba860192 100644 --- a/CPP/7zip/Bundles/Alone/makefile.list +++ b/CPP/7zip/Bundles/Alone/makefile.list @@ -205,6 +205,7 @@ SRCS=\ ../../../../CPP/Windows/FileName.cpp \ ../../../../CPP/Windows/PropVariant.cpp \ ../../../../CPP/Windows/PropVariantConv.cpp \ + ../../../../CPP/Windows/PropVariantUtils.cpp \ ../../../../CPP/Windows/Synchronization.cpp \ ../../../../CPP/Windows/System.cpp \ ../../../../CPP/Windows/TimeUtils.cpp \ @@ -871,6 +872,8 @@ PropVariant.o : ../../../../CPP/Windows/PropVariant.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/Windows/PropVariant.cpp PropVariantConv.o : ../../../../CPP/Windows/PropVariantConv.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/Windows/PropVariantConv.cpp +PropVariantUtils.o : ../../../../CPP/Windows/PropVariantUtils.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/Windows/PropVariantUtils.cpp Synchronization.o : ../../../../CPP/Windows/Synchronization.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/Windows/Synchronization.cpp System.o : ../../../../CPP/Windows/System.cpp @@ -1097,6 +1100,7 @@ OBJS=\ FileName.o \ PropVariant.o \ PropVariantConv.o \ + PropVariantUtils.o \ Synchronization.o \ System.o \ TimeUtils.o \ diff --git a/CPP/7zip/Compress/XzDecoder.cpp b/CPP/7zip/Compress/XzDecoder.cpp index c28ac900..b33d54cd 100644 --- a/CPP/7zip/Compress/XzDecoder.cpp +++ b/CPP/7zip/Compress/XzDecoder.cpp @@ -96,7 +96,7 @@ HRESULT CDecoder::Decode(ISequentialInStream *seqInStream, ISequentialOutStream ECoderFinishMode finishMode = CODER_FINISH_ANY; /* - // 17.01 : the code was disabled: + // 17.02 : the code was disabled: if (inSize == 0) finishMode = CODER_FINISH_END; */ diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp index 434ee694..76593ae9 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp @@ -1520,7 +1520,7 @@ STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes) COM_TRY_END } -bool CArchiveExtractCallback::SetTarFileSymLinkAttrib() +bool CArchiveExtractCallback::SetFileSymLinkAttrib() { if (!SetTarFileSymLink(_diskFilePath, &_delayedSymLinks)) return E_FAIL; diff --git a/CPP/7zip/UI/Common/OpenArchive.cpp b/CPP/7zip/UI/Common/OpenArchive.cpp index 832ce1f1..bdd4d8e7 100644 --- a/CPP/7zip/UI/Common/OpenArchive.cpp +++ b/CPP/7zip/UI/Common/OpenArchive.cpp @@ -1482,7 +1482,7 @@ class CExtractCallback_To_OpenCallback: } }; -bool CExtractCallback_To_OpenCallback::SetTarFileSymLinkAttrib() +bool CExtractCallback_To_OpenCallback::SetFileSymLinkAttrib() { /* DO NOTHING */ return S_OK; diff --git a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp index 8dac7fbc..45012705 100644 --- a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp @@ -32,7 +32,7 @@ static HRESULT CheckBreak2() return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; } -static const char *kError = "ERROR: "; +static const char * const kError = "ERROR: "; void CExtractScanConsole::StartScanning() @@ -138,33 +138,33 @@ static NSynchronization::CCriticalSection g_CriticalSection; #endif -static const char *kTestString = "T"; -static const char *kExtractString = "-"; -static const char *kSkipString = "."; +static const char * const kTestString = "T"; +static const char * const kExtractString = "-"; +static const char * const kSkipString = "."; // static const char *kCantAutoRename = "can not create file with auto name\n"; // static const char *kCantRenameFile = "can not rename existing file\n"; // static const char *kCantDeleteOutputFile = "can not delete output file "; -static const char *kMemoryExceptionMessage = "Can't allocate required memory!"; +static const char * const kMemoryExceptionMessage = "Can't allocate required memory!"; -static const char *kExtracting = "Extracting archive: "; -static const char *kTesting = "Testing archive: "; +static const char * const kExtracting = "Extracting archive: "; +static const char * const kTesting = "Testing archive: "; -static const char *kEverythingIsOk = "Everything is Ok"; -static const char *kNoFiles = "No files to process"; +static const char * const kEverythingIsOk = "Everything is Ok"; +static const char * const kNoFiles = "No files to process"; -static const char *kUnsupportedMethod = "Unsupported Method"; -static const char *kCrcFailed = "CRC Failed"; -static const char *kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?"; -static const char *kDataError = "Data Error"; -static const char *kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?"; -static const char *kUnavailableData = "Unavailable data"; -static const char *kUnexpectedEnd = "Unexpected end of data"; -static const char *kDataAfterEnd = "There are some data after the end of the payload data"; -static const char *kIsNotArc = "Is not archive"; -static const char *kHeadersError = "Headers Error"; -static const char *kWrongPassword = "Wrong password"; +static const char * const kUnsupportedMethod = "Unsupported Method"; +static const char * const kCrcFailed = "CRC Failed"; +static const char * const kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?"; +static const char * const kDataError = "Data Error"; +static const char * const kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?"; +static const char * const kUnavailableData = "Unavailable data"; +static const char * const kUnexpectedEnd = "Unexpected end of data"; +static const char * const kDataAfterEnd = "There are some data after the end of the payload data"; +static const char * const kIsNotArc = "Is not archive"; +static const char * const kHeadersError = "Headers Error"; +static const char * const kWrongPassword = "Wrong password"; static const char * const k_ErrorFlagsMessages[] = { @@ -206,7 +206,7 @@ STDMETHODIMP CExtractCallbackConsole::SetCompleted(const UInt64 *completeValue) return CheckBreak2(); } -static const char *kTab = " "; +static const char * const kTab = " "; static void PrintFileInfo(CStdOutStream *_so, const wchar_t *path, const FILETIME *ft, const UInt64 *size) { diff --git a/CPP/7zip/UI/Console/HashCon.cpp b/CPP/7zip/UI/Console/HashCon.cpp index a71e4b50..1ff98828 100644 --- a/CPP/7zip/UI/Console/HashCon.cpp +++ b/CPP/7zip/UI/Console/HashCon.cpp @@ -7,9 +7,9 @@ #include "ConsoleClose.h" #include "HashCon.h" -static const wchar_t *kEmptyFileAlias = L"[Content]"; +static const wchar_t * const kEmptyFileAlias = L"[Content]"; -static const char *kScanningMessage = "Scanning"; +static const char * const kScanningMessage = "Scanning"; static HRESULT CheckBreak2() { @@ -283,7 +283,7 @@ HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBun return CheckBreak2(); } -static const char *k_DigestTitles[] = +static const char * const k_DigestTitles[] = { " : " , " for data: " diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp index db880e0d..4226e534 100644 --- a/CPP/7zip/UI/Console/Main.cpp +++ b/CPP/7zip/UI/Console/Main.cpp @@ -75,7 +75,7 @@ extern const CCodecInfo *g_Codecs[]; extern unsigned g_NumHashers; extern const CHasherInfo *g_Hashers[]; -static const char *kCopyrightString = "\n7-Zip" +static const char * const kCopyrightString = "\n7-Zip" #ifndef EXTERNAL_CODECS #ifdef PROG_VARIANT_R " (r)" @@ -92,7 +92,7 @@ static const char *kCopyrightString = "\n7-Zip" " " MY_VERSION_COPYRIGHT_DATE "\n"; -static const char *kHelpString = +static const char * const kHelpString = "Usage: 7z" #ifndef EXTERNAL_CODECS #ifdef PROG_VARIANT_R @@ -102,7 +102,6 @@ static const char *kHelpString = #endif #endif " [...] [...]\n" - " [<@listfiles...>]\n" "\n" "\n" " a : Add files to archive\n" @@ -119,6 +118,7 @@ static const char *kHelpString = "\n" "\n" " -- : Stop switches parsing\n" + " @listfile : set path to listfile that contains file names\n" " -ai[r[-|0]]{@listfile|!wildcard} : Include archives\n" " -ax[r[-|0]]{@listfile|!wildcard} : eXclude archives\n" " -ao{a|s|t|u} : set Overwrite mode\n" @@ -130,6 +130,7 @@ static const char *kHelpString = " -i[r[-|0]]{@listfile|!wildcard} : Include filenames\n" " -m{Parameters} : set compression Method\n" " -mmt[N] : set number of CPU threads\n" + " -mx[N] : set compression level: -mx1 (fastest) ... -mx9 (ultra)\n" " -o{Directory} : set Output directory\n" #ifndef _NO_CRYPTO " -p{Password} : set Password\n" @@ -168,11 +169,11 @@ static const char *kHelpString = // --------------------------- // exception messages -static const char *kEverythingIsOk = "Everything is Ok"; -static const char *kUserErrorMessage = "Incorrect command line"; -static const char *kNoFormats = "7-Zip cannot find the code that works with archives."; -static const char *kUnsupportedArcTypeMessage = "Unsupported archive type"; -// static const char *kUnsupportedUpdateArcType = "Can't create archive for that type"; +static const char * const kEverythingIsOk = "Everything is Ok"; +static const char * const kUserErrorMessage = "Incorrect command line"; +static const char * const kNoFormats = "7-Zip cannot find the code that works with archives."; +static const char * const kUnsupportedArcTypeMessage = "Unsupported archive type"; +// static const char * const kUnsupportedUpdateArcType = "Can't create archive for that type"; static CFSTR kDefaultSfxModule = FTEXT("7zCon.sfx"); @@ -650,7 +651,7 @@ int Main2( so << endl << "Formats:" << endl; - const char *kArcFlags = "KSNFMGOPBELH"; + const char * const kArcFlags = "KSNFMGOPBELH"; const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags); for (i = 0; i < codecs->Formats.Size(); i++) diff --git a/CPP/7zip/UI/Console/MainAr.cpp b/CPP/7zip/UI/Console/MainAr.cpp index d30a96e4..68e5fe97 100644 --- a/CPP/7zip/UI/Console/MainAr.cpp +++ b/CPP/7zip/UI/Console/MainAr.cpp @@ -24,12 +24,12 @@ extern int Main2( #endif ); -static const char *kException_CmdLine_Error_Message = "Command Line Error:"; -static const char *kExceptionErrorMessage = "ERROR:"; -static const char *kUserBreakMessage = "Break signaled"; -static const char *kMemoryExceptionMessage = "ERROR: Can't allocate required memory!"; -static const char *kUnknownExceptionMessage = "Unknown Error"; -static const char *kInternalExceptionMessage = "\n\nInternal Error #"; +static const char * const kException_CmdLine_Error_Message = "Command Line Error:"; +static const char * const kExceptionErrorMessage = "ERROR:"; +static const char * const kUserBreakMessage = "Break signaled"; +static const char * const kMemoryExceptionMessage = "ERROR: Can't allocate required memory!"; +static const char * const kUnknownExceptionMessage = "Unknown Error"; +static const char * const kInternalExceptionMessage = "\n\nInternal Error #"; static void FlushStreams() { diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp index 5e3bc9d1..dd27bbd4 100644 --- a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp @@ -23,15 +23,15 @@ static NSynchronization::CCriticalSection g_CriticalSection; #define MT_LOCK #endif -static const wchar_t *kEmptyFileAlias = L"[Content]"; +static const wchar_t * const kEmptyFileAlias = L"[Content]"; -static const char *kOpenArchiveMessage = "Open archive: "; -static const char *kCreatingArchiveMessage = "Creating archive: "; -static const char *kUpdatingArchiveMessage = "Updating archive: "; -static const char *kScanningMessage = "Scanning the drive:"; +static const char * const kOpenArchiveMessage = "Open archive: "; +static const char * const kCreatingArchiveMessage = "Creating archive: "; +static const char * const kUpdatingArchiveMessage = "Updating archive: "; +static const char * const kScanningMessage = "Scanning the drive:"; -static const char *kError = "ERROR: "; -static const char *kWarning = "WARNING: "; +static const char * const kError = "ERROR: "; +static const char * const kWarning = "WARNING: "; static HRESULT CheckBreak2() { @@ -259,7 +259,7 @@ HRESULT CUpdateCallbackConsole::FinishScanning(const CDirItemsStat &st) return S_OK; } -static const char *k_StdOut_ArcName = "StdOut"; +static const char * const k_StdOut_ArcName = "StdOut"; HRESULT CUpdateCallbackConsole::StartOpenArchive(const wchar_t *name) { diff --git a/CPP/Common/MyString.h b/CPP/Common/MyString.h index dc516ffe..4808d355 100644 --- a/CPP/Common/MyString.h +++ b/CPP/Common/MyString.h @@ -705,6 +705,8 @@ class UString2 // operator const wchar_t *() const { return _chars; } const wchar_t *GetRawPtr() const { return _chars; } + int Compare(const wchar_t *s) const { return wcscmp(_chars, s); } + wchar_t *GetBuf(unsigned minLen) { if (!_chars || minLen > _len) diff --git a/ChangeLog b/ChangeLog index 2671011d..caf2935c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,33 @@ +Version 17.02 +============= + + - p7zip 17.02 is more like 7zip 17.01(only 7za and 7z),The difference from 7zip 17.01 + and older version p7zip is the following description + - Supports Fast lzma2 1.0.1 compression method + - Update Zstd method to 1.4.5 + - Add zstd method parameters in 7z format + ZSTD parameters NEW name: + strategy -> strat + fast -> fast + long -> long + WindowLog -> wlog + HashLog -> hlog + ChainLog -> clog + SearchLog -> slog + MinMatch -> slen + TargetLen -> tlen + OverlapLog -> ovlog + LdmHashLog -> ldmhlog + LdmSearchLength -> ldmslen + LdmBucketSizeLog -> ldmblog + LdmHashRateLog -> ldmhevery + - Fix symlink files contained inside tar and squashfs as regular file + - Add lz4 and Zstd decompress method to squashfs + Version 17.01 ============= + - Fix BUG CVE-2018-10115 - Fix BUG CVE-2018-5996 - Fix BUG CVE-2017-17969 - Fix BUG CVE-2016-9296 diff --git a/DOC/MANUAL/7-zip.chm b/DOC/MANUAL/7-zip.chm new file mode 100644 index 00000000..91fe2731 Binary files /dev/null and b/DOC/MANUAL/7-zip.chm differ diff --git a/DOC/MANUAL/start.htm b/DOC/MANUAL/start.htm index 47fb993f..129eaaf9 100644 --- a/DOC/MANUAL/start.htm +++ b/DOC/MANUAL/start.htm @@ -10,7 +10,7 @@

7-Zip

-

Welcome to 7-Zip 17.01

+

Welcome to 7-Zip 17.02

7-Zip is a file archiver with a high compression ratio.

The documentation for 7-Zip includes:

diff --git a/DOC/README.md b/DOC/README.md index 01ad2be1..2d0dfbdb 100644 --- a/DOC/README.md +++ b/DOC/README.md @@ -153,7 +153,7 @@ 根据 7zip 版本对 p7zip进行版本对齐维护 17.01:新增NewHandler.h / NewHandler.cpp重新定义了new(),针对老版本的_MSC_VER < 1900,修改了C/7zTypes.h中变量名,一些造成崩溃的BUG修复 根据紧迫度和难度分步迭代优化 - 计划中 + 完成 18.03:汇编优化的LZMA 解压缩函数,在数据块独立时,支持对LZMA2/xz的多线程打包 diff --git a/DOC/readme.txt b/DOC/readme.txt index 00b1be9d..01ed94a8 100644 --- a/DOC/readme.txt +++ b/DOC/readme.txt @@ -1,4 +1,4 @@ -7-Zip 17.01 Sources +7-Zip 17.02 Sources ------------------- 7-Zip is a file archiver for Windows. diff --git a/README b/README index c47e52a6..252fe71b 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ - p7zip 17.01 + p7zip 17.02 =========== Homepage : /~https://github.com/szcnick/p7zip diff --git a/README.md b/README.md index 3a7fe5c3..f9fb2e13 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,10 @@ This is the place for the active development of p7zip to include major modern codecs such as LZ4 and Zstd. In order to support multithreading for those addional codecs, this project depends on the [Multithreading Library](/~https://github.com/mcmilk/zstdmt). # status -| [Ubuntu][ubuntu-link]| -|---------------| -| ![ubuntu-badge] | +[![ubuntu-badge]][ubuntu-link] -[ubuntu-link]: /~https://github.com/2273816832/test_github_action/actions?query=workflow%3AUbuntu "UbuntuAction" -[ubuntu-badge]: /~https://github.com/2273816832/test_github_action/workflows/Ubuntu/badge.svg "Ubuntu" +[ubuntu-link]: /~https://github.com/szcnick/p7zip/actions?query=workflow%3AUbuntu "UbuntuL" +[ubuntu-badge]: /~https://github.com/szcnick/p7zip/workflows/Ubuntu/badge.svg "UbuntuB" ## Codec overview 1. [Zstandard] v1.4.5 is a real-time compression algorithm, providing high compression ratios. It offers a very wide range of compression / speed trade-off, while being backed by a very fast decoder. @@ -32,7 +30,7 @@ We use [silesia](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia) files(to |7z-7z|lz4-12|77788386|3548 ms|56.97|409|494.18|2.72| |7z-7z|flzma2-9|48676481|12619 ms|16.02|3877|52.13|4.35| -### install CLI +### Install CLI #### (Currently only supports CLI, if you want to do GUI please contact us) 1. git clone /~https://github.com/szcnick/p7zip.git 2. cd p7zip && make 7z . (OR make 7za) @@ -40,8 +38,8 @@ We use [silesia](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia) files(to The output should look like this: ``` -7-Zip (a) [64] 17.01 : Copyright (c) 1999-2016 Igor Pavlov -p7zip Version 17.01 (locale=zh_CN.UTF-8,Utf16=on,HugeFiles=on,64 bits,12 CPUs x64) +7-Zip (a) [64] 17.02 : Copyright (c) 1999-2020 Igor Pavlov +p7zip Version 17.02 (locale=zh_CN.UTF-8,Utf16=on,HugeFiles=on,64 bits,12 CPUs x64) Formats: ... @@ -104,7 +102,7 @@ Hashers: ## License and redistribution -- the same as the Mainline [p7-Zip], which means GNU LGPL +- the same as the Mainline [7-Zip], which means GNU LGPL ## Links @@ -112,7 +110,7 @@ Hashers: ## Version Information -- p7zip Version 17.01 +- p7zip Version 17.02 - [LZ4] Version 1.9.2 - [Zstandard] Version 1.4.5 - [Fast LZMA2] Version v1.0.1 @@ -120,7 +118,7 @@ Hashers: ## Working Plan - [check here](/~https://github.com/szcnick/p7zip/tree/dev/DOC) -[p7-Zip]:https://www.7-zip.org/ +[7-Zip]:https://www.7-zip.org/ [LZ4]:/~https://github.com/lz4/lz4/ [Zstandard]:/~https://github.com/facebook/zstd/ [Fast LZMA2]:/~https://github.com/conor42/fast-lzma2 diff --git a/check/check.sh b/check/check.sh index 01d42db4..697c9da4 100644 --- a/check/check.sh +++ b/check/check.sh @@ -39,6 +39,8 @@ sure ${P7ZIP} t ../test/7za433_7zip_lzma.7z sure ${P7ZIP} t -pqwerty ../test/7za433_7zip_lzma_crypto.7z sure ${P7ZIP} t ../test/7za433_7zip_ppmd.7z sure ${P7ZIP} t ../test/7za433_7zip_bzip2.7z +sure ${P7ZIP} t ../test/7za433_rar.rar +sure ${P7ZIP} t ../test/7za433_rar4.rar echo "" echo "# EXTRACTING ..." @@ -68,6 +70,12 @@ sure diff -r 7za433_ref 7za433_7zip_ppmd_bcj2 sure ${P7ZIP} x ../test/7za433_7zip_bzip2.7z sure diff -r 7za433_ref 7za433_7zip_bzip2 +sure ${P7ZIP} x ../test/7za433_rar.rar -y +sure diff -r 7za433_ref 7za433_rar + +sure ${P7ZIP} x ../test/7za433_rar4.rar -y +sure diff -r 7za433_ref 7za433_rar4 + sure ${P7ZIP} x ../test/7za433_7zip_lzma2.7z sure diff -r 7za433_ref 7za433_7zip_lzma2 @@ -112,6 +120,8 @@ sure ${P7ZIP} a -t7z 7za433_7zip_zstd.7z 7za433_7zip_lzma -m0=zstd -mx=22 # mx=l sure ${P7ZIP} a -t7z 7za433_7zip_lz4.7z 7za433_7zip_lzma -m0=lz4 -mmt=on # mmt=multithreading mode +sure ${P7ZIP} a -t7z 7za433_7zip_flzma2.7z 7za433_7zip_lzma -m0=flzma2 -mmt=on # mmt=multithreading mode + sure ${P7ZIP} a -t7z 7za433_7zip_lzma3.7z 7za433_7zip_lzma -m0=LZMA -mf=BCJ # mf=FilterID sure ${P7ZIP} a -t7z 7za433_7zip_lzma4.7z 7za433_7zip_lzma -m0=LZMA -mf=ARM @@ -222,6 +232,10 @@ sure ${P7ZIP} x 7za433_7zip_lz4.7z sure diff -r 7za433_ref 7za433_7zip_lzma sure rm -rf 7za433_7zip_lzma +sure ${P7ZIP} x 7za433_7zip_flzma2.7z +sure diff -r 7za433_ref 7za433_7zip_lzma +sure rm -rf 7za433_7zip_lzma + sure ${P7ZIP} x 7za433_7zip_lzma3.7z sure diff -r 7za433_ref 7za433_7zip_lzma sure rm -rf 7za433_7zip_lzma @@ -357,7 +371,7 @@ chmod -R 777 ${REP} 2> /dev/null rm -fr ${REP} echo "" -echo "========" +echo "===========" echo "ALL SUCCESS" -echo "========" +echo "===========" echo "" diff --git a/check/test/7za433_rar.rar b/check/test/7za433_rar.rar new file mode 100644 index 00000000..fdf009ac Binary files /dev/null and b/check/test/7za433_rar.rar differ diff --git a/check/test/7za433_rar4.rar b/check/test/7za433_rar4.rar new file mode 100644 index 00000000..8e7eb0e3 Binary files /dev/null and b/check/test/7za433_rar4.rar differ