diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2014-11-23 03:00:00 +0300 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:51 +0300 |
commit | f08f4dcc3c02464c17753b3feafcfe5243b9e236 (patch) | |
tree | b0e1b15bc5368d92dff422e8ec0818564a2b00b8 /CPP/7zip/Archive | |
parent | 83f8ddcc5b2161e1e3c49666265257fca8aeb12c (diff) |
9.349.34
Diffstat (limited to 'CPP/7zip/Archive')
238 files changed, 33542 insertions, 14766 deletions
diff --git a/CPP/7zip/Archive/7z/7z.dsp b/CPP/7zip/Archive/7z/7z.dsp index 0484228d..53913f77 100755..100644 --- a/CPP/7zip/Archive/7z/7z.dsp +++ b/CPP/7zip/Archive/7z/7z.dsp @@ -328,6 +328,14 @@ SOURCE=..\..\..\Common\StringToInt.cpp SOURCE=..\..\..\Common\StringToInt.h # End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File # End Group # Begin Group "Archive Common" @@ -482,6 +490,10 @@ SOURCE=..\..\Common\ProgressUtils.h # End Source File # Begin Source File +SOURCE=..\..\Common\PropId.cpp +# End Source File +# Begin Source File + SOURCE=..\..\Common\RegisterArc.h # End Source File # Begin Source File @@ -558,6 +570,10 @@ SOURCE=..\..\..\Windows\FileIO.h # End Source File # Begin Source File +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + SOURCE=..\..\..\Windows\FileName.h # End Source File # Begin Source File diff --git a/CPP/7zip/Archive/7z/7z.dsw b/CPP/7zip/Archive/7z/7z.dsw index 702a86c7..702a86c7 100755..100644 --- a/CPP/7zip/Archive/7z/7z.dsw +++ b/CPP/7zip/Archive/7z/7z.dsw diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.cpp b/CPP/7zip/Archive/7z/7zCompressionMode.cpp index 6774fc48..6774fc48 100755..100644 --- a/CPP/7zip/Archive/7z/7zCompressionMode.cpp +++ b/CPP/7zip/Archive/7z/7zCompressionMode.cpp diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.h b/CPP/7zip/Archive/7z/7zCompressionMode.h index 5cde97c3..5cde97c3 100755..100644 --- a/CPP/7zip/Archive/7z/7zCompressionMode.h +++ b/CPP/7zip/Archive/7z/7zCompressionMode.h diff --git a/CPP/7zip/Archive/7z/7zDecode.cpp b/CPP/7zip/Archive/7z/7zDecode.cpp index 425a3415..7f0e45d1 100755..100644 --- a/CPP/7zip/Archive/7z/7zDecode.cpp +++ b/CPP/7zip/Archive/7z/7zDecode.cpp @@ -16,29 +16,33 @@ static void ConvertFolderItemInfoToBindInfo(const CFolder &folder, CBindInfoEx &bindInfo) { bindInfo.Clear(); - int i; + bindInfo.BindPairs.ClearAndSetSize(folder.BindPairs.Size()); + unsigned i; for (i = 0; i < folder.BindPairs.Size(); i++) { - NCoderMixer::CBindPair bindPair; + NCoderMixer::CBindPair &bindPair = bindInfo.BindPairs[i]; bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex; bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex; - bindInfo.BindPairs.Add(bindPair); } + + bindInfo.Coders.ClearAndSetSize(folder.Coders.Size()); + bindInfo.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size()); + UInt32 outStreamIndex = 0; for (i = 0; i < folder.Coders.Size(); i++) { - NCoderMixer::CCoderStreamsInfo coderStreamsInfo; + NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i]; const CCoderInfo &coderInfo = folder.Coders[i]; coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams; coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams; - bindInfo.Coders.Add(coderStreamsInfo); - bindInfo.CoderMethodIDs.Add(coderInfo.MethodID); + bindInfo.CoderMethodIDs[i] = coderInfo.MethodID; for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++) if (folder.FindBindPairForOutStream(outStreamIndex) < 0) bindInfo.OutStreams.Add(outStreamIndex); } + bindInfo.InStreams.ClearAndSetSize(folder.PackStreams.Size()); for (i = 0; i < folder.PackStreams.Size(); i++) - bindInfo.InStreams.Add((UInt32)folder.PackStreams[i]); + bindInfo.InStreams[i] = (UInt32)folder.PackStreams[i]; } static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1, @@ -58,7 +62,7 @@ static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2) { if (a1.Coders.Size() != a2.Coders.Size()) return false; - int i; + unsigned i; for (i = 0; i < a1.Coders.Size(); i++) if (!AreCodersEqual(a1.Coders[i], a2.Coders[i])) return false; @@ -90,45 +94,49 @@ HRESULT CDecoder::Decode( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, UInt64 startPos, - const UInt64 *packSizes, - const CFolder &folderInfo, + const CFolders &folders, int folderIndex, ISequentialOutStream *outStream, ICompressProgressInfo *compressProgress - #ifndef _NO_CRYPTO - , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined - #endif + _7Z_DECODER_CRYPRO_VARS_DECL #if !defined(_7ZIP_ST) && !defined(_SFX) , bool mtMode, UInt32 numThreads #endif ) { - if (!folderInfo.CheckStructure()) + const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]]; + CFolder folderInfo; + folders.ParseFolderInfo(folderIndex, folderInfo); + + if (!folderInfo.CheckStructure(folders.GetNumFolderUnpackSizes(folderIndex))) return E_NOTIMPL; + + /* + We don't need to init isEncrypted and passwordIsDefined + We must upgrade them only #ifndef _NO_CRYPTO + isEncrypted = false; passwordIsDefined = false; #endif + */ + CObjectVector< CMyComPtr<ISequentialInStream> > inStreams; CLockedInStream lockedInStream; lockedInStream.Init(inStream); - for (int j = 0; j < folderInfo.PackStreams.Size(); j++) + for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++) { - CLockedSequentialInStreamImp *lockedStreamImpSpec = new - CLockedSequentialInStreamImp; + CLockedSequentialInStreamImp *lockedStreamImpSpec = new CLockedSequentialInStreamImp; CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec; - lockedStreamImpSpec->Init(&lockedInStream, startPos); - startPos += packSizes[j]; - - CLimitedSequentialInStream *streamSpec = new - CLimitedSequentialInStream; + lockedStreamImpSpec->Init(&lockedInStream, startPos + packPositions[j]); + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr<ISequentialInStream> inStream = streamSpec; streamSpec->SetStream(lockedStreamImp); - streamSpec->Init(packSizes[j]); + streamSpec->Init(packPositions[j + 1] - packPositions[j]); inStreams.Add(inStream); } - int numCoders = folderInfo.Coders.Size(); + unsigned numCoders = folderInfo.Coders.Size(); CBindInfoEx bindInfo; ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo); @@ -139,7 +147,7 @@ HRESULT CDecoder::Decode( createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev); if (createNewCoders) { - int i; + unsigned i; _decoders.Clear(); // _decoders2.Clear(); @@ -204,17 +212,19 @@ HRESULT CDecoder::Decode( decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { - RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo)); + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); } #endif } _bindInfoExPrev = bindInfo; _bindInfoExPrevIsDefined = true; } - int i; + unsigned i; _mixerCoderCommon->ReInit(); - UInt32 packStreamIndex = 0, unpackStreamIndex = 0; + UInt32 packStreamIndex = 0; + UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex]; + UInt32 unpackStreamIndex = unpackStreamIndexStart; UInt32 coderIndex = 0; // UInt32 coder2Index = 0; @@ -229,7 +239,7 @@ HRESULT CDecoder::Decode( if (setDecoderProperties) { const CByteBuffer &props = coderInfo.Props; - size_t size = props.GetCapacity(); + size_t size = props.Size(); if (size > 0xFFFFFFFF) return E_NOTIMPL; // if (size > 0) @@ -257,22 +267,23 @@ HRESULT CDecoder::Decode( decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); if (cryptoSetPassword) { - if (getTextPassword == 0) - return E_FAIL; + isEncrypted = true; + if (!getTextPassword) + return E_NOTIMPL; CMyComBSTR passwordBSTR; RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR)); - CByteBuffer buffer; passwordIsDefined = true; - const UString password(passwordBSTR); - const UInt32 sizeInBytes = password.Length() * 2; - buffer.SetCapacity(sizeInBytes); - for (int i = 0; i < password.Length(); i++) + size_t len = 0; + if (passwordBSTR) + len = MyStringLen((BSTR)passwordBSTR); + CByteBuffer buffer(len * 2); + for (size_t i = 0; i < len; i++) { - wchar_t c = password[i]; + wchar_t c = passwordBSTR[i]; ((Byte *)buffer)[i * 2] = (Byte)c; ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); } - RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes)); + RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size())); } } #endif @@ -281,32 +292,30 @@ HRESULT CDecoder::Decode( UInt32 numInStreams = (UInt32)coderInfo.NumInStreams; UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams; - CRecordVector<const UInt64 *> packSizesPointers; - CRecordVector<const UInt64 *> unpackSizesPointers; - packSizesPointers.Reserve(numInStreams); - unpackSizesPointers.Reserve(numOutStreams); + CObjArray<UInt64> packSizes(numInStreams); + CObjArray<const UInt64 *> packSizesPointers(numInStreams); + CObjArray<const UInt64 *> unpackSizesPointers(numOutStreams); UInt32 j; + for (j = 0; j < numOutStreams; j++, unpackStreamIndex++) - unpackSizesPointers.Add(&folderInfo.UnpackSizes[unpackStreamIndex]); + unpackSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndex]; for (j = 0; j < numInStreams; j++, packStreamIndex++) { int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex); if (bindPairIndex >= 0) - packSizesPointers.Add( - &folderInfo.UnpackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]); + packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + (UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]; else { int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex); if (index < 0) - return E_FAIL; - packSizesPointers.Add(&packSizes[index]); + return S_FALSE; // check it + packSizes[j] = packPositions[index + 1] - packPositions[index]; + packSizesPointers[j] = &packSizes[j]; } } - _mixerCoderCommon->SetCoderInfo(i, - &packSizesPointers.Front(), - &unpackSizesPointers.Front()); + _mixerCoderCommon->SetCoderInfo(i, packSizesPointers, unpackSizesPointers); } UInt32 mainCoder, temp; bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp); @@ -320,13 +329,15 @@ HRESULT CDecoder::Decode( if (numCoders == 0) return 0; - CRecordVector<ISequentialInStream *> inStreamPointers; - inStreamPointers.Reserve(inStreams.Size()); - for (i = 0; i < inStreams.Size(); i++) - inStreamPointers.Add(inStreams[i]); + unsigned num = inStreams.Size(); + CObjArray<ISequentialInStream *> inStreamPointers(num); + for (i = 0; i < num; i++) + inStreamPointers[i] = inStreams[i]; ISequentialOutStream *outStreamPointer = outStream; - return _mixerCoder->Code(&inStreamPointers.Front(), NULL, - inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress); + return _mixerCoder->Code( + inStreamPointers, NULL, num, + &outStreamPointer, NULL, 1, + compressProgress); } }} diff --git a/CPP/7zip/Archive/7z/7zDecode.h b/CPP/7zip/Archive/7z/7zDecode.h index d8a424a3..1361772c 100755..100644 --- a/CPP/7zip/Archive/7z/7zDecode.h +++ b/CPP/7zip/Archive/7z/7zDecode.h @@ -14,7 +14,7 @@ #include "../../Common/CreateCoder.h" -#include "7zItem.h" +#include "7zIn.h" namespace NArchive { namespace N7z { @@ -50,13 +50,10 @@ public: DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, UInt64 startPos, - const UInt64 *packSizes, - const CFolder &folder, + const CFolders &folders, int folderIndex, ISequentialOutStream *outStream, ICompressProgressInfo *compressProgress - #ifndef _NO_CRYPTO - , ICryptoGetTextPassword *getTextPasswordSpec, bool &passwordIsDefined - #endif + _7Z_DECODER_CRYPRO_VARS_DECL #if !defined(_7ZIP_ST) && !defined(_SFX) , bool mtMode, UInt32 numThreads #endif diff --git a/CPP/7zip/Archive/7z/7zEncode.cpp b/CPP/7zip/Archive/7z/7zEncode.cpp index 614f9913..36ff5177 100755..100644 --- a/CPP/7zip/Archive/7z/7zEncode.cpp +++ b/CPP/7zip/Archive/7z/7zEncode.cpp @@ -23,30 +23,30 @@ static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindIn const CRecordVector<CMethodId> decompressionMethods, CFolder &folder) { - folder.Coders.Clear(); // bindInfo.CoderMethodIDs.Clear(); // folder.OutStreams.Clear(); - folder.PackStreams.Clear(); - folder.BindPairs.Clear(); - int i; + folder.BindPairs.SetSize(bindInfo.BindPairs.Size()); + unsigned i; for (i = 0; i < bindInfo.BindPairs.Size(); i++) { - CBindPair bindPair; - bindPair.InIndex = bindInfo.BindPairs[i].InIndex; - bindPair.OutIndex = bindInfo.BindPairs[i].OutIndex; - folder.BindPairs.Add(bindPair); + CBindPair &bp = folder.BindPairs[i]; + const NCoderMixer::CBindPair &mixerBp = bindInfo.BindPairs[i]; + bp.InIndex = mixerBp.InIndex; + bp.OutIndex = mixerBp.OutIndex; } + folder.Coders.SetSize(bindInfo.Coders.Size()); for (i = 0; i < bindInfo.Coders.Size(); i++) { - CCoderInfo coderInfo; + CCoderInfo &coderInfo = folder.Coders[i]; const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i]; coderInfo.NumInStreams = coderStreamsInfo.NumInStreams; coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams; coderInfo.MethodID = decompressionMethods[i]; - folder.Coders.Add(coderInfo); + // coderInfo.Props can be nonFree; } + folder.PackStreams.SetSize(bindInfo.InStreams.Size()); for (i = 0; i < bindInfo.InStreams.Size(); i++) - folder.PackStreams.Add(bindInfo.InStreams[i]); + folder.PackStreams[i] = bindInfo.InStreams[i]; } static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder) @@ -65,11 +65,10 @@ HRESULT CEncoder::CreateMixerCoder( _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT; _mixerCoder = _mixerCoderSpec; RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo)); - for (int i = 0; i < _options.Methods.Size(); i++) + FOR_VECTOR (i, _options.Methods) { const CMethodFull &methodFull = _options.Methods[i]; - _codersInfo.Add(CCoderInfo()); - CCoderInfo &encodingInfo = _codersInfo.Back(); + CCoderInfo &encodingInfo = _codersInfo.AddNew(); encodingInfo.MethodID = methodFull.Id; CMyComPtr<ICompressCoder> encoder; CMyComPtr<ICompressCoder2> encoder2; @@ -100,7 +99,7 @@ HRESULT CEncoder::CreateMixerCoder( /* CMyComPtr<ICryptoResetSalt> resetSalt; encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt); - if (resetSalt != NULL) + if (resetSalt) { resetSalt->ResetSalt(); } @@ -111,7 +110,7 @@ HRESULT CEncoder::CreateMixerCoder( encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { - RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo)); + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); } #endif @@ -120,10 +119,9 @@ HRESULT CEncoder::CreateMixerCoder( if (cryptoSetPassword) { - CByteBuffer buffer; - const UInt32 sizeInBytes = _options.Password.Length() * 2; - buffer.SetCapacity(sizeInBytes); - for (int i = 0; i < _options.Password.Length(); i++) + const UInt32 sizeInBytes = _options.Password.Len() * 2; + CByteBuffer buffer(sizeInBytes); + for (unsigned i = 0; i < _options.Password.Len(); i++) { wchar_t c = _options.Password[i]; ((Byte *)buffer)[i * 2] = (Byte)c; @@ -145,13 +143,15 @@ HRESULT CEncoder::Encode( ISequentialInStream *inStream, const UInt64 *inStreamSize, const UInt64 *inSizeForReduce, CFolder &folderItem, + CRecordVector<UInt64> &coderUnpackSizes, + UInt64 &unpackSize, ISequentialOutStream *outStream, CRecordVector<UInt64> &packSizes, ICompressProgressInfo *compressProgress) { RINOK(EncoderConstr()); - if (_mixerCoderSpec == NULL) + if (!_mixerCoderSpec) { RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce)); } @@ -161,13 +161,13 @@ HRESULT CEncoder::Encode( CObjectVector<CInOutTempBuffer> inOutTempBuffers; CObjectVector<CSequentialOutTempBufferImp *> tempBufferSpecs; CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers; - int numMethods = _bindInfo.Coders.Size(); - int i; + unsigned numMethods = _bindInfo.Coders.Size(); + unsigned i; for (i = 1; i < _bindInfo.OutStreams.Size(); i++) { - inOutTempBuffers.Add(CInOutTempBuffer()); - inOutTempBuffers.Back().Create(); - inOutTempBuffers.Back().InitWriting(); + CInOutTempBuffer &iotb = inOutTempBuffers.AddNew(); + iotb.Create(); + iotb.InitWriting(); } for (i = 1; i < _bindInfo.OutStreams.Size(); i++) { @@ -186,7 +186,7 @@ HRESULT CEncoder::Encode( UInt32 mainCoderIndex, mainStreamIndex; _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex); - if (inStreamSize != NULL) + if (inStreamSize) { CRecordVector<const UInt64 *> sizePointers; for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++) @@ -203,17 +203,24 @@ HRESULT CEncoder::Encode( CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2; CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec; - CSequentialOutStreamSizeCount *outStreamSizeCountSpec = new CSequentialOutStreamSizeCount; - CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec; + CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL; + CMyComPtr<ISequentialOutStream> outStreamSizeCount; inStreamSizeCountSpec->Init(inStream); - outStreamSizeCountSpec->SetStream(outStream); - outStreamSizeCountSpec->Init(); CRecordVector<ISequentialInStream *> inStreamPointers; CRecordVector<ISequentialOutStream *> outStreamPointers; inStreamPointers.Add(inStreamSizeCount); - outStreamPointers.Add(outStreamSizeCount); + + if (_bindInfo.OutStreams.Size() != 0) + { + outStreamSizeCountSpec = new CSequentialOutStreamSizeCount; + outStreamSizeCount = outStreamSizeCountSpec; + outStreamSizeCountSpec->SetStream(outStream); + outStreamSizeCountSpec->Init(); + outStreamPointers.Add(outStreamSizeCount); + } + for (i = 1; i < _bindInfo.OutStreams.Size(); i++) outStreamPointers.Add(tempBuffers[i - 1]); @@ -223,14 +230,14 @@ HRESULT CEncoder::Encode( CMyComPtr<ICryptoResetInitVector> resetInitVector; _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector); - if (resetInitVector != NULL) + if (resetInitVector) { resetInitVector->ResetInitVector(); } CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties; _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties); - if (writeCoderProperties != NULL) + if (writeCoderProperties) { CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream; CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); @@ -256,7 +263,8 @@ HRESULT CEncoder::Encode( ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, folderItem); - packSizes.Add(outStreamSizeCountSpec->GetSize()); + if (_bindInfo.OutStreams.Size() != 0) + packSizes.Add(outStreamSizeCountSpec->GetSize()); for (i = 1; i < _bindInfo.OutStreams.Size(); i++) { @@ -264,19 +272,23 @@ HRESULT CEncoder::Encode( RINOK(inOutTempBuffer.WriteToStream(outStream)); packSizes.Add(inOutTempBuffer.GetDataSize()); } - + + unpackSize = 0; for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++) { int binder = _bindInfo.FindBinderForInStream( _bindReverseConverter->DestOutToSrcInMap[i]); UInt64 streamSize; if (binder < 0) + { streamSize = inStreamSizeCountSpec->GetSize(); + unpackSize = streamSize; + } else streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder); - folderItem.UnpackSizes.Add(streamSize); + coderUnpackSizes.Add(streamSize); } - for (i = numMethods - 1; i >= 0; i--) + for (i = 0; i < numMethods; i++) folderItem.Coders[numMethods - 1 - i].Props = _codersInfo[i].Props; return S_OK; } @@ -323,7 +335,7 @@ HRESULT CEncoder::EncoderConstr() { UInt32 numInStreams = 0, numOutStreams = 0; - int i; + unsigned i; for (i = 0; i < _options.Methods.Size(); i++) { const CMethodFull &methodFull = _options.Methods[i]; @@ -339,7 +351,7 @@ HRESULT CEncoder::EncoderConstr() bindPair.OutIndex = numOutStreams; _bindInfo.BindPairs.Add(bindPair); } - else + else if (coderStreamsInfo.NumOutStreams != 0) _bindInfo.OutStreams.Insert(0, numOutStreams); for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++) _bindInfo.OutStreams.Add(numOutStreams + j); @@ -398,7 +410,7 @@ HRESULT CEncoder::EncoderConstr() if (_options.PasswordIsDefined) { - int numCryptoStreams = _bindInfo.OutStreams.Size(); + unsigned numCryptoStreams = _bindInfo.OutStreams.Size(); for (i = 0; i < numCryptoStreams; i++) { diff --git a/CPP/7zip/Archive/7z/7zEncode.h b/CPP/7zip/Archive/7z/7zEncode.h index 4909a6e8..8e20bdb5 100755..100644 --- a/CPP/7zip/Archive/7z/7zEncode.h +++ b/CPP/7zip/Archive/7z/7zEncode.h @@ -45,6 +45,8 @@ public: ISequentialInStream *inStream, const UInt64 *inStreamSize, const UInt64 *inSizeForReduce, CFolder &folderItem, + CRecordVector<UInt64> &coderUnpackSizes, + UInt64 &unpackSize, ISequentialOutStream *outStream, CRecordVector<UInt64> &packSizes, ICompressProgressInfo *compressProgress); diff --git a/CPP/7zip/Archive/7z/7zExtract.cpp b/CPP/7zip/Archive/7z/7zExtract.cpp index d55f38e1..6d2c5b06 100755..100644 --- a/CPP/7zip/Archive/7z/7zExtract.cpp +++ b/CPP/7zip/Archive/7z/7zExtract.cpp @@ -37,8 +37,8 @@ struct CExtractFolderInfo { if (fileIndex != kNumNoIndex) { - ExtractStatuses.Reserve(1); - ExtractStatuses.Add(true); + ExtractStatuses.ClearAndSetSize(1); + ExtractStatuses[0] = true; } }; }; @@ -51,7 +51,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec; UInt64 importantTotalUnpacked = 0; - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = #ifdef _7Z_VOL @@ -67,7 +67,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if(_volumes.Size() != 1) return E_FAIL; const CVolume &volume = _volumes.Front(); - const CArchiveDatabaseEx &_db = volume.Database; + const CDbEx &_db = volume.Database; IInStream *_inStream = volume.Stream; */ @@ -86,10 +86,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, int volumeIndex = ref.VolumeIndex; const CVolume &volume = _volumes[volumeIndex]; - const CArchiveDatabaseEx &db = volume.Database; + const CDbEx &db = volume.Database; UInt32 fileIndex = ref.ItemIndex; #else - const CArchiveDatabaseEx &db = _db; + const CDbEx &db = _db; UInt32 fileIndex = ref2Index; #endif @@ -115,8 +115,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, volumeIndex, #endif kNumNoIndex, folderIndex)); - const CFolder &folderInfo = db.Folders[folderIndex]; - UInt64 unpackSize = folderInfo.GetUnpackSize(); + UInt64 unpackSize = db.GetFolderUnpackSize(folderIndex); importantTotalUnpacked += unpackSize; extractFolderInfoVector.Back().UnpackSize = unpackSize; } @@ -156,7 +155,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); - for (int i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked) + for (unsigned i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked) { lps->OutSize = totalUnpacked; lps->InSize = totalPacked; @@ -174,9 +173,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, #ifdef _7Z_VOL const CVolume &volume = _volumes[efi.VolumeIndex]; - const CArchiveDatabaseEx &db = volume.Database; + const CDbEx &db = volume.Database; #else - const CArchiveDatabaseEx &db = _db; + const CDbEx &db = _db; #endif CNum startIndex; @@ -200,13 +199,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; CNum folderIndex = efi.FolderIndex; - const CFolder &folderInfo = db.Folders[folderIndex]; - curPacked = _db.GetFolderFullPackSize(folderIndex); - CNum packStreamIndex = db.FolderStartPackStreamIndex[folderIndex]; - UInt64 folderStartPackPos = db.GetFolderStreamPos(folderIndex, 0); - #ifndef _NO_CRYPTO CMyComPtr<ICryptoGetTextPassword> getTextPassword; if (extractCallback) @@ -216,26 +210,24 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, try { #ifndef _NO_CRYPTO - bool passwordIsDefined; + bool isEncrypted = false; + bool passwordIsDefined = false; #endif HRESULT result = decoder.Decode( EXTERNAL_CODECS_VARS #ifdef _7Z_VOL - volume.Stream, + volume.Stream, #else - _inStream, + _inStream, #endif - folderStartPackPos, - &db.PackSizes[packStreamIndex], - folderInfo, + db.ArcInfo.DataStartPosition, + db, folderIndex, outStream, progress - #ifndef _NO_CRYPTO - , getTextPassword, passwordIsDefined - #endif + _7Z_DECODER_CRYPRO_VARS #if !defined(_7ZIP_ST) && !defined(_SFX) - , true, _numThreads + , true, _numThreads #endif ); @@ -246,7 +238,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } if (result == E_NOTIMPL) { - RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kUnsupportedMethod)); continue; } if (result != S_OK) diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/CPP/7zip/Archive/7z/7zFolderInStream.cpp index edd276bc..3f420a51 100755..100644 --- a/CPP/7zip/Archive/7z/7zFolderInStream.cpp +++ b/CPP/7zip/Archive/7z/7zFolderInStream.cpp @@ -106,8 +106,8 @@ STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSiz STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value) { *value = 0; - int index2 = (int)subStream; - if (index2 < 0 || subStream > Sizes.Size()) + unsigned index2 = (unsigned)subStream; + if (subStream > Sizes.Size()) return E_FAIL; if (index2 < Sizes.Size()) { diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.h b/CPP/7zip/Archive/7z/7zFolderInStream.h index 6df3672a..4ed4b2dd 100755..100644 --- a/CPP/7zip/Archive/7z/7zFolderInStream.h +++ b/CPP/7zip/Archive/7z/7zFolderInStream.h @@ -47,7 +47,7 @@ public: UInt64 GetFullSize() const { UInt64 size = 0; - for (int i = 0; i < Sizes.Size(); i++) + FOR_VECTOR (i, Sizes) size += Sizes[i]; return size; } diff --git a/CPP/7zip/Archive/7z/7zFolderOutStream.cpp b/CPP/7zip/Archive/7z/7zFolderOutStream.cpp index 22c4600e..847f65bf 100755..100644 --- a/CPP/7zip/Archive/7z/7zFolderOutStream.cpp +++ b/CPP/7zip/Archive/7z/7zFolderOutStream.cpp @@ -14,7 +14,7 @@ CFolderOutStream::CFolderOutStream() } HRESULT CFolderOutStream::Init( - const CArchiveDatabaseEx *db, + const CDbEx *db, UInt32 ref2Offset, UInt32 startIndex, const CBoolVector *extractStatuses, IArchiveExtractCallback *extractCallback, diff --git a/CPP/7zip/Archive/7z/7zFolderOutStream.h b/CPP/7zip/Archive/7z/7zFolderOutStream.h index f9bb1af4..cc2d7734 100755..100644 --- a/CPP/7zip/Archive/7z/7zFolderOutStream.h +++ b/CPP/7zip/Archive/7z/7zFolderOutStream.h @@ -19,12 +19,12 @@ class CFolderOutStream: { COutStreamWithCRC *_crcStreamSpec; CMyComPtr<ISequentialOutStream> _crcStream; - const CArchiveDatabaseEx *_db; + const CDbEx *_db; const CBoolVector *_extractStatuses; CMyComPtr<IArchiveExtractCallback> _extractCallback; UInt32 _ref2Offset; UInt32 _startIndex; - int _currentIndex; + unsigned _currentIndex; bool _testMode; bool _checkCrc; bool _fileIsOpen; @@ -43,7 +43,7 @@ public: STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); HRESULT Init( - const CArchiveDatabaseEx *db, + const CDbEx *db, UInt32 ref2Offset, UInt32 startIndex, const CBoolVector *extractStatuses, IArchiveExtractCallback *extractCallback, diff --git a/CPP/7zip/Archive/7z/7zHandler.cpp b/CPP/7zip/Archive/7z/7zHandler.cpp index 93d4f51e..82983419 100755..100644 --- a/CPP/7zip/Archive/7z/7zHandler.cpp +++ b/CPP/7zip/Archive/7z/7zHandler.cpp @@ -23,6 +23,7 @@ #endif using namespace NWindows; +using namespace NCOM; namespace NArchive { namespace N7z { @@ -30,6 +31,7 @@ namespace N7z { CHandler::CHandler() { #ifndef _NO_CRYPTO + _isEncrypted = false; _passwordIsDefined = false; #endif @@ -49,11 +51,12 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) #ifdef _SFX -IMP_IInArchive_ArcProps_NO +IMP_IInArchive_ArcProps_NO_Table -STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */) +STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) { - return E_NOTIMPL; + *numProps = 0; + return S_OK; } STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */, @@ -62,156 +65,473 @@ STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */, return E_NOTIMPL; } - #else -static const STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidSolid, VT_BOOL}, - { NULL, kpidNumBlocks, VT_UI4}, - { NULL, kpidPhySize, VT_UI8}, - { NULL, kpidHeadersSize, VT_UI8}, - { NULL, kpidOffset, VT_UI8} + kpidHeadersSize, + kpidMethod, + kpidSolid, + kpidNumBlocks + // , kpidIsTree }; -static inline wchar_t GetHex(Byte value) +IMP_IInArchive_ArcProps + +static inline char GetHex(unsigned value) { - return (wchar_t)((value < 10) ? ('0' + value) : ('A' + (value - 10))); + return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); } -static UString ConvertMethodIdToString(UInt64 id) +static unsigned ConvertMethodIdToString_Back(char *s, UInt64 id) { - wchar_t s[32]; - int len = 32; - s[--len] = 0; + int len = 0; do { - s[--len] = GetHex((Byte)id & 0xF); id >>= 4; - s[--len] = GetHex((Byte)id & 0xF); id >>= 4; + s[--len] = GetHex((unsigned)id & 0xF); id >>= 4; + s[--len] = GetHex((unsigned)id & 0xF); id >>= 4; } while (id != 0); - return s + len; + return (unsigned)-len; +} + +static void ConvertMethodIdToString(AString &res, UInt64 id) +{ + const unsigned kLen = 32; + char s[kLen]; + unsigned len = kLen - 1; + s[len] = 0; + res += s + len - ConvertMethodIdToString_Back(s + len, id); +} + +static unsigned GetStringForSizeValue(char *s, UInt32 val) +{ + unsigned i; + for (i = 0; i <= 31; i++) + if (((UInt32)1 << i) == val) + { + if (i < 10) + { + s[0] = (char)('0' + i); + s[1] = 0; + return 1; + } + if (i < 20) { s[0] = '1'; s[1] = (char)('0' + i - 10); } + else if (i < 30) { s[0] = '2'; s[1] = (char)('0' + i - 20); } + else { s[0] = '3'; s[1] = (char)('0' + i - 30); } + s[2] = 0; + return 2; + } + char c = 'b'; + if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } + else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } + ::ConvertUInt32ToString(val, s); + unsigned pos = MyStringLen(s); + s[pos++] = c; + s[pos] = 0; + return pos; } +/* +static inline void AddHexToString(UString &res, Byte value) +{ + res += GetHex((Byte)(value >> 4)); + res += GetHex((Byte)(value & 0xF)); +} +*/ + +static char *AddProp32(char *s, const char *name, UInt32 v) +{ + *s++ = ':'; + s = MyStpCpy(s, name); + ::ConvertUInt32ToString(v, s); + return s + MyStringLen(s); +} + +void CHandler::AddMethodName(AString &s, UInt64 id) +{ + UString methodName; + FindMethod(EXTERNAL_CODECS_VARS id, methodName); + if (methodName.IsEmpty()) + { + for (unsigned i = 0; i < methodName.Len(); i++) + if (methodName[i] >= 0x80) + { + methodName.Empty(); + break; + } + } + if (methodName.IsEmpty()) + ConvertMethodIdToString(s, id); + else + for (unsigned i = 0; i < methodName.Len(); i++) + s += (char)methodName[i]; +} + +#endif + STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { + #ifndef _SFX COM_TRY_BEGIN + #endif NCOM::CPropVariant prop; - switch(propID) + switch (propID) { + #ifndef _SFX case kpidMethod: { - UString resString; - CRecordVector<UInt64> ids; - int i; - for (i = 0; i < _db.Folders.Size(); i++) + AString s; + const CParsedMethods &pm = _db.ParsedMethods; + FOR_VECTOR (i, pm.IDs) { - const CFolder &f = _db.Folders[i]; - for (int j = f.Coders.Size() - 1; j >= 0; j--) - ids.AddToUniqueSorted(f.Coders[j].MethodID); - } - - for (i = 0; i < ids.Size(); i++) - { - UInt64 id = ids[i]; - UString methodName; - /* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName); - if (methodName.IsEmpty()) - methodName = ConvertMethodIdToString(id); - if (!resString.IsEmpty()) - resString += L' '; - resString += methodName; + UInt64 id = pm.IDs[i]; + if (!s.IsEmpty()) + s += ' '; + char temp[16]; + if (id == k_LZMA2) + { + s += "LZMA2:"; + if ((pm.Lzma2Prop & 1) == 0) + ConvertUInt32ToString((pm.Lzma2Prop >> 1) + 12, temp); + else + GetStringForSizeValue(temp, 3 << ((pm.Lzma2Prop >> 1) + 11)); + s += temp; + } + else if (id == k_LZMA) + { + s += "LZMA:"; + GetStringForSizeValue(temp, pm.LzmaDic); + s += temp; + } + else + AddMethodName(s, id); } - prop = resString; + prop = s; break; } case kpidSolid: prop = _db.IsSolid(); break; - case kpidNumBlocks: prop = (UInt32)_db.Folders.Size(); break; + case kpidNumBlocks: prop = (UInt32)_db.NumFolders; break; case kpidHeadersSize: prop = _db.HeadersSize; break; case kpidPhySize: prop = _db.PhySize; break; - case kpidOffset: if (_db.ArchiveInfo.StartPosition != 0) prop = _db.ArchiveInfo.StartPosition; break; + case kpidOffset: if (_db.ArcInfo.StartPosition != 0) prop = _db.ArcInfo.StartPosition; break; + /* + case kpidIsTree: if (_db.IsTree) prop = true; break; + case kpidIsAltStream: if (_db.ThereAreAltStreams) prop = true; break; + case kpidIsAux: if (_db.IsTree) prop = true; break; + */ + // case kpidError: if (_db.ThereIsHeaderError) prop = "Header error"; break; + #endif + + case kpidWarningFlags: + { + UInt32 v = 0; + if (_db.StartHeaderWasRecovered) v |= kpv_ErrorFlags_HeadersError; + if (_db.UnsupportedFeatureWarning) v |= kpv_ErrorFlags_UnsupportedFeature; + if (v != 0) + prop = v; + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_db.IsArc) v |= kpv_ErrorFlags_IsNotArc; + if (_db.ThereIsHeaderError) v |= kpv_ErrorFlags_HeadersError; + if (_db.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + // if (_db.UnsupportedVersion) v |= kpv_ErrorFlags_Unsupported; + if (_db.UnsupportedFeatureError) v |= kpv_ErrorFlags_UnsupportedFeature; + prop = v; + break; + } } prop.Detach(value); return S_OK; + #ifndef _SFX COM_TRY_END + #endif } -IMP_IInArchive_ArcProps - -#endif - -static void SetPropFromUInt64Def(CUInt64DefVector &v, int index, NCOM::CPropVariant &prop) +static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVector &v, int index) { UInt64 value; if (v.GetItem(index, value)) + PropVarEm_Set_FileTime64(prop, value); +} + +bool CHandler::IsFolderEncrypted(CNum folderIndex) const +{ + if (folderIndex == kNumNoIndex) + return false; + size_t startPos = _db.FoCodersDataOffset[folderIndex]; + const Byte *p = _db.CodersData + startPos; + size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos; + CInByte2 inByte; + inByte.Init(p, size); + + CNum numCoders = inByte.ReadNum(); + for (; numCoders != 0; numCoders--) { - FILETIME ft; - ft.dwLowDateTime = (DWORD)value; - ft.dwHighDateTime = (DWORD)(value >> 32); - prop = ft; + Byte mainByte = inByte.ReadByte(); + unsigned idSize = (mainByte & 0xF); + const Byte *longID = inByte.GetPtr(); + UInt64 id64 = 0; + for (unsigned j = 0; j < idSize; j++) + id64 = ((id64 << 8) | longID[j]); + inByte.SkipDataNoCheck(idSize); + if (id64 == k_AES) + return true; + if ((mainByte & 0x20) != 0) + inByte.SkipDataNoCheck(inByte.ReadNum()); } + return false; } -#ifndef _SFX +STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) +{ + *numProps = 0; + return S_OK; +} -static UString ConvertUInt32ToString(UInt32 value) +STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) { - wchar_t buffer[32]; - ConvertUInt64ToString(value, buffer); - return buffer; + *name = NULL; + *propID = kpidNtSecure; + return S_OK; } -static UString GetStringForSizeValue(UInt32 value) +STDMETHODIMP CHandler::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType) { - for (int i = 31; i >= 0; i--) - if ((UInt32(1) << i) == value) - return ConvertUInt32ToString(i); - UString result; - if (value % (1 << 20) == 0) - { - result += ConvertUInt32ToString(value >> 20); - result += L"m"; - } - else if (value % (1 << 10) == 0) + /* + const CFileItem &file = _db.Files[index]; + *parentType = (file.IsAltStream ? NParentType::kAltStream : NParentType::kDir); + *parent = (UInt32)(Int32)file.Parent; + */ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; + return S_OK; +} + +STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + + if (/* _db.IsTree && propID == kpidName || + !_db.IsTree && */ propID == kpidPath) { - result += ConvertUInt32ToString(value >> 10); - result += L"k"; + *data = (void *)_db.GetName(index); + if (*data) + { + *dataSize = (UInt32)((_db.NameOffsets[index + 1] - _db.NameOffsets[index]) * 2); + *propType = NPropDataType::kUtf16z; + } + return S_OK; } - else + /* + if (propID == kpidNtSecure) { - result += ConvertUInt32ToString(value); - result += L"b"; + if (index < (UInt32)_db.SecureIDs.Size()) + { + int id = _db.SecureIDs[index]; + size_t offs = _db.SecureOffsets[id]; + size_t size = _db.SecureOffsets[id + 1] - offs; + if (size >= 0) + { + *data = _db.SecureBuf + offs; + *dataSize = (UInt32)size; + *propType = NPropDataType::kRaw; + } + } } - return result; + */ + return S_OK; } -static inline void AddHexToString(UString &res, Byte value) -{ - res += GetHex((Byte)(value >> 4)); - res += GetHex((Byte)(value & 0xF)); -} +#ifndef _SFX -static void AddProp32(UString &s, const wchar_t *name, UInt32 v) +HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const { - s += name; - s += ConvertUInt32ToString(v); -} + PropVariant_Clear(prop); + if (folderIndex == kNumNoIndex) + return S_OK; + // for (int ttt = 0; ttt < 1; ttt++) { + const unsigned kTempSize = 256; + char temp[kTempSize]; + unsigned pos = kTempSize; + temp[--pos] = 0; -#endif - -bool CHandler::IsEncrypted(UInt32 index2) const -{ - CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; - if (folderIndex != kNumNoIndex) - return _db.Folders[folderIndex].IsEncrypted(); - return false; + size_t startPos = _db.FoCodersDataOffset[folderIndex]; + const Byte *p = _db.CodersData + startPos; + size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos; + CInByte2 inByte; + inByte.Init(p, size); + + // numCoders == 0 ??? + CNum numCoders = inByte.ReadNum(); + bool needSpace = false; + for (; numCoders != 0; numCoders--, needSpace = true) + { + if (pos < 32) // max size of property + break; + Byte mainByte = inByte.ReadByte(); + unsigned idSize = (mainByte & 0xF); + const Byte *longID = inByte.GetPtr(); + UInt64 id64 = 0; + for (unsigned j = 0; j < idSize; j++) + id64 = ((id64 << 8) | longID[j]); + inByte.SkipDataNoCheck(idSize); + CNum propsSize = 0; + const Byte *props = NULL; + if ((mainByte & 0x20) != 0) + { + propsSize = inByte.ReadNum(); + props = inByte.GetPtr(); + inByte.SkipDataNoCheck(propsSize); + } + + const char *name = NULL; + char s[32]; + s[0] = 0; + + if (id64 <= (UInt32)0xFFFFFFFF) + { + UInt32 id = (UInt32)id64; + if (id == k_LZMA) + { + name = "LZMA"; + if (propsSize == 5) + { + UInt32 dicSize = GetUi32((const Byte *)props + 1); + char *dest = s + GetStringForSizeValue(s, dicSize); + UInt32 d = props[0]; + if (d != 0x5D) + { + UInt32 lc = d % 9; + d /= 9; + UInt32 pb = d / 5; + UInt32 lp = d % 5; + if (lc != 3) dest = AddProp32(dest, "lc", lc); + if (lp != 0) dest = AddProp32(dest, "lp", lp); + if (pb != 2) dest = AddProp32(dest, "pb", pb); + } + } + } + else if (id == k_LZMA2) + { + name = "LZMA2"; + if (propsSize == 1) + { + Byte p = props[0]; + if ((p & 1) == 0) + ConvertUInt32ToString((UInt32)((p >> 1) + 12), s); + else + GetStringForSizeValue(s, 3 << ((p >> 1) + 11)); + } + } + else if (id == k_PPMD) + { + name = "PPMD"; + if (propsSize == 5) + { + Byte order = *props; + char *dest = s; + *dest++ = 'o'; + ConvertUInt32ToString(order, dest); + dest += MyStringLen(dest); + dest = MyStpCpy(dest, ":mem"); + GetStringForSizeValue(dest, GetUi32(props + 1)); + } + } + 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) + { + unsigned nameLen = MyStringLen(name); + unsigned propsLen = MyStringLen(s); + unsigned totalLen = nameLen + propsLen; + if (propsLen != 0) + totalLen++; + if (needSpace) + totalLen++; + if (totalLen + 5 >= pos) + break; + pos -= totalLen; + MyStringCopy(temp + pos, name); + if (propsLen != 0) + { + char *dest = temp + pos + nameLen; + *dest++ = ':'; + MyStringCopy(dest, s); + } + if (needSpace) + temp[pos + totalLen - 1] = ' '; + } + else + { + UString methodName; + FindMethod(EXTERNAL_CODECS_VARS id64, methodName); + if (methodName.IsEmpty()) + { + for (unsigned j = 0; j < methodName.Len(); j++) + if (methodName[j] >= 0x80) + { + methodName.Empty(); + break; + } + } + if (needSpace) + temp[--pos] = ' '; + if (methodName.IsEmpty()) + pos -= ConvertMethodIdToString_Back(temp + pos, id64); + else + { + unsigned len = methodName.Len(); + if (len + 5 > pos) + break; + pos -= len; + for (unsigned i = 0; i < len; i++) + temp[pos + i] = (char)methodName[i]; + } + } + } + if (numCoders != 0 && pos >= 4) + { + temp[--pos] = ' '; + temp[--pos] = '.'; + temp[--pos] = '.'; + temp[--pos] = '.'; + } + return PropVarEm_Set_Str(prop, temp + pos); + // } } -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +#endif + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { - COM_TRY_BEGIN - NCOM::CPropVariant prop; + PropVariant_Clear(value); + // COM_TRY_BEGIN + // NCOM::CPropVariant prop; /* const CRef2 &ref2 = _refs[index]; @@ -225,14 +545,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va switch(propID) { - case kpidPath: - if (!item.Name.IsEmpty()) - prop = NItemName::GetOSName(item.Name); - break; - case kpidIsDir: prop = item.IsDir; break; + case kpidIsDir: PropVarEm_Set_Bool(value, item.IsDir); break; case kpidSize: { - prop = item.Size; + PropVarEm_Set_UInt64(value, item.Size); // prop = ref2.Size; break; } @@ -244,130 +560,49 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va if (folderIndex != kNumNoIndex) { if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2) - prop = _db.GetFolderFullPackSize(folderIndex); + PropVarEm_Set_UInt64(value, _db.GetFolderFullPackSize(folderIndex)); /* else - prop = (UInt64)0; + PropVarEm_Set_UInt64(value, 0); */ } else - prop = (UInt64)0; + PropVarEm_Set_UInt64(value, 0); } break; } - case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) prop = v; break; } - case kpidCTime: SetPropFromUInt64Def(_db.CTime, index2, prop); break; - case kpidATime: SetPropFromUInt64Def(_db.ATime, index2, prop); break; - case kpidMTime: SetPropFromUInt64Def(_db.MTime, index2, prop); break; - case kpidAttrib: if (item.AttribDefined) prop = item.Attrib; break; - case kpidCRC: if (item.CrcDefined) prop = item.Crc; break; - case kpidEncrypted: prop = IsEncrypted(index2); break; - case kpidIsAnti: prop = _db.IsItemAnti(index2); break; - #ifndef _SFX - case kpidMethod: + // case kpidIsAux: prop = _db.IsItemAux(index2); break; + case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) PropVarEm_Set_UInt64(value, v); break; } + 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 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; + /* + case kpidIsAltStream: prop = item.IsAltStream; break; + case kpidNtSecure: { - CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; - if (folderIndex != kNumNoIndex) + int id = _db.SecureIDs[index]; + size_t offs = _db.SecureOffsets[id]; + size_t size = _db.SecureOffsets[id + 1] - offs; + if (size >= 0) { - const CFolder &folderInfo = _db.Folders[folderIndex]; - UString methodsString; - for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--) - { - const CCoderInfo &coder = folderInfo.Coders[i]; - if (!methodsString.IsEmpty()) - methodsString += L' '; - - UString methodName, propsString; - bool methodIsKnown = FindMethod( - EXTERNAL_CODECS_VARS - coder.MethodID, methodName); - - if (!methodIsKnown) - methodsString += ConvertMethodIdToString(coder.MethodID); - else - { - methodsString += methodName; - if (coder.MethodID == k_Delta && coder.Props.GetCapacity() == 1) - propsString = ConvertUInt32ToString((UInt32)coder.Props[0] + 1); - else if (coder.MethodID == k_LZMA && coder.Props.GetCapacity() == 5) - { - UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1); - propsString = GetStringForSizeValue(dicSize); - UInt32 d = coder.Props[0]; - UInt32 lc = d % 9; - d /= 9; - UInt32 pb = d / 5; - UInt32 lp = d % 5; - if (lc != 3) AddProp32(propsString, L":lc", lc); - if (lp != 0) AddProp32(propsString, L":lp", lp); - if (pb != 2) AddProp32(propsString, L":pb", pb); - } - else if (coder.MethodID == k_LZMA2 && coder.Props.GetCapacity() == 1) - { - Byte p = coder.Props[0]; - UInt32 dicSize = (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)); - propsString = GetStringForSizeValue(dicSize); - } - else if (coder.MethodID == k_PPMD && coder.Props.GetCapacity() == 5) - { - Byte order = *(const Byte *)coder.Props; - propsString = L'o'; - propsString += ConvertUInt32ToString(order); - propsString += L":mem"; - UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1); - propsString += GetStringForSizeValue(dicSize); - } - else if (coder.MethodID == k_AES && coder.Props.GetCapacity() >= 1) - { - const Byte *data = (const Byte *)coder.Props; - Byte firstByte = *data++; - UInt32 numCyclesPower = firstByte & 0x3F; - propsString = ConvertUInt32ToString(numCyclesPower); - /* - if ((firstByte & 0xC0) != 0) - { - UInt32 saltSize = (firstByte >> 7) & 1; - UInt32 ivSize = (firstByte >> 6) & 1; - if (coder.Props.GetCapacity() >= 2) - { - Byte secondByte = *data++; - saltSize += (secondByte >> 4); - ivSize += (secondByte & 0x0F); - } - } - */ - } - } - if (!propsString.IsEmpty()) - { - methodsString += L':'; - methodsString += propsString; - } - else if (coder.Props.GetCapacity() > 0) - { - methodsString += L":["; - for (size_t bi = 0; bi < coder.Props.GetCapacity(); bi++) - { - if (bi > 5 && bi + 1 < coder.Props.GetCapacity()) - { - methodsString += L".."; - break; - } - else - AddHexToString(methodsString, coder.Props[bi]); - } - methodsString += L']'; - } - } - prop = methodsString; + prop.SetBlob(_db.SecureBuf + offs, (ULONG)size); } + break; } - break; + */ + + case kpidPath: return _db.GetPath(index, value); + #ifndef _SFX + case kpidMethod: return SetMethodToProp(_db.FileIndexToFolderIndexMap[index2], value); case kpidBlock: { CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; if (folderIndex != kNumNoIndex) - prop = (UInt32)folderIndex; + PropVarEm_Set_UInt32(value, (UInt32)folderIndex); } break; case kpidPackedSize0: @@ -376,6 +611,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va case kpidPackedSize3: case kpidPackedSize4: { + /* CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; if (folderIndex != kNumNoIndex) { @@ -390,13 +626,14 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va } else prop = (UInt64)0; + */ } break; #endif } - prop.Detach(value); + // prop.Detach(value); return S_OK; - COM_TRY_END + // COM_TRY_END } STDMETHODIMP CHandler::Open(IInStream *stream, @@ -408,6 +645,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, #ifndef _SFX _fileInfoPopIDs.Clear(); #endif + try { CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback; @@ -415,31 +653,30 @@ STDMETHODIMP CHandler::Open(IInStream *stream, #ifndef _NO_CRYPTO CMyComPtr<ICryptoGetTextPassword> getTextPassword; if (openArchiveCallback) - { - openArchiveCallbackTemp.QueryInterface( - IID_ICryptoGetTextPassword, &getTextPassword); - } + openArchiveCallbackTemp.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); #endif + CInArchive archive; + _db.IsArc = false; RINOK(archive.Open(stream, maxCheckStartPosition)); - #ifndef _NO_CRYPTO - _passwordIsDefined = false; - UString password; - #endif + _db.IsArc = true; + HRESULT result = archive.ReadDatabase( - EXTERNAL_CODECS_VARS - _db - #ifndef _NO_CRYPTO - , getTextPassword, _passwordIsDefined - #endif - ); + EXTERNAL_CODECS_VARS + _db + #ifndef _NO_CRYPTO + , getTextPassword, _isEncrypted, _passwordIsDefined + #endif + ); RINOK(result); - _db.Fill(); + _inStream = stream; } catch(...) { Close(); + // return E_INVALIDARG; + // we must return out_of_memory here return S_FALSE; } // _inStream = stream; @@ -455,6 +692,10 @@ STDMETHODIMP CHandler::Close() COM_TRY_BEGIN _inStream.Release(); _db.Clear(); + #ifndef _NO_CRYPTO + _isEncrypted = false; + _passwordIsDefined = false; + #endif return S_OK; COM_TRY_END } @@ -462,16 +703,16 @@ STDMETHODIMP CHandler::Close() #ifdef __7Z_SET_PROPERTIES #ifdef EXTRACT_ONLY -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); _numThreads = numProcessors; - for (int i = 0; i < numProperties; i++) + for (UInt32 i = 0; i < numProps; i++) { UString name = names[i]; - name.MakeUpper(); + name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &value = values[i]; @@ -479,9 +720,9 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v int index = ParseStringToUInt32(name, number); if (index == 0) { - if(name.Left(2).CompareNoCase(L"MT") == 0) + if (name.IsPrefixedBy(L"mt")) { - RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads)); + RINOK(ParseMtProp(name.Ptr(2), value, numProcessors, _numThreads)); continue; } else diff --git a/CPP/7zip/Archive/7z/7zHandler.h b/CPP/7zip/Archive/7z/7zHandler.h index 247b55f7..dad943e0 100755..100644 --- a/CPP/7zip/Archive/7z/7zHandler.h +++ b/CPP/7zip/Archive/7z/7zHandler.h @@ -58,10 +58,11 @@ public: bool _compressHeaders; bool _encryptHeadersSpecified; bool _encryptHeaders; + // bool _useParents; 9.26 - bool WriteCTime; - bool WriteATime; - bool WriteMTime; + CBoolPair Write_CTime; + CBoolPair Write_ATime; + CBoolPair Write_MTime; bool _volumeMode; @@ -85,10 +86,8 @@ public: #endif class CHandler: - #ifndef EXTRACT_ONLY - public COutHandler, - #endif public IInArchive, + public IArchiveGetRawProps, #ifdef __7Z_SET_PROPERTIES public ISetProperties, #endif @@ -97,9 +96,13 @@ class CHandler: #endif PUBLIC_ISetCompressCodecsInfo public CMyUnknownImp + #ifndef EXTRACT_ONLY + , public COutHandler + #endif { public: MY_QUERYINTERFACE_BEGIN2(IInArchive) + // MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps) #ifdef __7Z_SET_PROPERTIES MY_QUERYINTERFACE_ENTRY(ISetProperties) #endif @@ -111,9 +114,10 @@ public: MY_ADDREF_RELEASE INTERFACE_IInArchive(;) + INTERFACE_IArchiveGetRawProps(;) #ifdef __7Z_SET_PROPERTIES - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties); + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); #endif #ifndef EXTRACT_ONLY @@ -126,8 +130,9 @@ public: private: CMyComPtr<IInStream> _inStream; - NArchive::N7z::CArchiveDatabaseEx _db; + NArchive::N7z::CDbEx _db; #ifndef _NO_CRYPTO + bool _isEncrypted; bool _passwordIsDefined; #endif @@ -156,11 +161,13 @@ private: #endif - bool IsEncrypted(UInt32 index2) const; + bool IsFolderEncrypted(CNum folderIndex) const; #ifndef _SFX CRecordVector<UInt64> _fileInfoPopIDs; void FillPopIDs(); + void AddMethodName(AString &s, UInt64 id); + HRESULT SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const; #endif diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp index dd73ee84..2f6a4c37 100755..100644 --- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp +++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp @@ -4,6 +4,7 @@ #include "../../../Common/ComTry.h" #include "../../../Common/StringToInt.h" +#include "../../../Common/Wildcard.h" #include "../Common/ItemNameUtils.h" #include "../Common/ParseProperties.h" @@ -18,7 +19,7 @@ namespace NArchive { namespace N7z { static const wchar_t *k_LZMA_Name = L"LZMA"; -static const wchar_t *kDefaultMethodName = k_LZMA_Name; +static const wchar_t *kDefaultMethodName = L"LZMA2"; static const wchar_t *k_Copy_Name = L"Copy"; static const wchar_t *k_MatchFinder_ForHeaders = L"BT2"; @@ -67,9 +68,9 @@ HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod) void CHandler::AddDefaultMethod() { - for (int i = 0; i < _methods.Size(); i++) + FOR_VECTOR (i, _methods) { - UString &methodName = _methods[0].MethodName; + UString &methodName = _methods[i].MethodName; if (methodName.IsEmpty()) methodName = kDefaultMethodName; } @@ -95,7 +96,7 @@ HRESULT CHandler::SetMainMethod( const UInt64 kSolidBytes_Max = ((UInt64)1 << 32) - 1; bool needSolid = false; - for (int i = 0; i < methods.Size(); i++) + FOR_VECTOR (i, methods) { COneMethodInfo &oneMethodInfo = methods[i]; SetGlobalLevelAndThreads(oneMethodInfo @@ -139,12 +140,10 @@ HRESULT CHandler::SetMainMethod( return S_OK; } -static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, bool writeTime, PROPID propID, UInt64 &ft, bool &ftDefined) +static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, UInt64 &ft, bool &ftDefined) { - ft = 0; - ftDefined = false; - if (!writeTime) - return S_OK; + // ft = 0; + // ftDefined = false; NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(index, propID, &prop)); if (prop.vt == VT_FILETIME) @@ -154,15 +153,87 @@ static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, bool w } else if (prop.vt != VT_EMPTY) return E_INVALIDARG; + else + { + ft = 0; + ftDefined = false; + } return S_OK; } +/* + +#ifdef _WIN32 +static const wchar_t kDirDelimiter1 = L'\\'; +#endif +static const wchar_t kDirDelimiter2 = L'/'; + +static inline bool IsCharDirLimiter(wchar_t c) +{ + return ( + #ifdef _WIN32 + c == kDirDelimiter1 || + #endif + c == kDirDelimiter2); +} + +static int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex) +{ + CTreeFolder &tf = treeFolders[cur]; + tf.SortIndex = curSortIndex++; + for (int i = 0; i < tf.SubFolders.Size(); i++) + curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex); + tf.SortIndexEnd = curSortIndex; + return curSortIndex; +} + +static int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos) +{ + const CIntVector &subFolders = treeFolders[cur].SubFolders; + int left = 0, right = subFolders.Size(); + insertPos = -1; + for (;;) + { + if (left == right) + { + insertPos = left; + return -1; + } + int mid = (left + right) / 2; + int midFolder = subFolders[mid]; + int compare = CompareFileNames(name, treeFolders[midFolder].Name); + if (compare == 0) + return midFolder; + if (compare < 0) + right = mid; + else + left = mid + 1; + } +} + +static int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name) +{ + int insertPos; + int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos); + if (folderIndex < 0) + { + folderIndex = treeFolders.Size(); + CTreeFolder &newFolder = treeFolders.AddNew(); + newFolder.Parent = cur; + newFolder.Name = name; + treeFolders[cur].SubFolders.Insert(insertPos, folderIndex); + } + // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234; + return folderIndex; +} +*/ + STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) { COM_TRY_BEGIN - const CArchiveDatabaseEx *db = 0; + const CDbEx *db = 0; #ifdef _7Z_VOL if (_volumes.Size() > 1) return E_FAIL; @@ -177,8 +248,35 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt db = &_db; #endif + /* + CMyComPtr<IArchiveGetRawProps> getRawProps; + updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps); + + CUniqBlocks secureBlocks; + secureBlocks.AddUniq(NULL, 0); + + CObjectVector<CTreeFolder> treeFolders; + { + CTreeFolder folder; + folder.Parent = -1; + treeFolders.Add(folder); + } + */ + CObjectVector<CUpdateItem> updateItems; - + + bool need_CTime = (Write_CTime.Def && Write_CTime.Val); + bool need_ATime = (Write_ATime.Def && Write_ATime.Val); + bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def); + if (db) + { + if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); + if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); + if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty(); + } + + UString s; + for (UInt32 i = 0; i < numItems; i++) { Int32 newData, newProps; @@ -194,24 +292,35 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt ui.IsAnti = false; ui.Size = 0; + UString name; + // bool isAltStream = false; if (ui.IndexInArchive != -1) { - if (db == 0 || ui.IndexInArchive >= db->Files.Size()) + if (db == 0 || (unsigned)ui.IndexInArchive >= db->Files.Size()) return E_INVALIDARG; const CFileItem &fi = db->Files[ui.IndexInArchive]; - ui.Name = fi.Name; + if (!ui.NewProps) + { + NCOM::CPropVariant prop; + RINOK(_db.GetPath(ui.IndexInArchive, &prop)); + if (prop.vt == VT_BSTR) + name = prop.bstrVal; + } ui.IsDir = fi.IsDir; ui.Size = fi.Size; + // isAltStream = fi.IsAltStream; ui.IsAnti = db->IsItemAnti(ui.IndexInArchive); - ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime); - ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime); - ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime); + if (!ui.NewProps) + { + ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime); + ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime); + ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime); + } } if (ui.NewProps) { - bool nameIsDefined; bool folderStatusIsDefined; { NCOM::CPropVariant prop; @@ -228,21 +337,35 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt } // we need MTime to sort files. - RINOK(GetTime(updateCallback, i, WriteCTime, kpidCTime, ui.CTime, ui.CTimeDefined)); - RINOK(GetTime(updateCallback, i, WriteATime, kpidATime, ui.ATime, ui.ATimeDefined)); - RINOK(GetTime(updateCallback, i, true, kpidMTime, ui.MTime, ui.MTimeDefined)); + if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined)); + if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined)); + if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined)); + + /* + if (getRawProps) + { + const void *data; + UInt32 dataSize; + UInt32 propType; + + getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType); + if (dataSize != 0 && propType != NPropDataType::kRaw) + return E_FAIL; + ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize); + } + */ { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(i, kpidPath, &prop)); if (prop.vt == VT_EMPTY) - nameIsDefined = false; + { + } else if (prop.vt != VT_BSTR) return E_INVALIDARG; else { - ui.Name = NItemName::MakeLegalName(prop.bstrVal); - nameIsDefined = true; + name = NItemName::MakeLegalName(prop.bstrVal); } } { @@ -270,6 +393,19 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt ui.IsAnti = (prop.boolVal != VARIANT_FALSE); } + /* + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop)); + if (prop.vt == VT_EMPTY) + isAltStream = false; + else if (prop.vt != VT_BOOL) + return E_INVALIDARG; + else + isAltStream = (prop.boolVal != VARIANT_FALSE); + } + */ + if (ui.IsAnti) { ui.AttribDefined = false; @@ -284,6 +420,80 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (!folderStatusIsDefined && ui.AttribDefined) ui.SetDirStatusFromAttrib(); } + else + { + /* + if (_db.SecureIDs.IsEmpty()) + ui.SecureIndex = secureBlocks.AddUniq(NULL, 0); + else + { + int id = _db.SecureIDs[ui.IndexInArchive]; + size_t offs = _db.SecureOffsets[id]; + size_t size = _db.SecureOffsets[id + 1] - offs; + ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size); + } + */ + } + + /* + { + int folderIndex = 0; + if (_useParents) + { + int j; + s.Empty(); + for (j = 0; j < name.Len(); j++) + { + wchar_t c = name[j]; + if (IsCharDirLimiter(c)) + { + folderIndex = AddFolder(treeFolders, folderIndex, s); + s.Empty(); + continue; + } + s += c; + } + if (isAltStream) + { + int colonPos = s.Find(':'); + if (colonPos < 0) + { + // isAltStream = false; + return E_INVALIDARG; + } + UString mainName = s.Left(colonPos); + int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName); + if (treeFolders[newFolderIndex].UpdateItemIndex < 0) + { + for (int j = updateItems.Size() - 1; j >= 0; j--) + { + CUpdateItem &ui2 = updateItems[j]; + if (ui2.ParentFolderIndex == folderIndex + && ui2.Name == mainName) + { + ui2.TreeFolderIndex = newFolderIndex; + treeFolders[newFolderIndex].UpdateItemIndex = j; + } + } + } + folderIndex = newFolderIndex; + s.Delete(0, colonPos + 1); + } + ui.Name = s; + } + else + ui.Name = name; + ui.IsAltStream = isAltStream; + ui.ParentFolderIndex = folderIndex; + ui.TreeFolderIndex = -1; + if (ui.IsDir && !s.IsEmpty()) + { + ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s); + treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size(); + } + } + */ + ui.Name = name; if (ui.NewData) { @@ -298,6 +508,16 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt updateItems.Add(ui); } + /* + FillSortIndex(treeFolders, 0, 0); + for (i = 0; i < (UInt32)updateItems.Size(); i++) + { + CUpdateItem &ui = updateItems[i]; + ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex; + ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd; + } + */ + CCompressionMethodMode methodMode, headerMethod; HRESULT res = SetMainMethod(methodMode, _methods @@ -317,17 +537,17 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt CMyComPtr<ICryptoGetTextPassword2> getPassword2; updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2); + methodMode.PasswordIsDefined = false; + methodMode.Password.Empty(); if (getPassword2) { CMyComBSTR password; Int32 passwordIsDefined; RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password)); methodMode.PasswordIsDefined = IntToBool(passwordIsDefined); - if (methodMode.PasswordIsDefined) + if (methodMode.PasswordIsDefined && (BSTR)password) methodMode.Password = password; } - else - methodMode.PasswordIsDefined = false; bool compressMainHeader = _compressHeaders; // check it @@ -360,9 +580,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt options.MaxFilter = level >= 8; options.HeaderOptions.CompressMainHeader = compressMainHeader; - options.HeaderOptions.WriteCTime = WriteCTime; - options.HeaderOptions.WriteATime = WriteATime; - options.HeaderOptions.WriteMTime = WriteMTime; + /* + options.HeaderOptions.WriteCTime = Write_CTime; + options.HeaderOptions.WriteATime = Write_ATime; + options.HeaderOptions.WriteMTime = Write_MTime; + */ options.NumSolidFiles = _numSolidFiles; options.NumSolidBytes = _numSolidBytes; @@ -371,11 +593,23 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt options.VolumeMode = _volumeMode; COutArchive archive; - CArchiveDatabase newDatabase; + CArchiveDatabaseOut newDatabase; CMyComPtr<ICryptoGetTextPassword> getPassword; updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword); + /* + if (secureBlocks.Sorted.Size() > 1) + { + secureBlocks.GetReverseMap(); + for (int i = 0; i < updateItems.Size(); i++) + { + int &secureIndex = updateItems[i].SecureIndex; + secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex]; + } + } + */ + res = Update( EXTERNAL_CODECS_VARS #ifdef _7Z_VOL @@ -386,6 +620,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt db, #endif updateItems, + // treeFolders, + // secureBlocks, archive, newDatabase, outStream, updateCallback, options #ifndef _NO_CRYPTO , getPassword @@ -409,7 +645,7 @@ static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream if (index == 0) return E_INVALIDARG; srcString.Delete(0, index); - if (srcString[0] == 'S') + if (srcString[0] == 's') { srcString.Delete(0); int index = ParseStringToUInt32(srcString, stream); @@ -428,11 +664,12 @@ void COutHandler::InitProps() _compressHeaders = true; _encryptHeadersSpecified = false; _encryptHeaders = false; + // _useParents = false; - WriteCTime = false; - WriteATime = false; - WriteMTime = true; - + Write_CTime.Init(); + Write_ATime.Init(); + Write_MTime.Init(); + _volumeMode = false; InitSolid(); } @@ -440,24 +677,24 @@ void COutHandler::InitProps() HRESULT COutHandler::SetSolidFromString(const UString &s) { UString s2 = s; - s2.MakeUpper(); - for (int i = 0; i < s2.Length();) + s2.MakeLower_Ascii(); + for (unsigned i = 0; i < s2.Len();) { const wchar_t *start = ((const wchar_t *)s2) + i; const wchar_t *end; UInt64 v = ConvertStringToUInt64(start, &end); if (start == end) { - if (s2[i++] != 'E') + if (s2[i++] != 'e') return E_INVALIDARG; _solidExtension = true; continue; } i += (int)(end - start); - if (i == s2.Length()) + if (i == s2.Len()) return E_INVALIDARG; wchar_t c = s2[i++]; - if (c == 'F') + if (c == 'f') { if (v < 1) v = 1; @@ -468,10 +705,11 @@ HRESULT COutHandler::SetSolidFromString(const UString &s) unsigned numBits; switch (c) { - case 'B': numBits = 0; break; - case 'K': numBits = 10; break; - case 'M': numBits = 20; break; - case 'G': numBits = 30; break; + case 'b': numBits = 0; break; + case 'k': numBits = 10; break; + case 'm': numBits = 20; break; + case 'g': numBits = 30; break; + case 't': numBits = 40; break; default: return E_INVALIDARG; } _numSolidBytes = (v << numBits); @@ -501,14 +739,21 @@ HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value) return S_OK; } +static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest) +{ + RINOK(PROPVARIANT_to_bool(prop, dest.Val)); + dest.Def = true; + return S_OK; +} + HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) { UString name = nameSpec; - name.MakeUpper(); + name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; - if (name[0] == L'S') + if (name[0] == L's') { name.Delete(0); if (name.IsEmpty()) @@ -520,47 +765,52 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val UInt32 number; int index = ParseStringToUInt32(name, number); - UString realName = name.Mid(index); + UString realName = name.Ptr(index); if (index == 0) { - if (name.CompareNoCase(L"RSFX") == 0) return PROPVARIANT_to_bool(value, _removeSfxBlock); - if (name.CompareNoCase(L"HC") == 0) return PROPVARIANT_to_bool(value, _compressHeaders); - if (name.CompareNoCase(L"HCF") == 0) + if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock); + if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders); + // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents); + + if (name.IsEqualTo("hcf")) { bool compressHeadersFull = true; RINOK(PROPVARIANT_to_bool(value, compressHeadersFull)); return compressHeadersFull ? S_OK: E_INVALIDARG; } - if (name.CompareNoCase(L"HE") == 0) + + if (name.IsEqualTo("he")) { RINOK(PROPVARIANT_to_bool(value, _encryptHeaders)); _encryptHeadersSpecified = true; return S_OK; } - if (name.CompareNoCase(L"TC") == 0) return PROPVARIANT_to_bool(value, WriteCTime); - if (name.CompareNoCase(L"TA") == 0) return PROPVARIANT_to_bool(value, WriteATime); - if (name.CompareNoCase(L"TM") == 0) return PROPVARIANT_to_bool(value, WriteMTime); - if (name.CompareNoCase(L"V") == 0) return PROPVARIANT_to_bool(value, _volumeMode); + + if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime); + if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime); + if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime); + + if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode); } return CMultiMethodProps::SetProperty(name, value); } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN _binds.Clear(); InitProps(); - for (int i = 0; i < numProps; i++) + for (UInt32 i = 0; i < numProps; i++) { UString name = names[i]; - name.MakeUpper(); + name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &value = values[i]; - if (name[0] == 'B') + if (name[0] == 'b') { if (value.vt != VT_EMPTY) return E_INVALIDARG; @@ -580,10 +830,10 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v RINOK(SetProperty(name, value)); } - int numEmptyMethods = GetNumEmptyMethods(); + unsigned numEmptyMethods = GetNumEmptyMethods(); if (numEmptyMethods > 0) { - int k; + unsigned k; for (k = 0; k < _binds.Size(); k++) { const CBind &bind = _binds[k]; @@ -597,14 +847,14 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v bind.InCoder -= (UInt32)numEmptyMethods; bind.OutCoder -= (UInt32)numEmptyMethods; } - _methods.Delete(0, numEmptyMethods); + _methods.DeleteFrontal(numEmptyMethods); } AddDefaultMethod(); if (!_filterMethod.MethodName.IsEmpty()) { - for (int k = 0; k < _binds.Size(); k++) + FOR_VECTOR (k, _binds) { CBind &bind = _binds[k]; bind.InCoder++; @@ -613,7 +863,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v _methods.Insert(0, _filterMethod); } - for (int k = 0; k < _binds.Size(); k++) + FOR_VECTOR (k, _binds) { const CBind &bind = _binds[k]; if (bind.InCoder >= (UInt32)_methods.Size() || diff --git a/CPP/7zip/Archive/7z/7zHeader.cpp b/CPP/7zip/Archive/7z/7zHeader.cpp index 5b5f2fb3..acff2fdd 100755..100644 --- a/CPP/7zip/Archive/7z/7zHeader.cpp +++ b/CPP/7zip/Archive/7z/7zHeader.cpp @@ -1,6 +1,7 @@ // 7zHeader.cpp #include "StdAfx.h" + #include "7zHeader.h" namespace NArchive { @@ -11,4 +12,8 @@ Byte kSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; Byte kFinishSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C + 1}; #endif +// We can change signature. So file doesn't contain correct signature. +// struct SignatureInitializer { SignatureInitializer() { kSignature[0]--; } }; +// static SignatureInitializer g_SignatureInitializer; + }} diff --git a/CPP/7zip/Archive/7z/7zHeader.h b/CPP/7zip/Archive/7z/7zHeader.h index 30622b90..d72fdefa 100755..100644 --- a/CPP/7zip/Archive/7z/7zHeader.h +++ b/CPP/7zip/Archive/7z/7zHeader.h @@ -3,12 +3,12 @@ #ifndef __7Z_HEADER_H #define __7Z_HEADER_H -#include "../../../Common/Types.h" +#include "../../../Common/MyTypes.h" namespace NArchive { namespace N7z { -const int kSignatureSize = 6; +const unsigned kSignatureSize = 6; extern Byte kSignature[kSignatureSize]; // #define _7Z_VOL @@ -82,13 +82,17 @@ namespace NID kCTime, kATime, kMTime, - kWinAttributes, + kWinAttrib, kComment, kEncodedHeader, kStartPos, kDummy + + // kNtSecure, + // kParent, + // kIsAux }; } diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp index fd751a74..d84cf0b0 100755..100644 --- a/CPP/7zip/Archive/7z/7zIn.cpp +++ b/CPP/7zip/Archive/7z/7zIn.cpp @@ -20,15 +20,21 @@ #define FORMAT_7Z_RECOVERY #endif +using namespace NWindows; +using namespace NCOM; + namespace NArchive { namespace N7z { -static void BoolVector_Fill_False(CBoolVector &v, int size) +static const UInt32 k_LZMA2 = 0x21; +static const UInt32 k_LZMA = 0x030101; + +static void BoolVector_Fill_False(CBoolVector &v, unsigned size) { - v.Clear(); - v.Reserve(size); - for (int i = 0; i < size; i++) - v.Add(false); + v.ClearAndSetSize(size); + bool *p = &v[0]; + for (unsigned i = 0; i < size; i++) + p[i] = false; } static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index) @@ -40,11 +46,11 @@ static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index) return res; } -bool CFolder::CheckStructure() const +bool CFolder::CheckStructure(unsigned numUnpackSizes) const { - const int kNumCodersMax = sizeof(UInt32) * 8; // don't change it - const int kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax - const int kNumBindsMax = 32; + const unsigned kNumCodersMax = sizeof(UInt32) * 8; // don't change it + const unsigned kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax + const unsigned kNumBindsMax = 32; if (Coders.Size() > kNumCodersMax || BindPairs.Size() > kNumBindsMax) return false; @@ -53,7 +59,7 @@ bool CFolder::CheckStructure() const CBoolVector v; BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size()); - int i; + unsigned i; for (i = 0; i < BindPairs.Size(); i++) if (BoolVector_GetAndSet(v, BindPairs[i].InIndex)) return false; @@ -61,19 +67,19 @@ bool CFolder::CheckStructure() const if (BoolVector_GetAndSet(v, PackStreams[i])) return false; - BoolVector_Fill_False(v, UnpackSizes.Size()); + BoolVector_Fill_False(v, numUnpackSizes); for (i = 0; i < BindPairs.Size(); i++) if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex)) return false; } UInt32 mask[kMaskSize]; - int i; + unsigned i; for (i = 0; i < kMaskSize; i++) mask[i] = 0; { - CIntVector inStreamToCoder, outStreamToCoder; + CUIntVector inStreamToCoder, outStreamToCoder; for (i = 0; i < Coders.Size(); i++) { CNum j; @@ -92,7 +98,7 @@ bool CFolder::CheckStructure() const } for (i = 0; i < kMaskSize; i++) - for (int j = 0; j < kMaskSize; j++) + for (unsigned j = 0; j < kMaskSize; j++) if (((1 << j) & mask[i]) != 0) mask[i] |= mask[j]; @@ -104,43 +110,23 @@ bool CFolder::CheckStructure() const } class CInArchiveException {}; +class CUnsupportedFeatureException: public CInArchiveException {}; static void ThrowException() { throw CInArchiveException(); } static inline void ThrowEndOfData() { ThrowException(); } -static inline void ThrowUnsupported() { ThrowException(); } +static inline void ThrowUnsupported() { throw CUnsupportedFeatureException(); } static inline void ThrowIncorrect() { ThrowException(); } -static inline void ThrowUnsupportedVersion() { ThrowException(); } - -/* -class CInArchiveException -{ -public: - enum CCauseType - { - kUnsupportedVersion = 0, - kUnsupported, - kIncorrect, - kEndOfData - } Cause; - CInArchiveException(CCauseType cause): Cause(cause) {}; -}; - -static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchiveException(c); } -static void ThrowEndOfData() { ThrowException(CInArchiveException::kEndOfData); } -static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupported); } -static void ThrowIncorrect() { ThrowException(CInArchiveException::kIncorrect); } -static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUnsupportedVersion); } -*/ class CStreamSwitch { CInArchive *_archive; bool _needRemove; + bool _needUpdatePos; public: - CStreamSwitch(): _needRemove(false) {} + CStreamSwitch(): _needRemove(false), _needUpdatePos(false) {} ~CStreamSwitch() { Remove(); } void Remove(); - void Set(CInArchive *archive, const Byte *data, size_t size); + void Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos); void Set(CInArchive *archive, const CByteBuffer &byteBuffer); void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector); }; @@ -149,22 +135,25 @@ void CStreamSwitch::Remove() { if (_needRemove) { - _archive->DeleteByteStream(); + if (_archive->_inByteBack->GetRem() != 0) + _archive->ThereIsHeaderError = true; + _archive->DeleteByteStream(_needUpdatePos); _needRemove = false; } } -void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size) +void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos) { Remove(); _archive = archive; _archive->AddByteStream(data, size); _needRemove = true; + _needUpdatePos = needUpdatePos; } void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer) { - Set(archive, byteBuffer, byteBuffer.GetCapacity()); + Set(archive, byteBuffer, byteBuffer.Size(), false); } void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector) @@ -173,13 +162,22 @@ void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *d Byte external = archive->ReadByte(); if (external != 0) { - int dataIndex = (int)archive->ReadNum(); - if (dataIndex < 0 || dataIndex >= dataVector->Size()) + CNum dataIndex = archive->ReadNum(); + if (dataIndex >= dataVector->Size()) ThrowIncorrect(); Set(archive, (*dataVector)[dataIndex]); } } +void CInArchive::AddByteStream(const Byte *buf, size_t size) +{ + if (_numInByteBufs == kNumBufLevelsMax) + ThrowIncorrect(); + _inByteBack = &_inByteVector[_numInByteBufs++]; + _inByteBack->Init(buf, size); +} + + Byte CInByte2::ReadByte() { if (_pos >= _size) @@ -191,8 +189,8 @@ void CInByte2::ReadBytes(Byte *data, size_t size) { if (size > _size - _pos) ThrowEndOfData(); - for (size_t i = 0; i < size; i++) - data[i] = _buffer[_pos++]; + memcpy(data, _buffer + _pos, size); + _pos += size; } void CInByte2::SkipData(UInt64 size) @@ -207,31 +205,75 @@ void CInByte2::SkipData() SkipData(ReadNumber()); } -UInt64 CInByte2::ReadNumber() +static UInt64 ReadNumberSpec(const Byte *p, size_t size, size_t &processed) { - if (_pos >= _size) - ThrowEndOfData(); - Byte firstByte = _buffer[_pos++]; - Byte mask = 0x80; - UInt64 value = 0; - for (int i = 0; i < 8; i++) + if (size == 0) + { + processed = 0; + return 0; + } + Byte firstByte = *p++; + size--; + if ((firstByte & 0x80) == 0) + { + processed = 1; + return firstByte; + } + Byte mask = 0x40; + if (size == 0) + { + processed = 0; + return 0; + } + UInt64 value = (UInt64)*p; + p++; + size--; + for (unsigned i = 1; i < 8; i++) { if ((firstByte & mask) == 0) { UInt64 highPart = firstByte & (mask - 1); value += (highPart << (i * 8)); + processed = i + 1; return value; } - if (_pos >= _size) - ThrowEndOfData(); - value |= ((UInt64)_buffer[_pos++] << (8 * i)); + if (size == 0) + { + processed = 0; + return 0; + } + value |= ((UInt64)*p << (i * 8)); + p++; + size--; mask >>= 1; } + processed = 9; return value; } +UInt64 CInByte2::ReadNumber() +{ + size_t processed; + UInt64 res = ReadNumberSpec(_buffer + _pos, _size - _pos, processed); + if (processed == 0) + ThrowEndOfData(); + _pos += processed; + return res; +} + CNum CInByte2::ReadNum() { + /* + if (_pos < _size) + { + Byte val = _buffer[_pos]; + if ((unsigned)val < 0x80) + { + _pos++; + return (unsigned)val; + } + } + */ UInt64 value = ReadNumber(); if (value > kNumMax) ThrowUnsupported(); @@ -256,48 +298,21 @@ UInt64 CInByte2::ReadUInt64() return res; } -void CInByte2::ReadString(UString &s) -{ - const Byte *buf = _buffer + _pos; - size_t rem = (_size - _pos) / 2 * 2; - { - size_t i; - for (i = 0; i < rem; i += 2) - if (buf[i] == 0 && buf[i + 1] == 0) - break; - if (i == rem) - ThrowEndOfData(); - rem = i; - } - int len = (int)(rem / 2); - if (len < 0 || (size_t)len * 2 != rem) - ThrowUnsupported(); - wchar_t *p = s.GetBuffer(len); - int i; - for (i = 0; i < len; i++, buf += 2) - p[i] = (wchar_t)Get16(buf); - s.ReleaseBuffer(len); - _pos += rem + 2; -} +#define CHECK_SIGNATURE if (p[0] != '7' || p[1] != 'z' || p[2] != 0xBC || p[3] != 0xAF || p[4] != 0x27 || p[5] != 0x1C) return false; static inline bool TestSignature(const Byte *p) { - for (int i = 0; i < kSignatureSize; i++) - if (p[i] != kSignature[i]) - return false; - return CrcCalc(p + 12, 20) == GetUi32(p + 8); + CHECK_SIGNATURE + return CrcCalc(p + 12, 20) == Get32(p + 8); } #ifdef FORMAT_7Z_RECOVERY static inline bool TestSignature2(const Byte *p) { - int i; - for (i = 0; i < kSignatureSize; i++) - if (p[i] != kSignature[i]) - return false; - if (CrcCalc(p + 12, 20) == GetUi32(p + 8)) + CHECK_SIGNATURE; + if (CrcCalc(p + 12, 20) == Get32(p + 8)) return true; - for (i = 8; i < kHeaderSize; i++) + for (unsigned i = 8; i < kHeaderSize; i++) if (p[i] != 0) return false; return (p[6] != 0 || p[7] != 0); @@ -312,39 +327,52 @@ HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *search if (TestSignature2(_header)) return S_OK; + if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) + return S_FALSE; - CByteBuffer byteBuffer; - const UInt32 kBufferSize = (1 << 16); - byteBuffer.SetCapacity(kBufferSize); - Byte *buffer = byteBuffer; - memcpy(buffer, _header, kHeaderSize); - UInt64 curTestPos = _arhiveBeginStreamPosition; + const UInt32 kBufSize = 1 << 15; + CByteArr buf(kBufSize); + memcpy(buf, _header, kHeaderSize); + UInt64 offset = 0; + for (;;) { - if (searchHeaderSizeLimit != NULL) - if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit) - break; - UInt32 processedSize; - RINOK(stream->Read(buffer + kHeaderSize, kBufferSize - kHeaderSize, &processedSize)); - if (processedSize == 0) + UInt32 readSize = kBufSize - kHeaderSize; + { + UInt64 rem = *searchHeaderSizeLimit - offset; + if (readSize > rem) + readSize = (UInt32)rem; + if (readSize == 0) + return S_FALSE; + } + UInt32 processed = 0; + RINOK(stream->Read(buf + kHeaderSize, readSize, &processed)); + if (processed == 0) return S_FALSE; - for (UInt32 pos = 1; pos <= processedSize; pos++) + for (UInt32 pos = 0;;) { - for (; buffer[pos] != '7' && pos <= processedSize; pos++); - if (pos > processedSize) + const Byte *p = buf + pos + 1; + const Byte *lim = buf + processed; + for (; p <= lim; p += 4) + { + if (p[0] == '7') break; + if (p[1] == '7') { p += 1; break; } + if (p[2] == '7') { p += 2; break; } + if (p[3] == '7') { p += 3; break; } + }; + if (p > lim) break; - if (TestSignature(buffer + pos)) + pos = (UInt32)(p - buf); + if (TestSignature(p)) { - memcpy(_header, buffer + pos, kHeaderSize); - curTestPos += pos; - _arhiveBeginStreamPosition = curTestPos; - return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL); + memcpy(_header, p, kHeaderSize); + _arhiveBeginStreamPosition += offset + pos; + return stream->Seek(_arhiveBeginStreamPosition + kHeaderSize, STREAM_SEEK_SET, NULL); } } - curTestPos += processedSize; - memmove(buffer, buffer + processedSize, kHeaderSize); + offset += processed; + memmove(buf, buf + processed, kHeaderSize); } - return S_FALSE; } // S_FALSE means that file is not archive @@ -362,7 +390,9 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) void CInArchive::Close() { + _numInByteBufs = 0; _stream.Release(); + ThereIsHeaderError = false; } void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */) @@ -375,30 +405,32 @@ void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */) } } -void CInArchive::GetNextFolderItem(CFolder &folder) +// CFolder &folder can be non empty. So we must set all fields + +void CInByte2::ParseFolder(CFolder &folder) { CNum numCoders = ReadNum(); - folder.Coders.Clear(); - folder.Coders.Reserve((int)numCoders); + folder.Coders.SetSize(numCoders); + CNum numInStreams = 0; CNum numOutStreams = 0; CNum i; for (i = 0; i < numCoders; i++) { - folder.Coders.Add(CCoderInfo()); - CCoderInfo &coder = folder.Coders.Back(); - + CCoderInfo &coder = folder.Coders[i]; { Byte mainByte = ReadByte(); - int idSize = (mainByte & 0xF); - Byte longID[15]; - ReadBytes(longID, idSize); - if (idSize > 8) + if ((mainByte & 0xC0) != 0) ThrowUnsupported(); + unsigned idSize = (mainByte & 0xF); + if (idSize > 8 || idSize > GetRem()) + ThrowUnsupported(); + const Byte *longID = GetPtr(); UInt64 id = 0; - for (int j = 0; j < idSize; j++) - id |= (UInt64)longID[idSize - 1 - j] << (8 * j); + for (unsigned j = 0; j < idSize; j++) + id = ((id << 8) | longID[j]); + SkipDataNoCheck(idSize); coder.MethodID = id; if ((mainByte & 0x10) != 0) @@ -414,53 +446,117 @@ void CInArchive::GetNextFolderItem(CFolder &folder) if ((mainByte & 0x20) != 0) { CNum propsSize = ReadNum(); - coder.Props.SetCapacity((size_t)propsSize); + coder.Props.Alloc((size_t)propsSize); ReadBytes((Byte *)coder.Props, (size_t)propsSize); } - if ((mainByte & 0x80) != 0) - ThrowUnsupported(); + else + coder.Props.Free(); } numInStreams += coder.NumInStreams; numOutStreams += coder.NumOutStreams; } CNum numBindPairs = numOutStreams - 1; - folder.BindPairs.Clear(); - folder.BindPairs.Reserve(numBindPairs); + folder.BindPairs.SetSize(numBindPairs); for (i = 0; i < numBindPairs; i++) { - CBindPair bp; + CBindPair &bp = folder.BindPairs[i]; bp.InIndex = ReadNum(); bp.OutIndex = ReadNum(); - folder.BindPairs.Add(bp); } if (numInStreams < numBindPairs) ThrowUnsupported(); CNum numPackStreams = numInStreams - numBindPairs; - folder.PackStreams.Reserve(numPackStreams); + folder.PackStreams.SetSize(numPackStreams); if (numPackStreams == 1) { for (i = 0; i < numInStreams; i++) if (folder.FindBindPairForInStream(i) < 0) { - folder.PackStreams.Add(i); + folder.PackStreams[0] = i; break; } - if (folder.PackStreams.Size() != 1) + if (i == numInStreams) ThrowUnsupported(); } else for (i = 0; i < numPackStreams; i++) - folder.PackStreams.Add(ReadNum()); + folder.PackStreams[i] = ReadNum(); +} + +void CFolders::ParseFolderInfo(unsigned folderIndex, CFolder &folder) const +{ + size_t startPos = FoCodersDataOffset[folderIndex]; + CInByte2 inByte; + inByte.Init(CodersData + startPos, FoCodersDataOffset[folderIndex + 1] - startPos); + inByte.ParseFolder(folder); + if (inByte.GetRem() != 0) + throw 20120424; } -void CInArchive::WaitAttribute(UInt64 attribute) + +HRESULT CDatabase::GetPath(unsigned index, PROPVARIANT *path) const +{ + PropVariant_Clear(path); + if (!NameOffsets || !NamesBuf) + return S_OK; + + unsigned cur = index; + unsigned size = 0; + + // for (int i = 0;; i++) + { + size_t len = NameOffsets[cur + 1] - NameOffsets[cur]; + size += (unsigned)len; + if (/* i > 256 || */ len > (1 << 12) || size > (1 << 14)) + return PropVarEm_Set_Str(path, "[TOO-LONG]"); + /* + cur = Files[cur].Parent; + if (cur < 0) + break; + */ + } + size--; + + RINOK(PropVarEm_Alloc_Bstr(path, size)); + wchar_t *s = path->bstrVal; + s += size; + *s = 0; + cur = index; + + for (;;) + { + unsigned len = (unsigned)(NameOffsets[cur + 1] - NameOffsets[cur] - 1); + const Byte *p = (const Byte *)NamesBuf + (NameOffsets[cur + 1] * 2) - 2; + do + { + p -= 2; + --s; + wchar_t c = Get16(p); + if (c == '/') + c = WCHAR_PATH_SEPARATOR; + *s = c; + } + while (--len); + /* + const CFileItem &file = Files[cur]; + cur = file.Parent; + if (cur < 0) + */ + return S_OK; + /* + *(--s) = (file.IsAltStream ? ':' : WCHAR_PATH_SEPARATOR); + */ + } +} + +void CInArchive::WaitId(UInt64 id) { for (;;) { UInt64 type = ReadID(); - if (type == attribute) + if (type == id) return; if (type == NID::kEnd) ThrowIncorrect(); @@ -468,90 +564,209 @@ void CInArchive::WaitAttribute(UInt64 attribute) } } -void CInArchive::ReadHashDigests(int numItems, - CBoolVector &digestsDefined, - CRecordVector<UInt32> &digests) +void CInArchive::ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs) { - ReadBoolVector2(numItems, digestsDefined); - digests.Clear(); - digests.Reserve(numItems); - for (int i = 0; i < numItems; i++) + ReadBoolVector2(numItems, crcs.Defs); + crcs.Vals.ClearAndSetSize(numItems); + UInt32 *p = &crcs.Vals[0]; + const bool *defs = &crcs.Defs[0]; + for (unsigned i = 0; i < numItems; i++) { UInt32 crc = 0; - if (digestsDefined[i]) + if (defs[i]) crc = ReadUInt32(); - digests.Add(crc); + p[i] = crc; } } -void CInArchive::ReadPackInfo( - UInt64 &dataOffset, - CRecordVector<UInt64> &packSizes, - CBoolVector &packCRCsDefined, - CRecordVector<UInt32> &packCRCs) +void CInArchive::ReadPackInfo(CFolders &f) { - dataOffset = ReadNumber(); CNum numPackStreams = ReadNum(); - - WaitAttribute(NID::kSize); - packSizes.Clear(); - packSizes.Reserve(numPackStreams); + + WaitId(NID::kSize); + f.PackPositions.Alloc(numPackStreams + 1); + f.NumPackStreams = numPackStreams; + UInt64 sum = 0; for (CNum i = 0; i < numPackStreams; i++) - packSizes.Add(ReadNumber()); + { + f.PackPositions[i] = sum; + UInt64 packSize = ReadNumber(); + sum += packSize; + if (sum < packSize) + ThrowIncorrect(); + } + f.PackPositions[numPackStreams] = sum; UInt64 type; for (;;) { type = ReadID(); if (type == NID::kEnd) - break; + return; if (type == NID::kCRC) { - ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs); + CUInt32DefVector PackCRCs; + ReadHashDigests(numPackStreams, PackCRCs); continue; } SkipData(); } - if (packCRCsDefined.IsEmpty()) - { - BoolVector_Fill_False(packCRCsDefined, numPackStreams); - packCRCs.Reserve(numPackStreams); - packCRCs.Clear(); - for (CNum i = 0; i < numPackStreams; i++) - packCRCs.Add(0); - } } void CInArchive::ReadUnpackInfo( const CObjectVector<CByteBuffer> *dataVector, - CObjectVector<CFolder> &folders) + CFolders &folders) { - WaitAttribute(NID::kFolder); + WaitId(NID::kFolder); CNum numFolders = ReadNum(); + CNum numCodersOutStreams = 0; { CStreamSwitch streamSwitch; streamSwitch.Set(this, dataVector); - folders.Clear(); - folders.Reserve(numFolders); - for (CNum i = 0; i < numFolders; i++) + const Byte *startBufPtr = _inByteBack->GetPtr(); + folders.NumFolders = numFolders; + + folders.FoStartPackStreamIndex.Alloc(numFolders + 1); + folders.FoToMainUnpackSizeIndex.Alloc(numFolders); + folders.FoCodersDataOffset.Alloc(numFolders + 1); + folders.FoToCoderUnpackSizes.Alloc(numFolders + 1); + + CRecordVector<bool> InStreamUsed; + CRecordVector<bool> OutStreamUsed; + + CNum packStreamIndex = 0; + CNum fo; + CInByte2 *inByte = _inByteBack; + for (fo = 0; fo < numFolders; fo++) { - folders.Add(CFolder()); - GetNextFolderItem(folders.Back()); + UInt32 numOutStreams = 0; + UInt32 indexOfMainStream = 0; + UInt32 numPackStreams = 0; + folders.FoCodersDataOffset[fo] = _inByteBack->GetPtr() - startBufPtr; + + numOutStreams = 0; + CNum numInStreams = 0; + CNum numCoders = inByte->ReadNum(); + for (CNum ci = 0; ci < numCoders; ci++) + { + Byte mainByte = inByte->ReadByte(); + if ((mainByte & 0xC0) != 0) + ThrowUnsupported(); + unsigned idSize = (mainByte & 0xF); + if (idSize > 8) + ThrowUnsupported(); + if (idSize > inByte->GetRem()) + ThrowEndOfData(); + const Byte *longID = inByte->GetPtr(); + UInt64 id = 0; + for (unsigned j = 0; j < idSize; j++) + id = ((id << 8) | longID[j]); + inByte->SkipDataNoCheck(idSize); + if (folders.ParsedMethods.IDs.Size() < 128) + folders.ParsedMethods.IDs.AddToUniqueSorted(id); + CNum coderInStreams = 1; + CNum coderOutStreams = 1; + if ((mainByte & 0x10) != 0) + { + coderInStreams = inByte->ReadNum(); + coderOutStreams = inByte->ReadNum(); + } + numInStreams += coderInStreams; + if (numInStreams < coderInStreams) + ThrowUnsupported(); + numOutStreams += coderOutStreams; + if (numOutStreams < coderOutStreams) + ThrowUnsupported(); + if ((mainByte & 0x20) != 0) + { + CNum propsSize = inByte->ReadNum(); + if (propsSize > inByte->GetRem()) + ThrowEndOfData(); + if (id == k_LZMA2 && propsSize == 1) + { + Byte v = *_inByteBack->GetPtr(); + if (folders.ParsedMethods.Lzma2Prop < v) + folders.ParsedMethods.Lzma2Prop = v; + } + else if (id == k_LZMA && propsSize == 5) + { + UInt32 dicSize = GetUi32(_inByteBack->GetPtr() + 1); + if (folders.ParsedMethods.LzmaDic < dicSize) + folders.ParsedMethods.LzmaDic = dicSize; + } + inByte->SkipDataNoCheck((size_t)propsSize); + } + } + + if (numOutStreams == 1 && numInStreams == 1) + { + indexOfMainStream = 0; + numPackStreams = 1; + } + else + { + UInt32 i; + if (numOutStreams == 0) + ThrowUnsupported(); + CNum numBindPairs = numOutStreams - 1; + if (numInStreams < numBindPairs) + ThrowUnsupported(); + if (numInStreams >= 256 || numOutStreams >= 256) + ThrowUnsupported(); + + InStreamUsed.ClearAndSetSize(numInStreams); + for (i = 0; i < numInStreams; i++) + InStreamUsed[i] = false; + + OutStreamUsed.ClearAndSetSize(numOutStreams); + for (i = 0; i < numOutStreams; i++) + OutStreamUsed[i] = false; + + for (i = 0; i < numBindPairs; i++) + { + CNum index = ReadNum(); + if (index >= numInStreams || InStreamUsed[index]) + ThrowUnsupported(); + InStreamUsed[index] = true; + index = ReadNum(); + if (index >= numOutStreams || OutStreamUsed[index]) + ThrowUnsupported(); + OutStreamUsed[index] = true; + } + + numPackStreams = numInStreams - numBindPairs; + + if (numPackStreams != 1) + for (i = 0; i < numPackStreams; i++) + inByte->ReadNum(); // PackStreams + + for (i = 0; i < numOutStreams; i++) + if (!OutStreamUsed[i]) + { + indexOfMainStream = i; + break; + } + if (i == numOutStreams) + ThrowUnsupported(); + } + folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams; + numCodersOutStreams += numOutStreams; + folders.FoStartPackStreamIndex[fo] = packStreamIndex; + packStreamIndex += numPackStreams; + folders.FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; } + size_t dataSize = _inByteBack->GetPtr() - startBufPtr; + folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams; + folders.FoStartPackStreamIndex[fo] = packStreamIndex; + folders.FoCodersDataOffset[fo] = _inByteBack->GetPtr() - startBufPtr; + folders.CodersData.CopyFrom(startBufPtr, dataSize); } - WaitAttribute(NID::kCodersUnpackSize); - - CNum i; - for (i = 0; i < numFolders; i++) - { - CFolder &folder = folders[i]; - CNum numOutStreams = folder.GetNumOutStreams(); - folder.UnpackSizes.Reserve(numOutStreams); - for (CNum j = 0; j < numOutStreams; j++) - folder.UnpackSizes.Add(ReadNumber()); - } + WaitId(NID::kCodersUnpackSize); + folders.CoderUnpackSizes.Alloc(numCodersOutStreams); + for (CNum i = 0; i < numCodersOutStreams; i++) + folders.CoderUnpackSizes[i] = ReadNumber(); for (;;) { @@ -560,15 +775,7 @@ void CInArchive::ReadUnpackInfo( return; if (type == NID::kCRC) { - CBoolVector crcsDefined; - CRecordVector<UInt32> crcs; - ReadHashDigests(numFolders, crcsDefined, crcs); - for (i = 0; i < numFolders; i++) - { - CFolder &folder = folders[i]; - folder.UnpackCRCDefined = crcsDefined[i]; - folder.UnpackCRC = crcs[i]; - } + ReadHashDigests(numFolders, folders.FolderCRCs); continue; } SkipData(); @@ -576,170 +783,217 @@ void CInArchive::ReadUnpackInfo( } void CInArchive::ReadSubStreamsInfo( - const CObjectVector<CFolder> &folders, - CRecordVector<CNum> &numUnpackStreamsInFolders, + CFolders &folders, CRecordVector<UInt64> &unpackSizes, - CBoolVector &digestsDefined, - CRecordVector<UInt32> &digests) + CUInt32DefVector &digests) { - numUnpackStreamsInFolders.Clear(); - numUnpackStreamsInFolders.Reserve(folders.Size()); + folders.NumUnpackStreamsVector.Alloc(folders.NumFolders); + CNum i; + for (i = 0; i < folders.NumFolders; i++) + folders.NumUnpackStreamsVector[i] = 1; + UInt64 type; + for (;;) { type = ReadID(); if (type == NID::kNumUnpackStream) { - for (int i = 0; i < folders.Size(); i++) - numUnpackStreamsInFolders.Add(ReadNum()); + for (i = 0; i < folders.NumFolders; i++) + folders.NumUnpackStreamsVector[i] = ReadNum(); continue; } - if (type == NID::kCRC || type == NID::kSize) - break; - if (type == NID::kEnd) + if (type == NID::kCRC || type == NID::kSize || type == NID::kEnd) break; SkipData(); } - if (numUnpackStreamsInFolders.IsEmpty()) - for (int i = 0; i < folders.Size(); i++) - numUnpackStreamsInFolders.Add(1); - - int i; - for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) + if (type == NID::kSize) { - // v3.13 incorrectly worked with empty folders - // v4.07: we check that folder is empty - CNum numSubstreams = numUnpackStreamsInFolders[i]; - if (numSubstreams == 0) - continue; - UInt64 sum = 0; - for (CNum j = 1; j < numSubstreams; j++) - if (type == NID::kSize) + for (i = 0; i < folders.NumFolders; i++) + { + // v3.13 incorrectly worked with empty folders + // v4.07: we check that folder is empty + CNum numSubstreams = folders.NumUnpackStreamsVector[i]; + if (numSubstreams == 0) + continue; + UInt64 sum = 0; + for (CNum j = 1; j < numSubstreams; j++) { UInt64 size = ReadNumber(); unpackSizes.Add(size); sum += size; + if (sum < size) + ThrowIncorrect(); } - unpackSizes.Add(folders[i].GetUnpackSize() - sum); - } - if (type == NID::kSize) + UInt64 folderUnpackSize = folders.GetFolderUnpackSize(i); + if (folderUnpackSize < sum) + ThrowIncorrect(); + unpackSizes.Add(folderUnpackSize - sum); + } type = ReadID(); + } + else + { + for (i = 0; i < folders.NumFolders; i++) + { + /* v9.26 - v9.29 incorrectly worked: + if (folders.NumUnpackStreamsVector[i] == 0), it threw error */ + CNum val = folders.NumUnpackStreamsVector[i]; + if (val > 1) + ThrowIncorrect(); + if (val == 1) + unpackSizes.Add(folders.GetFolderUnpackSize(i)); + } + } - int numDigests = 0; - int numDigestsTotal = 0; - for (i = 0; i < folders.Size(); i++) + unsigned numDigests = 0; + for (i = 0; i < folders.NumFolders; i++) { - CNum numSubstreams = numUnpackStreamsInFolders[i]; - if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) + CNum numSubstreams = folders.NumUnpackStreamsVector[i]; + if (numSubstreams != 1 || !folders.FolderCRCs.ValidAndDefined(i)) numDigests += numSubstreams; - numDigestsTotal += numSubstreams; } for (;;) { + if (type == NID::kEnd) + break; if (type == NID::kCRC) { - CBoolVector digestsDefined2; - CRecordVector<UInt32> digests2; - ReadHashDigests(numDigests, digestsDefined2, digests2); - int digestIndex = 0; - for (i = 0; i < folders.Size(); i++) + // CUInt32DefVector digests2; + // ReadHashDigests(numDigests, digests2); + CBoolVector digests2; + ReadBoolVector2(numDigests, digests2); + + digests.ClearAndSetSize(unpackSizes.Size()); + + unsigned k = 0; + unsigned k2 = 0; + + for (i = 0; i < folders.NumFolders; i++) { - CNum numSubstreams = numUnpackStreamsInFolders[i]; - const CFolder &folder = folders[i]; - if (numSubstreams == 1 && folder.UnpackCRCDefined) + CNum numSubstreams = folders.NumUnpackStreamsVector[i]; + if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i)) { - digestsDefined.Add(true); - digests.Add(folder.UnpackCRC); + digests.Defs[k] = true; + digests.Vals[k] = folders.FolderCRCs.Vals[i]; + k++; + } + else for (CNum j = 0; j < numSubstreams; j++) + { + bool defined = digests2[k2++]; + digests.Defs[k] = defined; + UInt32 crc = 0; + if (defined) + crc = ReadUInt32(); + digests.Vals[k] = crc; + k++; } - else - for (CNum j = 0; j < numSubstreams; j++, digestIndex++) - { - digestsDefined.Add(digestsDefined2[digestIndex]); - digests.Add(digests2[digestIndex]); - } } + // if (k != unpackSizes.Size()) throw 1234567; } - else if (type == NID::kEnd) + else + SkipData(); + + type = ReadID(); + } + + if (digests.Defs.Size() != unpackSizes.Size()) + { + digests.ClearAndSetSize(unpackSizes.Size()); + unsigned k = 0; + for (i = 0; i < folders.NumFolders; i++) { - if (digestsDefined.IsEmpty()) + CNum numSubstreams = folders.NumUnpackStreamsVector[i]; + if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i)) { - BoolVector_Fill_False(digestsDefined, numDigestsTotal); - digests.Clear(); - for (int i = 0; i < numDigestsTotal; i++) - digests.Add(0); + digests.Defs[k] = true; + digests.Vals[k] = folders.FolderCRCs.Vals[i]; + k++; + } + else for (CNum j = 0; j < numSubstreams; j++) + { + digests.Defs[k] = false; + digests.Vals[k] = 0; + k++; } - return; } - else - SkipData(); - type = ReadID(); } } void CInArchive::ReadStreamsInfo( const CObjectVector<CByteBuffer> *dataVector, UInt64 &dataOffset, - CRecordVector<UInt64> &packSizes, - CBoolVector &packCRCsDefined, - CRecordVector<UInt32> &packCRCs, - CObjectVector<CFolder> &folders, - CRecordVector<CNum> &numUnpackStreamsInFolders, + CFolders &folders, CRecordVector<UInt64> &unpackSizes, - CBoolVector &digestsDefined, - CRecordVector<UInt32> &digests) + CUInt32DefVector &digests) { - for (;;) + UInt64 type = ReadID(); + + if (type == NID::kPackInfo) { - UInt64 type = ReadID(); - if (type > ((UInt32)1 << 30)) - ThrowIncorrect(); - switch((UInt32)type) + dataOffset = ReadNumber(); + ReadPackInfo(folders); + type = ReadID(); + } + + if (type == NID::kUnpackInfo) + { + ReadUnpackInfo(dataVector, folders); + type = ReadID(); + } + + if (folders.NumFolders != 0 && !folders.PackPositions) + { + // if there are folders, we need PackPositions also + folders.PackPositions.Alloc(1); + folders.PackPositions[0] = 0; + } + + if (type == NID::kSubStreamsInfo) + { + ReadSubStreamsInfo(folders, unpackSizes, digests); + type = ReadID(); + } + else + { + folders.NumUnpackStreamsVector.Alloc(folders.NumFolders); + /* If digests.Defs.Size() == 0, it means that there are no crcs. + So we don't need to fill digests with values. */ + // digests.Vals.ClearAndSetSize(folders.NumFolders); + // BoolVector_Fill_False(digests.Defs, folders.NumFolders); + for (CNum i = 0; i < folders.NumFolders; i++) { - case NID::kEnd: - return; - case NID::kPackInfo: - { - ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs); - break; - } - case NID::kUnpackInfo: - { - ReadUnpackInfo(dataVector, folders); - break; - } - case NID::kSubStreamsInfo: - { - ReadSubStreamsInfo(folders, numUnpackStreamsInFolders, - unpackSizes, digestsDefined, digests); - break; - } - default: - ThrowIncorrect(); + folders.NumUnpackStreamsVector[i] = 1; + unpackSizes.Add(folders.GetFolderUnpackSize(i)); + // digests.Vals[i] = 0; } } + + if (type != NID::kEnd) + ThrowIncorrect(); } -void CInArchive::ReadBoolVector(int numItems, CBoolVector &v) +void CInArchive::ReadBoolVector(unsigned numItems, CBoolVector &v) { - v.Clear(); - v.Reserve(numItems); + v.ClearAndSetSize(numItems); Byte b = 0; Byte mask = 0; - for (int i = 0; i < numItems; i++) + bool *p = &v[0]; + for (unsigned i = 0; i < numItems; i++) { if (mask == 0) { b = ReadByte(); mask = 0x80; } - v.Add((b & mask) != 0); + p[i] = ((b & mask) != 0); mask >>= 1; } } -void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v) +void CInArchive::ReadBoolVector2(unsigned numItems, CBoolVector &v) { Byte allAreDefined = ReadByte(); if (allAreDefined == 0) @@ -747,27 +1001,30 @@ void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v) ReadBoolVector(numItems, v); return; } - v.Clear(); - v.Reserve(numItems); - for (int i = 0; i < numItems; i++) - v.Add(true); + v.ClearAndSetSize(numItems); + bool *p = &v[0]; + for (unsigned i = 0; i < numItems; i++) + p[i] = true; } void CInArchive::ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector, - CUInt64DefVector &v, int numFiles) + CUInt64DefVector &v, unsigned numItems) { - ReadBoolVector2(numFiles, v.Defined); + ReadBoolVector2(numItems, v.Defs); CStreamSwitch streamSwitch; streamSwitch.Set(this, &dataVector); - v.Values.Reserve(numFiles); + + v.Vals.ClearAndSetSize(numItems); + UInt64 *p = &v.Vals[0]; + const bool *defs = &v.Defs[0]; - for (int i = 0; i < numFiles; i++) + for (unsigned i = 0; i < numItems; i++) { UInt64 t = 0; - if (v.Defined[i]) + if (defs[i]) t = ReadUInt64(); - v.Values.Add(t); + p[i] = t; } } @@ -775,35 +1032,19 @@ HRESULT CInArchive::ReadAndDecodePackedStreams( DECL_EXTERNAL_CODECS_LOC_VARS UInt64 baseOffset, UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector - #ifndef _NO_CRYPTO - , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined - #endif + _7Z_DECODER_CRYPRO_VARS_DECL ) { - CRecordVector<UInt64> packSizes; - CBoolVector packCRCsDefined; - CRecordVector<UInt32> packCRCs; - CObjectVector<CFolder> folders; - - CRecordVector<CNum> numUnpackStreamsInFolders; + CFolders folders; CRecordVector<UInt64> unpackSizes; - CBoolVector digestsDefined; - CRecordVector<UInt32> digests; + CUInt32DefVector digests; ReadStreamsInfo(NULL, dataOffset, - packSizes, - packCRCsDefined, - packCRCs, folders, - numUnpackStreamsInFolders, unpackSizes, - digestsDefined, digests); - // db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader; - - CNum packIndex = 0; CDecoder decoder( #ifdef _ST_MODE false @@ -811,17 +1052,15 @@ HRESULT CInArchive::ReadAndDecodePackedStreams( true #endif ); - UInt64 dataStartPos = baseOffset + dataOffset; - for (int i = 0; i < folders.Size(); i++) + + for (CNum i = 0; i < folders.NumFolders; i++) { - const CFolder &folder = folders[i]; - dataVector.Add(CByteBuffer()); - CByteBuffer &data = dataVector.Back(); - UInt64 unpackSize64 = folder.GetUnpackSize(); + CByteBuffer &data = dataVector.AddNew(); + UInt64 unpackSize64 = folders.GetFolderUnpackSize(i); size_t unpackSize = (size_t)unpackSize64; if (unpackSize != unpackSize64) ThrowUnsupported(); - data.SetCapacity(unpackSize); + data.Alloc(unpackSize); CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; @@ -829,43 +1068,35 @@ HRESULT CInArchive::ReadAndDecodePackedStreams( HRESULT result = decoder.Decode( EXTERNAL_CODECS_LOC_VARS - _stream, dataStartPos, - &packSizes[packIndex], folder, outStream, NULL - #ifndef _NO_CRYPTO - , getTextPassword, passwordIsDefined - #endif + _stream, baseOffset + dataOffset, + folders, i, + outStream, NULL + _7Z_DECODER_CRYPRO_VARS #if !defined(_7ZIP_ST) && !defined(_SFX) , false, 1 #endif ); RINOK(result); - if (folder.UnpackCRCDefined) - if (CrcCalc(data, unpackSize) != folder.UnpackCRC) + if (folders.FolderCRCs.ValidAndDefined(i)) + if (CrcCalc(data, unpackSize) != folders.FolderCRCs.Vals[i]) ThrowIncorrect(); - for (int j = 0; j < folder.PackStreams.Size(); j++) - { - UInt64 packSize = packSizes[packIndex++]; - dataStartPos += packSize; - HeadersSize += packSize; - } } + HeadersSize += folders.PackPositions[folders.NumPackStreams]; return S_OK; } HRESULT CInArchive::ReadHeader( DECL_EXTERNAL_CODECS_LOC_VARS - CArchiveDatabaseEx &db - #ifndef _NO_CRYPTO - , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined - #endif + CDbEx &db + _7Z_DECODER_CRYPRO_VARS_DECL ) { UInt64 type = ReadID(); if (type == NID::kArchiveProperties) { - ReadArchiveProperties(db.ArchiveInfo); + ReadArchiveProperties(db.ArcInfo); type = ReadID(); } @@ -875,70 +1106,53 @@ HRESULT CInArchive::ReadHeader( { HRESULT result = ReadAndDecodePackedStreams( EXTERNAL_CODECS_LOC_VARS - db.ArchiveInfo.StartPositionAfterHeader, - db.ArchiveInfo.DataStartPosition2, + db.ArcInfo.StartPositionAfterHeader, + db.ArcInfo.DataStartPosition2, dataVector - #ifndef _NO_CRYPTO - , getTextPassword, passwordIsDefined - #endif + _7Z_DECODER_CRYPRO_VARS ); RINOK(result); - db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader; + db.ArcInfo.DataStartPosition2 += db.ArcInfo.StartPositionAfterHeader; type = ReadID(); } CRecordVector<UInt64> unpackSizes; - CBoolVector digestsDefined; - CRecordVector<UInt32> digests; + CUInt32DefVector digests; if (type == NID::kMainStreamsInfo) { ReadStreamsInfo(&dataVector, - db.ArchiveInfo.DataStartPosition, - db.PackSizes, - db.PackCRCsDefined, - db.PackCRCs, - db.Folders, - db.NumUnpackStreamsVector, + db.ArcInfo.DataStartPosition, + (CFolders &)db, unpackSizes, - digestsDefined, digests); - db.ArchiveInfo.DataStartPosition += db.ArchiveInfo.StartPositionAfterHeader; + db.ArcInfo.DataStartPosition += db.ArcInfo.StartPositionAfterHeader; type = ReadID(); } - else - { - for (int i = 0; i < db.Folders.Size(); i++) - { - db.NumUnpackStreamsVector.Add(1); - CFolder &folder = db.Folders[i]; - unpackSizes.Add(folder.GetUnpackSize()); - digestsDefined.Add(folder.UnpackCRCDefined); - digests.Add(folder.UnpackCRC); - } - } db.Files.Clear(); - if (type == NID::kEnd) - return S_OK; - if (type != NID::kFilesInfo) - ThrowIncorrect(); + if (type == NID::kFilesInfo) + { CNum numFiles = ReadNum(); + db.Files.ClearAndSetSize(numFiles); + CNum i; + /* db.Files.Reserve(numFiles); CNum i; for (i = 0; i < numFiles; i++) db.Files.Add(CFileItem()); + */ - db.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize); - if (!db.PackSizes.IsEmpty()) - db.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo); - if (numFiles > 0 && !digests.IsEmpty()) - db.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC); + db.ArcInfo.FileInfoPopIDs.Add(NID::kSize); + // if (!db.PackSizes.IsEmpty()) + db.ArcInfo.FileInfoPopIDs.Add(NID::kPackInfo); + if (numFiles > 0 && !digests.Defs.IsEmpty()) + db.ArcInfo.FileInfoPopIDs.Add(NID::kCRC); CBoolVector emptyStreamVector; - BoolVector_Fill_False(emptyStreamVector, (int)numFiles); + BoolVector_Fill_False(emptyStreamVector, (unsigned)numFiles); CBoolVector emptyFileVector; CBoolVector antiFileVector; CNum numEmptyStreams = 0; @@ -949,7 +1163,10 @@ HRESULT CInArchive::ReadHeader( if (type == NID::kEnd) break; UInt64 size = ReadNumber(); - size_t ppp = _inByteBack->_pos; + if (size > _inByteBack->GetRem()) + ThrowIncorrect(); + CStreamSwitch switchProp; + switchProp.Set(this, _inByteBack->GetPtr(), (size_t)size, true); bool addPropIdToList = true; bool isKnownType = true; if (type > ((UInt32)1 << 30)) @@ -960,11 +1177,29 @@ HRESULT CInArchive::ReadHeader( { CStreamSwitch streamSwitch; streamSwitch.Set(this, &dataVector); - for (int i = 0; i < db.Files.Size(); i++) - _inByteBack->ReadString(db.Files[i].Name); + size_t rem = _inByteBack->GetRem(); + db.NamesBuf.Alloc(rem); + ReadBytes(db.NamesBuf, rem); + db.NameOffsets.Alloc(db.Files.Size() + 1); + size_t pos = 0; + unsigned i; + for (i = 0; i < db.Files.Size(); i++) + { + size_t curRem = (rem - pos) / 2; + const UInt16 *buf = (const UInt16 *)(db.NamesBuf + pos); + size_t j; + for (j = 0; j < curRem && buf[j] != 0; j++); + if (j == curRem) + ThrowEndOfData(); + db.NameOffsets[i] = pos / 2; + pos += j * 2 + 2; + } + db.NameOffsets[i] = pos / 2; + if (pos != rem) + ThereIsHeaderError = true; break; } - case NID::kWinAttributes: + case NID::kWinAttrib: { CBoolVector boolVector; ReadBoolVector2(db.Files.Size(), boolVector); @@ -979,9 +1214,40 @@ HRESULT CInArchive::ReadHeader( } break; } + /* + case NID::kIsAux: + { + ReadBoolVector(db.Files.Size(), db.IsAux); + break; + } + case NID::kParent: + { + db.IsTree = true; + // CBoolVector boolVector; + // ReadBoolVector2(db.Files.Size(), boolVector); + // CStreamSwitch streamSwitch; + // streamSwitch.Set(this, &dataVector); + CBoolVector boolVector; + ReadBoolVector2(db.Files.Size(), boolVector); + + db.ThereAreAltStreams = false; + for (i = 0; i < numFiles; i++) + { + CFileItem &file = db.Files[i]; + // file.Parent = -1; + // if (boolVector[i]) + file.Parent = (int)ReadUInt32(); + file.IsAltStream = !boolVector[i]; + if (file.IsAltStream) + db.ThereAreAltStreams = true; + } + break; + } + */ case NID::kEmptyStream: { ReadBoolVector(numFiles, emptyStreamVector); + numEmptyStreams = 0; for (i = 0; i < (CNum)emptyStreamVector.Size(); i++) if (emptyStreamVector[i]) numEmptyStreams++; @@ -993,34 +1259,83 @@ HRESULT CInArchive::ReadHeader( } case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break; case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break; - case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (int)numFiles); break; - case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (int)numFiles); break; - case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (int)numFiles); break; - case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (int)numFiles); break; + case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (unsigned)numFiles); break; + case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (unsigned)numFiles); break; + case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (unsigned)numFiles); break; + case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (unsigned)numFiles); break; case NID::kDummy: { for (UInt64 j = 0; j < size; j++) if (ReadByte() != 0) - ThrowIncorrect(); + ThereIsHeaderError = true; addPropIdToList = false; break; } + /* + case NID::kNtSecure: + { + try + { + { + CStreamSwitch streamSwitch; + streamSwitch.Set(this, &dataVector); + UInt32 numDescriptors = ReadUInt32(); + size_t offset = 0; + db.SecureOffsets.Clear(); + for (i = 0; i < numDescriptors; i++) + { + UInt32 size = ReadUInt32(); + db.SecureOffsets.Add(offset); + offset += size; + } + // ThrowIncorrect();; + db.SecureOffsets.Add(offset); + db.SecureBuf.SetCapacity(offset); + for (i = 0; i < numDescriptors; i++) + { + offset = db.SecureOffsets[i]; + ReadBytes(db.SecureBuf + offset, db.SecureOffsets[i + 1] - offset); + } + db.SecureIDs.Clear(); + for (unsigned i = 0; i < db.Files.Size(); i++) + { + db.SecureIDs.Add(ReadNum()); + // db.SecureIDs.Add(ReadUInt32()); + } + // ReadUInt32(); + if (_inByteBack->GetRem() != 0) + ThrowIncorrect();; + } + } + catch(CInArchiveException &) + { + ThereIsHeaderError = true; + addPropIdToList = isKnownType = false; + db.ClearSecure(); + } + break; + } + */ default: addPropIdToList = isKnownType = false; } if (isKnownType) { - if(addPropIdToList) - db.ArchiveInfo.FileInfoPopIDs.Add(type); + if (addPropIdToList) + db.ArcInfo.FileInfoPopIDs.Add(type); } else - SkipData(size); - bool checkRecordsSize = (db.ArchiveInfo.Version.Major > 0 || - db.ArchiveInfo.Version.Minor > 2); - if (checkRecordsSize && _inByteBack->_pos - ppp != size) + { + db.UnsupportedFeatureWarning = true; + _inByteBack->SkipRem(); + } + // SkipData worked incorrectly in some versions before v4.59 (7zVer <= 00.02) + if (_inByteBack->GetRem() != 0) ThrowIncorrect(); } + type = ReadID(); // Read (NID::kEnd) end of headers + CNum emptyFileIndex = 0; CNum sizeIndex = 0; @@ -1034,13 +1349,15 @@ HRESULT CInArchive::ReadHeader( CFileItem &file = db.Files[i]; bool isAnti; file.HasStream = !emptyStreamVector[i]; + file.Crc = 0; if (file.HasStream) { file.IsDir = false; isAnti = false; file.Size = unpackSizes[sizeIndex]; - file.Crc = digests[sizeIndex]; - file.CrcDefined = digestsDefined[sizeIndex]; + file.CrcDefined = digests.ValidAndDefined(sizeIndex); + if (file.CrcDefined) + file.Crc = digests.Vals[sizeIndex]; sizeIndex++; } else @@ -1054,158 +1371,181 @@ HRESULT CInArchive::ReadHeader( if (numAntiItems != 0) db.IsAnti.Add(isAnti); } - return S_OK; -} - - -void CArchiveDatabaseEx::FillFolderStartPackStream() -{ - FolderStartPackStreamIndex.Clear(); - FolderStartPackStreamIndex.Reserve(Folders.Size()); - CNum startPos = 0; - for (int i = 0; i < Folders.Size(); i++) - { - FolderStartPackStreamIndex.Add(startPos); - startPos += (CNum)Folders[i].PackStreams.Size(); - } -} - -void CArchiveDatabaseEx::FillStartPos() -{ - PackStreamStartPositions.Clear(); - PackStreamStartPositions.Reserve(PackSizes.Size()); - UInt64 startPos = 0; - for (int i = 0; i < PackSizes.Size(); i++) - { - PackStreamStartPositions.Add(startPos); - startPos += PackSizes[i]; } + db.FillLinks(); + /* + if (type != NID::kEnd) + ThrowIncorrect(); + if (_inByteBack->GetRem() != 0) + ThrowIncorrect(); + */ + return S_OK; } -void CArchiveDatabaseEx::FillFolderStartFileIndex() +void CDbEx::FillLinks() { - FolderStartFileIndex.Clear(); - FolderStartFileIndex.Reserve(Folders.Size()); - FileIndexToFolderIndexMap.Clear(); - FileIndexToFolderIndexMap.Reserve(Files.Size()); + FolderStartFileIndex.ClearAndSetSize(NumFolders); - int folderIndex = 0; + FileIndexToFolderIndexMap.ClearAndSetSize(Files.Size()); + + CNum folderIndex = 0; CNum indexInFolder = 0; - for (int i = 0; i < Files.Size(); i++) + unsigned i; + for (i = 0; i < Files.Size(); i++) { - const CFileItem &file = Files[i]; - bool emptyStream = !file.HasStream; - if (emptyStream && indexInFolder == 0) - { - FileIndexToFolderIndexMap.Add(kNumNoIndex); - continue; - } + bool emptyStream = !Files[i].HasStream; if (indexInFolder == 0) { + if (emptyStream) + { + FileIndexToFolderIndexMap[i] = kNumNoIndex; + continue; + } // v3.13 incorrectly worked with empty folders - // v4.07: Loop for skipping empty folders + // v4.07: we skip empty folders for (;;) { - if (folderIndex >= Folders.Size()) + if (folderIndex >= NumFolders) ThrowIncorrect(); - FolderStartFileIndex.Add(i); // check it + FolderStartFileIndex[folderIndex] = i; if (NumUnpackStreamsVector[folderIndex] != 0) break; folderIndex++; } } - FileIndexToFolderIndexMap.Add(folderIndex); + FileIndexToFolderIndexMap[i] = folderIndex; if (emptyStream) continue; - indexInFolder++; - if (indexInFolder >= NumUnpackStreamsVector[folderIndex]) + if (++indexInFolder >= NumUnpackStreamsVector[folderIndex]) { folderIndex++; indexInFolder = 0; } } + + if (indexInFolder != 0) + folderIndex++; + /* + if (indexInFolder != 0) + ThrowIncorrect(); + */ + for (;;) + { + if (folderIndex >= NumFolders) + return; + FolderStartFileIndex[folderIndex] = i; + /* + if (NumUnpackStreamsVector[folderIndex] != 0) + ThrowIncorrect();; + */ + folderIndex++; + } } HRESULT CInArchive::ReadDatabase2( DECL_EXTERNAL_CODECS_LOC_VARS - CArchiveDatabaseEx &db - #ifndef _NO_CRYPTO - , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined - #endif + CDbEx &db + _7Z_DECODER_CRYPRO_VARS_DECL ) { db.Clear(); - db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition; + db.ArcInfo.StartPosition = _arhiveBeginStreamPosition; - db.ArchiveInfo.Version.Major = _header[6]; - db.ArchiveInfo.Version.Minor = _header[7]; + db.ArcInfo.Version.Major = _header[6]; + db.ArcInfo.Version.Minor = _header[7]; - if (db.ArchiveInfo.Version.Major != kMajorVersion) - ThrowUnsupportedVersion(); + if (db.ArcInfo.Version.Major != kMajorVersion) + { + // db.UnsupportedVersion = true; + return S_FALSE; + } - UInt32 crcFromArchive = Get32(_header + 8); - UInt64 nextHeaderOffset = Get64(_header + 0xC); - UInt64 nextHeaderSize = Get64(_header + 0x14); - UInt32 nextHeaderCRC = Get32(_header + 0x1C); - UInt32 crc = CrcCalc(_header + 0xC, 20); + UInt64 nextHeaderOffset = Get64(_header + 12); + UInt64 nextHeaderSize = Get64(_header + 20); + UInt32 nextHeaderCRC = Get32(_header + 28); #ifdef FORMAT_7Z_RECOVERY - if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0) + UInt32 crcFromArc = Get32(_header + 8); + if (crcFromArc == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0) { - UInt64 cur, cur2; + UInt64 cur, fileSize; RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur)); - const int kCheckSize = 500; + const unsigned kCheckSize = 512; Byte buf[kCheckSize]; - RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2)); - int checkSize = kCheckSize; - if (cur2 - cur < kCheckSize) - checkSize = (int)(cur2 - cur); - RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2)); - + RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize)); + UInt64 rem = fileSize - cur; + unsigned checkSize = kCheckSize; + if (rem < kCheckSize) + checkSize = (unsigned)(rem); + if (checkSize < 3) + return S_FALSE; + RINOK(_stream->Seek(fileSize - checkSize, STREAM_SEEK_SET, NULL)); RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize)); - int i; - for (i = (int)checkSize - 2; i >= 0; i--) - if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04) - break; - if (i < 0) + if (buf[checkSize - 1] != 0) return S_FALSE; + + unsigned i; + for (i = checkSize - 2;; i--) + { + if (buf[i] == NID::kEncodedHeader && buf[i + 1] == NID::kPackInfo || + buf[i] == NID::kHeader && buf[i + 1] == NID::kMainStreamsInfo) + break; + if (i == 0) + return S_FALSE; + } nextHeaderSize = checkSize - i; - nextHeaderOffset = cur2 - cur + i; + nextHeaderOffset = rem - nextHeaderSize; nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize); RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL)); + db.StartHeaderWasRecovered = true; } else #endif { - if (crc != crcFromArchive) - ThrowIncorrect(); + // Crc was tested already at signature check + // if (CrcCalc(_header + 12, 20) != crcFromArchive) ThrowIncorrect(); } - db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize; + db.ArcInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize; + db.PhySize = kHeaderSize; + db.IsArc = false; + if ((Int64)nextHeaderOffset < 0 || + nextHeaderSize > ((UInt64)1 << 62)) + return S_FALSE; if (nextHeaderSize == 0) + { + if (nextHeaderOffset != 0) + return S_FALSE; + db.IsArc = true; return S_OK; - - if (nextHeaderSize > (UInt64)(UInt32)0xFFFFFFFF) - return S_FALSE; - - if ((Int64)nextHeaderOffset < 0) - return S_FALSE; - - if (db.ArchiveInfo.StartPositionAfterHeader + nextHeaderOffset > _fileEndPosition) + } + + if (!db.StartHeaderWasRecovered) + db.IsArc = true; + + HeadersSize += kHeaderSize + nextHeaderSize; + db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize; + if (_fileEndPosition - db.ArcInfo.StartPositionAfterHeader < nextHeaderOffset + nextHeaderSize) + { + db.UnexpectedEnd = true; return S_FALSE; + } RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL)); - CByteBuffer buffer2; - buffer2.SetCapacity((size_t)nextHeaderSize); + size_t nextHeaderSize_t = (size_t)nextHeaderSize; + if (nextHeaderSize_t != nextHeaderSize) + return E_OUTOFMEMORY; + CByteBuffer buffer2(nextHeaderSize_t); - RINOK(ReadStream_FALSE(_stream, buffer2, (size_t)nextHeaderSize)); - HeadersSize += kHeaderSize + nextHeaderSize; - db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize; + RINOK(ReadStream_FALSE(_stream, buffer2, nextHeaderSize_t)); - if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC) + if (CrcCalc(buffer2, nextHeaderSize_t) != nextHeaderCRC) ThrowIncorrect(); + + if (!db.StartHeaderWasRecovered) + db.PhySizeWasConfirmed = true; CStreamSwitch streamSwitch; streamSwitch.Set(this, buffer2); @@ -1219,12 +1559,10 @@ HRESULT CInArchive::ReadDatabase2( ThrowIncorrect(); HRESULT result = ReadAndDecodePackedStreams( EXTERNAL_CODECS_LOC_VARS - db.ArchiveInfo.StartPositionAfterHeader, - db.ArchiveInfo.DataStartPosition2, + db.ArcInfo.StartPositionAfterHeader, + db.ArcInfo.DataStartPosition2, dataVector - #ifndef _NO_CRYPTO - , getTextPassword, passwordIsDefined - #endif + _7Z_DECODER_CRYPRO_VARS ); RINOK(result); if (dataVector.Size() == 0) @@ -1237,35 +1575,45 @@ HRESULT CInArchive::ReadDatabase2( ThrowIncorrect(); } + db.IsArc = true; + db.HeadersSize = HeadersSize; return ReadHeader( EXTERNAL_CODECS_LOC_VARS db - #ifndef _NO_CRYPTO - , getTextPassword, passwordIsDefined - #endif + _7Z_DECODER_CRYPRO_VARS ); } HRESULT CInArchive::ReadDatabase( DECL_EXTERNAL_CODECS_LOC_VARS - CArchiveDatabaseEx &db - #ifndef _NO_CRYPTO - , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined - #endif + CDbEx &db + _7Z_DECODER_CRYPRO_VARS_DECL ) { try { - return ReadDatabase2( + HRESULT res = ReadDatabase2( EXTERNAL_CODECS_LOC_VARS db - #ifndef _NO_CRYPTO - , getTextPassword, passwordIsDefined - #endif + _7Z_DECODER_CRYPRO_VARS ); + if (ThereIsHeaderError) + db.ThereIsHeaderError = true; + if (res == E_NOTIMPL) + ThrowUnsupported(); + return res; + } + catch(CUnsupportedFeatureException &) + { + db.UnsupportedFeatureError = true; + return S_FALSE; + } + catch(CInArchiveException &) + { + db.ThereIsHeaderError = true; + return S_FALSE; } - catch(CInArchiveException &) { return S_FALSE; } } }} diff --git a/CPP/7zip/Archive/7z/7zIn.h b/CPP/7zip/Archive/7z/7zIn.h index 4305a8c5..1836a06b 100755..100644 --- a/CPP/7zip/Archive/7z/7zIn.h +++ b/CPP/7zip/Archive/7z/7zIn.h @@ -5,6 +5,8 @@ #include "../../../Common/MyCom.h" +#include "../../../Windows/PropVariant.h" + #include "../../IPassword.h" #include "../../IStream.h" @@ -15,7 +17,147 @@ namespace NArchive { namespace N7z { + +/* + We don't need to init isEncrypted and passwordIsDefined + We must upgrade them only */ + +#ifdef _NO_CRYPTO +#define _7Z_DECODER_CRYPRO_VARS_DECL +#define _7Z_DECODER_CRYPRO_VARS +#else +#define _7Z_DECODER_CRYPRO_VARS_DECL , ICryptoGetTextPassword *getTextPassword, bool &isEncrypted, bool &passwordIsDefined +#define _7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined +#endif + +struct CParsedMethods +{ + Byte Lzma2Prop; + UInt32 LzmaDic; + CRecordVector<UInt64> IDs; + + CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {} +}; + +struct CFolders +{ + CNum NumPackStreams; + CNum NumFolders; + + CObjArray<UInt64> PackPositions; // NumPackStreams + 1 + // CUInt32DefVector PackCRCs; // we don't use PackCRCs now + + CUInt32DefVector FolderCRCs; // NumFolders + CObjArray<CNum> NumUnpackStreamsVector; // NumFolders + + CObjArray<UInt64> CoderUnpackSizes; // including unpack sizes of bind coders + CObjArray<CNum> FoToCoderUnpackSizes; // NumFolders + 1 + CObjArray<CNum> FoStartPackStreamIndex; // NumFolders + 1 + CObjArray<Byte> FoToMainUnpackSizeIndex; // NumFolders + CObjArray<size_t> FoCodersDataOffset; // NumFolders + 1 + CByteBuffer CodersData; + + CParsedMethods ParsedMethods; + + void ParseFolderInfo(unsigned folderIndex, CFolder &folder) const; + + unsigned GetNumFolderUnpackSizes(unsigned folderIndex) const + { + return FoToCoderUnpackSizes[folderIndex + 1] - FoToCoderUnpackSizes[folderIndex]; + } + + UInt64 GetFolderUnpackSize(unsigned folderIndex) const + { + return CoderUnpackSizes[FoToCoderUnpackSizes[folderIndex] + FoToMainUnpackSizeIndex[folderIndex]]; + } + + UInt64 GetStreamPackSize(unsigned index) const + { + return PackPositions[index + 1] - PackPositions[index]; + } + + void Clear() + { + NumPackStreams = 0; + PackPositions.Free(); + // PackCRCs.Clear(); + + NumFolders = 0; + FolderCRCs.Clear(); + NumUnpackStreamsVector.Free(); + CoderUnpackSizes.Free(); + FoToCoderUnpackSizes.Free(); + FoStartPackStreamIndex.Free(); + FoToMainUnpackSizeIndex.Free(); + FoCodersDataOffset.Free(); + CodersData.Free(); + } +}; + +struct CDatabase: public CFolders +{ + CRecordVector<CFileItem> Files; + + CUInt64DefVector CTime; + CUInt64DefVector ATime; + CUInt64DefVector MTime; + CUInt64DefVector StartPos; + CRecordVector<bool> IsAnti; + /* + CRecordVector<bool> IsAux; + CByteBuffer SecureBuf; + CRecordVector<UInt32> SecureIDs; + */ + + CByteBuffer NamesBuf; + CObjArray<size_t> NameOffsets; // numFiles + 1, conatins offsets of UINt16 symbols. + + /* + void ClearSecure() + { + SecureBuf.Free(); + SecureIDs.Clear(); + } + */ + + void Clear() + { + CFolders::Clear(); + // ClearSecure(); + + NamesBuf.Free(); + NameOffsets.Free(); + + Files.Clear(); + CTime.Clear(); + ATime.Clear(); + MTime.Clear(); + StartPos.Clear(); + IsAnti.Clear(); + // IsAux.Clear(); + } + + bool IsSolid() const + { + for (CNum i = 0; i < NumFolders; i++) + if (NumUnpackStreamsVector[i] > 1) + return true; + return false; + } + bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); } + // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); } + + const wchar_t * GetName(unsigned index) const + { + if (!NameOffsets || !NamesBuf) + return NULL; + return (const wchar_t *)(const Byte *)NamesBuf + NameOffsets[index]; + }; + + HRESULT GetPath(unsigned index, PROPVARIANT *path) const; +}; + struct CInArchiveInfo { CArchiveVersion Version; @@ -24,29 +166,73 @@ struct CInArchiveInfo UInt64 DataStartPosition; UInt64 DataStartPosition2; CRecordVector<UInt64> FileInfoPopIDs; + void Clear() { + StartPosition = 0; + StartPositionAfterHeader = 0; + DataStartPosition = 0; + DataStartPosition2 = 0; FileInfoPopIDs.Clear(); } }; -struct CArchiveDatabaseEx: public CArchiveDatabase +struct CDbEx: public CDatabase { - CInArchiveInfo ArchiveInfo; - CRecordVector<UInt64> PackStreamStartPositions; - CRecordVector<CNum> FolderStartPackStreamIndex; + CInArchiveInfo ArcInfo; CRecordVector<CNum> FolderStartFileIndex; CRecordVector<CNum> FileIndexToFolderIndexMap; UInt64 HeadersSize; UInt64 PhySize; + /* + CRecordVector<size_t> SecureOffsets; + bool IsTree; + bool ThereAreAltStreams; + */ + + bool IsArc; + bool PhySizeWasConfirmed; + + bool ThereIsHeaderError; + bool UnexpectedEnd; + // bool UnsupportedVersion; + + bool StartHeaderWasRecovered; + bool UnsupportedFeatureWarning; + bool UnsupportedFeatureError; + + /* + void ClearSecureEx() + { + ClearSecure(); + SecureOffsets.Clear(); + } + */ + void Clear() { - CArchiveDatabase::Clear(); - ArchiveInfo.Clear(); - PackStreamStartPositions.Clear(); - FolderStartPackStreamIndex.Clear(); + IsArc = false; + PhySizeWasConfirmed = false; + + ThereIsHeaderError = false; + UnexpectedEnd = false; + // UnsupportedVersion = false; + + StartHeaderWasRecovered = false; + UnsupportedFeatureError = false; + UnsupportedFeatureWarning = false; + + /* + IsTree = false; + ThereAreAltStreams = false; + */ + + CDatabase::Clear(); + + // SecureOffsets.Clear(); + ArcInfo.Clear(); FolderStartFileIndex.Clear(); FileIndexToFolderIndexMap.Clear(); @@ -54,36 +240,25 @@ struct CArchiveDatabaseEx: public CArchiveDatabase PhySize = 0; } - void FillFolderStartPackStream(); - void FillStartPos(); - void FillFolderStartFileIndex(); - - void Fill() - { - FillFolderStartPackStream(); - FillStartPos(); - FillFolderStartFileIndex(); - } + void FillLinks(); - UInt64 GetFolderStreamPos(int folderIndex, int indexInFolder) const + UInt64 GetFolderStreamPos(unsigned folderIndex, unsigned indexInFolder) const { - return ArchiveInfo.DataStartPosition + - PackStreamStartPositions[FolderStartPackStreamIndex[folderIndex] + indexInFolder]; + return ArcInfo.DataStartPosition + + PackPositions[FoStartPackStreamIndex[folderIndex] + indexInFolder]; } - UInt64 GetFolderFullPackSize(int folderIndex) const + UInt64 GetFolderFullPackSize(unsigned folderIndex) const { - CNum packStreamIndex = FolderStartPackStreamIndex[folderIndex]; - const CFolder &folder = Folders[folderIndex]; - UInt64 size = 0; - for (int i = 0; i < folder.PackStreams.Size(); i++) - size += PackSizes[packStreamIndex + i]; - return size; + return + PackPositions[FoStartPackStreamIndex[folderIndex + 1]] - + PackPositions[FoStartPackStreamIndex[folderIndex]]; } - UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const + UInt64 GetFolderPackStreamSize(unsigned folderIndex, unsigned streamIndex) const { - return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex]; + unsigned i = FoStartPackStreamIndex[folderIndex] + streamIndex; + return PackPositions[i + 1] - PackPositions[i]; } UInt64 GetFilePackSize(CNum fileIndex) const @@ -96,12 +271,17 @@ struct CArchiveDatabaseEx: public CArchiveDatabase } }; -class CInByte2 +const unsigned kNumBufLevelsMax = 4; + +struct CInByte2 { const Byte *_buffer; - size_t _size; public: + size_t _size; size_t _pos; + + size_t GetRem() const { return _size - _pos; } + const Byte *GetPtr() const { return _buffer + _pos; } void Init(const Byte *buffer, size_t size) { _buffer = buffer; @@ -110,13 +290,17 @@ public: } Byte ReadByte(); void ReadBytes(Byte *data, size_t size); + void SkipDataNoCheck(UInt64 size) { _pos += (size_t)size; } void SkipData(UInt64 size); + void SkipData(); + void SkipRem() { _pos = _size; } UInt64 ReadNumber(); CNum ReadNum(); UInt32 ReadUInt32(); UInt64 ReadUInt64(); - void ReadString(UString &s); + + void ParseFolder(CFolder &folder); }; class CStreamSwitch; @@ -129,8 +313,11 @@ class CInArchive CMyComPtr<IInStream> _stream; - CObjectVector<CInByte2> _inByteVector; + unsigned _numInByteBufs; + CInByte2 _inByteVector[kNumBufLevelsMax]; + CInByte2 *_inByteBack; + bool ThereIsHeaderError; UInt64 _arhiveBeginStreamPosition; UInt64 _fileEndPosition; @@ -139,18 +326,17 @@ class CInArchive UInt64 HeadersSize; - void AddByteStream(const Byte *buffer, size_t size) - { - _inByteVector.Add(CInByte2()); - _inByteBack = &_inByteVector.Back(); - _inByteBack->Init(buffer, size); - } + void AddByteStream(const Byte *buffer, size_t size); - void DeleteByteStream() + void DeleteByteStream(bool needUpdatePos) { - _inByteVector.DeleteBack(); - if (!_inByteVector.IsEmpty()) - _inByteBack = &_inByteVector.Back(); + _numInByteBufs--; + if (_numInByteBufs > 0) + { + _inByteBack = &_inByteVector[_numInByteBufs - 1]; + if (needUpdatePos) + _inByteBack->_pos += _inByteVector[_numInByteBufs]._pos; + } } private: @@ -165,79 +351,58 @@ private: UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); } void SkipData(UInt64 size) { _inByteBack->SkipData(size); } void SkipData() { _inByteBack->SkipData(); } - void WaitAttribute(UInt64 attribute); + void WaitId(UInt64 id); void ReadArchiveProperties(CInArchiveInfo &archiveInfo); - void GetNextFolderItem(CFolder &itemInfo); - void ReadHashDigests(int numItems, - CBoolVector &digestsDefined, CRecordVector<UInt32> &digests); + void ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs); - void ReadPackInfo( - UInt64 &dataOffset, - CRecordVector<UInt64> &packSizes, - CBoolVector &packCRCsDefined, - CRecordVector<UInt32> &packCRCs); + void ReadPackInfo(CFolders &f); void ReadUnpackInfo( const CObjectVector<CByteBuffer> *dataVector, - CObjectVector<CFolder> &folders); + CFolders &folders); void ReadSubStreamsInfo( - const CObjectVector<CFolder> &folders, - CRecordVector<CNum> &numUnpackStreamsInFolders, + CFolders &folders, CRecordVector<UInt64> &unpackSizes, - CBoolVector &digestsDefined, - CRecordVector<UInt32> &digests); + CUInt32DefVector &digests); void ReadStreamsInfo( const CObjectVector<CByteBuffer> *dataVector, UInt64 &dataOffset, - CRecordVector<UInt64> &packSizes, - CBoolVector &packCRCsDefined, - CRecordVector<UInt32> &packCRCs, - CObjectVector<CFolder> &folders, - CRecordVector<CNum> &numUnpackStreamsInFolders, + CFolders &folders, CRecordVector<UInt64> &unpackSizes, - CBoolVector &digestsDefined, - CRecordVector<UInt32> &digests); - + CUInt32DefVector &digests); - void ReadBoolVector(int numItems, CBoolVector &v); - void ReadBoolVector2(int numItems, CBoolVector &v); + void ReadBoolVector(unsigned numItems, CBoolVector &v); + void ReadBoolVector2(unsigned numItems, CBoolVector &v); void ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector, - CUInt64DefVector &v, int numFiles); + CUInt64DefVector &v, unsigned numItems); HRESULT ReadAndDecodePackedStreams( DECL_EXTERNAL_CODECS_LOC_VARS UInt64 baseOffset, UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector - #ifndef _NO_CRYPTO - , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined - #endif + _7Z_DECODER_CRYPRO_VARS_DECL ); HRESULT ReadHeader( DECL_EXTERNAL_CODECS_LOC_VARS - CArchiveDatabaseEx &db - #ifndef _NO_CRYPTO - ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined - #endif + CDbEx &db + _7Z_DECODER_CRYPRO_VARS_DECL ); HRESULT ReadDatabase2( DECL_EXTERNAL_CODECS_LOC_VARS - CArchiveDatabaseEx &db - #ifndef _NO_CRYPTO - ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined - #endif + CDbEx &db + _7Z_DECODER_CRYPRO_VARS_DECL ); public: + CInArchive(): _numInByteBufs(0) { } HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive void Close(); HRESULT ReadDatabase( DECL_EXTERNAL_CODECS_LOC_VARS - CArchiveDatabaseEx &db - #ifndef _NO_CRYPTO - ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined - #endif + CDbEx &db + _7Z_DECODER_CRYPRO_VARS_DECL ); }; diff --git a/CPP/7zip/Archive/7z/7zItem.h b/CPP/7zip/Archive/7z/7zItem.h index 34f10775..02a86196 100755..100644 --- a/CPP/7zip/Archive/7z/7zItem.h +++ b/CPP/7zip/Archive/7z/7zItem.h @@ -3,7 +3,7 @@ #ifndef __7Z_ITEM_H #define __7Z_ITEM_H -#include "../../../Common/Buffer.h" +#include "../../../Common/MyBuffer.h" #include "../../../Common/MyString.h" #include "../../Common/MethodId.h" @@ -25,6 +25,7 @@ struct CCoderInfo CByteBuffer Props; CNum NumInStreams; CNum NumOutStreams; + bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); } }; @@ -36,55 +37,48 @@ struct CBindPair struct CFolder { - CObjectVector<CCoderInfo> Coders; - CRecordVector<CBindPair> BindPairs; - CRecordVector<CNum> PackStreams; - CRecordVector<UInt64> UnpackSizes; - UInt32 UnpackCRC; - bool UnpackCRCDefined; - - CFolder(): UnpackCRCDefined(false) {} - - UInt64 GetUnpackSize() const // test it - { - if (UnpackSizes.IsEmpty()) - return 0; - for (int i = UnpackSizes.Size() - 1; i >= 0; i--) - if (FindBindPairForOutStream(i) < 0) - return UnpackSizes[i]; - throw 1; - } + CObjArray2<CCoderInfo> Coders; + CObjArray2<CBindPair> BindPairs; + CObjArray2<CNum> PackStreams; CNum GetNumOutStreams() const { CNum result = 0; - for (int i = 0; i < Coders.Size(); i++) + FOR_VECTOR(i, Coders) result += Coders[i].NumOutStreams; return result; } int FindBindPairForInStream(CNum inStreamIndex) const { - for(int i = 0; i < BindPairs.Size(); i++) + FOR_VECTOR(i, BindPairs) if (BindPairs[i].InIndex == inStreamIndex) return i; return -1; } int FindBindPairForOutStream(CNum outStreamIndex) const { - for(int i = 0; i < BindPairs.Size(); i++) + FOR_VECTOR(i, BindPairs) if (BindPairs[i].OutIndex == outStreamIndex) return i; return -1; } int FindPackStreamArrayIndex(CNum inStreamIndex) const { - for(int i = 0; i < PackStreams.Size(); i++) + FOR_VECTOR(i, PackStreams) if (PackStreams[i] == inStreamIndex) return i; return -1; } + int GetIndexOfMainOutStream() const + { + for (int i = (int)GetNumOutStreams() - 1; i >= 0; i--) + if (FindBindPairForOutStream(i) < 0) + return i; + throw 1; + } + bool IsEncrypted() const { for (int i = Coders.Size() - 1; i >= 0; i--) @@ -93,50 +87,66 @@ struct CFolder return false; } - bool CheckStructure() const; + bool CheckStructure(unsigned numUnpackSizes) const; +}; + +struct CUInt32DefVector +{ + CBoolVector Defs; + CRecordVector<UInt32> Vals; + + void ClearAndSetSize(unsigned newSize) + { + Defs.ClearAndSetSize(newSize); + Vals.ClearAndSetSize(newSize); + } + + void Clear() + { + Defs.Clear(); + Vals.Clear(); + } + + void ReserveDown() + { + Defs.ReserveDown(); + Vals.ReserveDown(); + } + + bool ValidAndDefined(unsigned i) const { return i < Defs.Size() && Defs[i]; } }; struct CUInt64DefVector { - CRecordVector<UInt64> Values; - CRecordVector<bool> Defined; + CBoolVector Defs; + CRecordVector<UInt64> Vals; void Clear() { - Values.Clear(); - Defined.Clear(); + Defs.Clear(); + Vals.Clear(); } void ReserveDown() { - Values.ReserveDown(); - Values.ReserveDown(); + Defs.ReserveDown(); + Vals.ReserveDown(); } - bool GetItem(int index, UInt64 &value) const + bool GetItem(unsigned index, UInt64 &value) const { - if (index < Defined.Size() && Defined[index]) + if (index < Defs.Size() && Defs[index]) { - value = Values[index]; + value = Vals[index]; return true; } value = 0; return false; } - void SetItem(int index, bool defined, UInt64 value) - { - while (index >= Defined.Size()) - Defined.Add(false); - Defined[index] = defined; - if (!defined) - return; - while (index >= Values.Size()) - Values.Add(0); - Values[index] = value; - } + void SetItem(unsigned index, bool defined, UInt64 value); - bool CheckSize(int size) const { return Defined.Size() == size || Defined.Size() == 0; } + bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; } }; struct CFileItem @@ -144,8 +154,10 @@ struct CFileItem UInt64 Size; UInt32 Attrib; UInt32 Crc; - UString Name; - + /* + int Parent; + bool IsAltStream; + */ bool HasStream; // Test it !!! it means that there is // stream in some folder. It can be empty stream bool IsDir; @@ -153,6 +165,10 @@ struct CFileItem bool AttribDefined; CFileItem(): + /* + Parent(-1), + IsAltStream(false), + */ HasStream(true), IsDir(false), CrcDefined(false), @@ -165,104 +181,6 @@ struct CFileItem } }; -struct CFileItem2 -{ - UInt64 CTime; - UInt64 ATime; - UInt64 MTime; - UInt64 StartPos; - bool CTimeDefined; - bool ATimeDefined; - bool MTimeDefined; - bool StartPosDefined; - bool IsAnti; -}; - -struct CArchiveDatabase -{ - CRecordVector<UInt64> PackSizes; - CRecordVector<bool> PackCRCsDefined; - CRecordVector<UInt32> PackCRCs; - CObjectVector<CFolder> Folders; - CRecordVector<CNum> NumUnpackStreamsVector; - CObjectVector<CFileItem> Files; - - CUInt64DefVector CTime; - CUInt64DefVector ATime; - CUInt64DefVector MTime; - CUInt64DefVector StartPos; - CRecordVector<bool> IsAnti; - - void Clear() - { - PackSizes.Clear(); - PackCRCsDefined.Clear(); - PackCRCs.Clear(); - Folders.Clear(); - NumUnpackStreamsVector.Clear(); - Files.Clear(); - CTime.Clear(); - ATime.Clear(); - MTime.Clear(); - StartPos.Clear(); - IsAnti.Clear(); - } - - void ReserveDown() - { - PackSizes.ReserveDown(); - PackCRCsDefined.ReserveDown(); - PackCRCs.ReserveDown(); - Folders.ReserveDown(); - NumUnpackStreamsVector.ReserveDown(); - Files.ReserveDown(); - CTime.ReserveDown(); - ATime.ReserveDown(); - MTime.ReserveDown(); - StartPos.ReserveDown(); - IsAnti.ReserveDown(); - } - - bool IsEmpty() const - { - return (PackSizes.IsEmpty() && - PackCRCsDefined.IsEmpty() && - PackCRCs.IsEmpty() && - Folders.IsEmpty() && - NumUnpackStreamsVector.IsEmpty() && - Files.IsEmpty()); - } - - bool CheckNumFiles() const - { - int size = Files.Size(); - return ( - CTime.CheckSize(size) && - ATime.CheckSize(size) && - MTime.CheckSize(size) && - StartPos.CheckSize(size) && - (size == IsAnti.Size() || IsAnti.Size() == 0)); - } - - bool IsSolid() const - { - for (int i = 0; i < NumUnpackStreamsVector.Size(); i++) - if (NumUnpackStreamsVector[i] > 1) - return true; - return false; - } - bool IsItemAnti(int index) const { return (index < IsAnti.Size() && IsAnti[index]); } - void SetItemAnti(int index, bool isAnti) - { - while (index >= IsAnti.Size()) - IsAnti.Add(false); - IsAnti[index] = isAnti; - } - - void GetFile(int index, CFileItem &file, CFileItem2 &file2) const; - void AddFile(const CFileItem &file, const CFileItem2 &file2); -}; - }} #endif diff --git a/CPP/7zip/Archive/7z/7zOut.cpp b/CPP/7zip/Archive/7z/7zOut.cpp index 0c8aa7e8..9ff97595 100755..100644 --- a/CPP/7zip/Archive/7z/7zOut.cpp +++ b/CPP/7zip/Archive/7z/7zOut.cpp @@ -10,35 +10,15 @@ #include "7zOut.h" -static HRESULT WriteBytes(ISequentialOutStream *stream, const void *data, size_t size) -{ - while (size > 0) - { - UInt32 curSize = (UInt32)MyMin(size, (size_t)0xFFFFFFFF); - UInt32 processedSize; - RINOK(stream->Write(data, curSize, &processedSize)); - if (processedSize == 0) - return E_FAIL; - data = (const void *)((const Byte *)data + processedSize); - size -= processedSize; - } - return S_OK; -} - namespace NArchive { namespace N7z { -HRESULT COutArchive::WriteDirect(const void *data, UInt32 size) -{ - return ::WriteBytes(SeqStream, data, size); -} - HRESULT COutArchive::WriteSignature() { Byte buf[8]; memcpy(buf, kSignature, kSignatureSize); buf[kSignatureSize] = kMajorVersion; - buf[kSignatureSize + 1] = 3; + buf[kSignatureSize + 1] = 4; return WriteDirect(buf, 8); } @@ -145,7 +125,9 @@ HRESULT COutArchive::SkipPrefixArchiveHeader() if (_endMarker) return S_OK; #endif - return Stream->Seek(24, STREAM_SEEK_CUR, NULL); + Byte buf[24]; + memset(buf, 0, 24); + return WriteDirect(buf, 24); } UInt64 COutArchive::GetPos() const @@ -271,19 +253,19 @@ UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props) void COutArchive::WriteFolder(const CFolder &folder) { WriteNumber(folder.Coders.Size()); - int i; + unsigned i; for (i = 0; i < folder.Coders.Size(); i++) { const CCoderInfo &coder = folder.Coders[i]; { - size_t propsSize = coder.Props.GetCapacity(); + size_t propsSize = coder.Props.Size(); UInt64 id = coder.MethodID; int idSize; for (idSize = 1; idSize < sizeof(id); idSize++) if ((id >> (8 * idSize)) == 0) break; - BYTE longID[15]; + Byte longID[15]; for (int t = idSize - 1; t >= 0 ; t--, id >>= 8) longID[t] = (Byte)(id & 0xFF); Byte b; @@ -321,7 +303,7 @@ void COutArchive::WriteBoolVector(const CBoolVector &boolVector) { Byte b = 0; Byte mask = 0x80; - for (int i = 0; i < boolVector.Size(); i++) + FOR_VECTOR (i, boolVector) { if (boolVector[i]) b |= mask; @@ -337,37 +319,42 @@ void COutArchive::WriteBoolVector(const CBoolVector &boolVector) WriteByte(b); } +static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; } -void COutArchive::WriteHashDigests( - const CRecordVector<bool> &digestsDefined, - const CRecordVector<UInt32> &digests) +void COutArchive::WritePropBoolVector(Byte id, const CBoolVector &boolVector) { - int numDefined = 0; - int i; - for (i = 0; i < digestsDefined.Size(); i++) - if (digestsDefined[i]) + WriteByte(id); + WriteNumber(Bv_GetSizeInBytes(boolVector)); + WriteBoolVector(boolVector); +} + +void COutArchive::WriteHashDigests(const CUInt32DefVector &digests) +{ + unsigned numDefined = 0; + unsigned i; + for (i = 0; i < digests.Defs.Size(); i++) + if (digests.Defs[i]) numDefined++; if (numDefined == 0) return; WriteByte(NID::kCRC); - if (numDefined == digestsDefined.Size()) + if (numDefined == digests.Defs.Size()) WriteByte(1); else { WriteByte(0); - WriteBoolVector(digestsDefined); + WriteBoolVector(digests.Defs); } - for (i = 0; i < digests.Size(); i++) - if (digestsDefined[i]) - WriteUInt32(digests[i]); + for (i = 0; i < digests.Defs.Size(); i++) + if (digests.Defs[i]) + WriteUInt32(digests.Vals[i]); } void COutArchive::WritePackInfo( UInt64 dataOffset, const CRecordVector<UInt64> &packSizes, - const CRecordVector<bool> &packCRCsDefined, - const CRecordVector<UInt32> &packCRCs) + const CUInt32DefVector &packCRCs) { if (packSizes.IsEmpty()) return; @@ -375,15 +362,15 @@ void COutArchive::WritePackInfo( WriteNumber(dataOffset); WriteNumber(packSizes.Size()); WriteByte(NID::kSize); - for (int i = 0; i < packSizes.Size(); i++) + FOR_VECTOR (i, packSizes) WriteNumber(packSizes[i]); - WriteHashDigests(packCRCsDefined, packCRCs); + WriteHashDigests(packCRCs); WriteByte(NID::kEnd); } -void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders) +void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders, const COutFolders &outFolders) { if (folders.IsEmpty()) return; @@ -394,44 +381,29 @@ void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders) WriteNumber(folders.Size()); { WriteByte(0); - for (int i = 0; i < folders.Size(); i++) + FOR_VECTOR (i, folders) WriteFolder(folders[i]); } WriteByte(NID::kCodersUnpackSize); - int i; - for (i = 0; i < folders.Size(); i++) - { - const CFolder &folder = folders[i]; - for (int j = 0; j < folder.UnpackSizes.Size(); j++) - WriteNumber(folder.UnpackSizes[j]); - } - - CRecordVector<bool> unpackCRCsDefined; - CRecordVector<UInt32> unpackCRCs; - for (i = 0; i < folders.Size(); i++) - { - const CFolder &folder = folders[i]; - unpackCRCsDefined.Add(folder.UnpackCRCDefined); - unpackCRCs.Add(folder.UnpackCRC); - } - WriteHashDigests(unpackCRCsDefined, unpackCRCs); - + FOR_VECTOR (i, outFolders.CoderUnpackSizes) + WriteNumber(outFolders.CoderUnpackSizes[i]); + + WriteHashDigests(outFolders.FolderUnpackCRCs); + WriteByte(NID::kEnd); } -void COutArchive::WriteSubStreamsInfo( - const CObjectVector<CFolder> &folders, - const CRecordVector<CNum> &numUnpackStreamsInFolders, +void COutArchive::WriteSubStreamsInfo(const CObjectVector<CFolder> &folders, + const COutFolders &outFolders, const CRecordVector<UInt64> &unpackSizes, - const CRecordVector<bool> &digestsDefined, - const CRecordVector<UInt32> &digests) + const CUInt32DefVector &digests) { + const CRecordVector<CNum> &numUnpackStreamsInFolders = outFolders.NumUnpackStreamsVector; WriteByte(NID::kSubStreamsInfo); - int i; + unsigned i; for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) - { if (numUnpackStreamsInFolders[i] != 1) { WriteByte(NID::kNumUnpackStream); @@ -439,54 +411,50 @@ void COutArchive::WriteSubStreamsInfo( WriteNumber(numUnpackStreamsInFolders[i]); break; } - } - - bool needFlag = true; - CNum index = 0; for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) - for (CNum j = 0; j < numUnpackStreamsInFolders[i]; j++) + if (numUnpackStreamsInFolders[i] > 1) { - if (j + 1 != numUnpackStreamsInFolders[i]) + WriteByte(NID::kSize); + CNum index = 0; + for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) { - if (needFlag) - WriteByte(NID::kSize); - needFlag = false; - WriteNumber(unpackSizes[index]); + CNum num = numUnpackStreamsInFolders[i]; + for (CNum j = 0; j < num; j++) + { + if (j + 1 != num) + WriteNumber(unpackSizes[index]); + index++; + } } - index++; + break; } - CRecordVector<bool> digestsDefined2; - CRecordVector<UInt32> digests2; + CUInt32DefVector digests2; - int digestIndex = 0; + unsigned digestIndex = 0; for (i = 0; i < folders.Size(); i++) { - int numSubStreams = (int)numUnpackStreamsInFolders[i]; - if (numSubStreams == 1 && folders[i].UnpackCRCDefined) + unsigned numSubStreams = (unsigned)numUnpackStreamsInFolders[i]; + if (numSubStreams == 1 && outFolders.FolderUnpackCRCs.ValidAndDefined(i)) digestIndex++; else - for (int j = 0; j < numSubStreams; j++, digestIndex++) + for (unsigned j = 0; j < numSubStreams; j++, digestIndex++) { - digestsDefined2.Add(digestsDefined[digestIndex]); - digests2.Add(digests[digestIndex]); + digests2.Defs.Add(digests.Defs[digestIndex]); + digests2.Vals.Add(digests.Vals[digestIndex]); } } - WriteHashDigests(digestsDefined2, digests2); + WriteHashDigests(digests2); WriteByte(NID::kEnd); } -void COutArchive::SkipAlign(unsigned /* pos */, unsigned /* alignSize */) -{ - return; -} - -/* -7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field. +// 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) { + if (!_useAlign) + return; pos += (unsigned)GetPos(); pos &= (alignSize - 1); if (pos == 0) @@ -500,11 +468,8 @@ void COutArchive::SkipAlign(unsigned pos, unsigned alignSize) for (unsigned i = 0; i < skip; i++) WriteByte(0); } -*/ - -static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; } -void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize) +void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize) { const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v); const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2; @@ -524,48 +489,53 @@ void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, B void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type) { - int numDefined = 0; + unsigned numDefined = 0; - int i; - for (i = 0; i < v.Defined.Size(); i++) - if (v.Defined[i]) + unsigned i; + for (i = 0; i < v.Defs.Size(); i++) + if (v.Defs[i]) numDefined++; if (numDefined == 0) return; - WriteAlignedBoolHeader(v.Defined, numDefined, type, 8); + WriteAlignedBoolHeader(v.Defs, numDefined, type, 8); - for (i = 0; i < v.Defined.Size(); i++) - if (v.Defined[i]) - WriteUInt64(v.Values[i]); + for (i = 0; i < v.Defs.Size(); i++) + if (v.Defs[i]) + WriteUInt64(v.Vals[i]); } HRESULT COutArchive::EncodeStream( DECL_EXTERNAL_CODECS_LOC_VARS CEncoder &encoder, const CByteBuffer &data, - CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders) + CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders, COutFolders &outFolders) { CBufInStream *streamSpec = new CBufInStream; CMyComPtr<ISequentialInStream> stream = streamSpec; - streamSpec->Init(data, data.GetCapacity()); - CFolder folderItem; - folderItem.UnpackCRCDefined = true; - folderItem.UnpackCRC = CrcCalc(data, data.GetCapacity()); - UInt64 dataSize64 = data.GetCapacity(); + streamSpec->Init(data, data.Size()); + outFolders.FolderUnpackCRCs.Defs.Add(true); + outFolders.FolderUnpackCRCs.Vals.Add(CrcCalc(data, data.Size())); + // outFolders.NumUnpackStreamsVector.Add(1); + UInt64 dataSize64 = data.Size(); + UInt64 unpackSize; RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS - stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL)) - folders.Add(folderItem); + stream, NULL, &dataSize64, folders.AddNew(), outFolders.CoderUnpackSizes, unpackSize, SeqStream, packSizes, NULL)) return S_OK; } void COutArchive::WriteHeader( - const CArchiveDatabase &db, - const CHeaderOptions &headerOptions, + const CArchiveDatabaseOut &db, + // const CHeaderOptions &headerOptions, UInt64 &headerOffset) { - int i; + /* + bool thereIsSecure = (db.SecureBuf.Size() != 0); + */ + _useAlign = true; + + unsigned i; UInt64 packedSize = 0; for (i = 0; i < db.PackSizes.Size(); i++) @@ -580,31 +550,22 @@ void COutArchive::WriteHeader( if (db.Folders.Size() > 0) { WriteByte(NID::kMainStreamsInfo); - WritePackInfo(0, db.PackSizes, - db.PackCRCsDefined, - db.PackCRCs); - - WriteUnpackInfo(db.Folders); + WritePackInfo(0, db.PackSizes, db.PackCRCs); + WriteUnpackInfo(db.Folders, (const COutFolders &)db); CRecordVector<UInt64> unpackSizes; - CRecordVector<bool> digestsDefined; - CRecordVector<UInt32> digests; + CUInt32DefVector digests; for (i = 0; i < db.Files.Size(); i++) { const CFileItem &file = db.Files[i]; if (!file.HasStream) continue; unpackSizes.Add(file.Size); - digestsDefined.Add(file.CrcDefined); - digests.Add(file.Crc); + digests.Defs.Add(file.CrcDefined); + digests.Vals.Add(file.Crc); } - WriteSubStreamsInfo( - db.Folders, - db.NumUnpackStreamsVector, - unpackSizes, - digestsDefined, - digests); + WriteSubStreamsInfo(db.Folders, (const COutFolders &)db, unpackSizes, digests); WriteByte(NID::kEnd); } @@ -618,85 +579,75 @@ void COutArchive::WriteHeader( WriteNumber(db.Files.Size()); { - /* ---------- Empty Streams ---------- */ - CBoolVector emptyStreamVector; - emptyStreamVector.Reserve(db.Files.Size()); - int numEmptyStreams = 0; - for (i = 0; i < db.Files.Size(); i++) - if (db.Files[i].HasStream) - emptyStreamVector.Add(false); - else - { - emptyStreamVector.Add(true); - numEmptyStreams++; - } - if (numEmptyStreams > 0) - { - WriteByte(NID::kEmptyStream); - WriteNumber(Bv_GetSizeInBytes(emptyStreamVector)); - WriteBoolVector(emptyStreamVector); - - CBoolVector emptyFileVector, antiVector; - emptyFileVector.Reserve(numEmptyStreams); - antiVector.Reserve(numEmptyStreams); - CNum numEmptyFiles = 0, numAntiItems = 0; + /* ---------- Empty Streams ---------- */ + CBoolVector emptyStreamVector; + emptyStreamVector.ClearAndSetSize(db.Files.Size()); + unsigned numEmptyStreams = 0; for (i = 0; i < db.Files.Size(); i++) + if (db.Files[i].HasStream) + emptyStreamVector[i] = false; + else + { + emptyStreamVector[i] = true; + numEmptyStreams++; + } + if (numEmptyStreams != 0) { - const CFileItem &file = db.Files[i]; - if (!file.HasStream) + WritePropBoolVector(NID::kEmptyStream, emptyStreamVector); + + CBoolVector emptyFileVector, antiVector; + emptyFileVector.ClearAndSetSize(numEmptyStreams); + antiVector.ClearAndSetSize(numEmptyStreams); + bool thereAreEmptyFiles = false, thereAreAntiItems = false; + unsigned cur = 0; + for (i = 0; i < db.Files.Size(); i++) { - emptyFileVector.Add(!file.IsDir); + const CFileItem &file = db.Files[i]; + if (file.HasStream) + continue; + emptyFileVector[cur] = !file.IsDir; if (!file.IsDir) - numEmptyFiles++; + thereAreEmptyFiles = true; bool isAnti = db.IsItemAnti(i); - antiVector.Add(isAnti); + antiVector[cur] = isAnti; if (isAnti) - numAntiItems++; + thereAreAntiItems = true; + cur++; } + + if (thereAreEmptyFiles) + WritePropBoolVector(NID::kEmptyFile, emptyFileVector); + if (thereAreAntiItems) + WritePropBoolVector(NID::kAnti, antiVector); } - - if (numEmptyFiles > 0) - { - WriteByte(NID::kEmptyFile); - WriteNumber(Bv_GetSizeInBytes(emptyFileVector)); - WriteBoolVector(emptyFileVector); - } - - if (numAntiItems > 0) - { - WriteByte(NID::kAnti); - WriteNumber(Bv_GetSizeInBytes(antiVector)); - WriteBoolVector(antiVector); - } - } } { /* ---------- Names ---------- */ - int numDefined = 0; + unsigned numDefined = 0; size_t namesDataSize = 0; - for (int i = 0; i < db.Files.Size(); i++) + FOR_VECTOR (i, db.Files) { - const UString &name = db.Files[i].Name; + const UString &name = db.Names[i]; if (!name.IsEmpty()) numDefined++; - namesDataSize += (name.Length() + 1) * 2; + namesDataSize += (name.Len() + 1) * 2; } if (numDefined > 0) { namesDataSize++; - SkipAlign(2 + GetBigNumberSize(namesDataSize), 2); + SkipAlign(2 + GetBigNumberSize(namesDataSize), 16); WriteByte(NID::kName); WriteNumber(namesDataSize); WriteByte(0); - for (int i = 0; i < db.Files.Size(); i++) + FOR_VECTOR (i, db.Files) { - const UString &name = db.Files[i].Name; - for (int t = 0; t <= name.Length(); t++) + const UString &name = db.Names[i]; + for (unsigned t = 0; t <= name.Len(); t++) { wchar_t c = name[t]; WriteByte((Byte)c); @@ -706,26 +657,26 @@ void COutArchive::WriteHeader( } } - if (headerOptions.WriteCTime) WriteUInt64DefVector(db.CTime, NID::kCTime); - if (headerOptions.WriteATime) WriteUInt64DefVector(db.ATime, NID::kATime); - if (headerOptions.WriteMTime) WriteUInt64DefVector(db.MTime, NID::kMTime); + /* if (headerOptions.WriteCTime) */ WriteUInt64DefVector(db.CTime, NID::kCTime); + /* if (headerOptions.WriteATime) */ WriteUInt64DefVector(db.ATime, NID::kATime); + /* if (headerOptions.WriteMTime) */ WriteUInt64DefVector(db.MTime, NID::kMTime); WriteUInt64DefVector(db.StartPos, NID::kStartPos); { /* ---------- Write Attrib ---------- */ CBoolVector boolVector; - boolVector.Reserve(db.Files.Size()); - int numDefined = 0; + boolVector.ClearAndSetSize(db.Files.Size()); + unsigned numDefined = 0; for (i = 0; i < db.Files.Size(); i++) { bool defined = db.Files[i].AttribDefined; - boolVector.Add(defined); + boolVector[i] = defined; if (defined) numDefined++; } - if (numDefined > 0) + if (numDefined != 0) { - WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttributes, 4); + WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttrib, 4); for (i = 0; i < db.Files.Size(); i++) { const CFileItem &file = db.Files[i]; @@ -735,13 +686,95 @@ 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); + } + } + + { + // ---------- Write Parent ---------- + CBoolVector boolVector; + boolVector.Reserve(db.Files.Size()); + unsigned numIsDir = 0; + unsigned numParentLinks = 0; + for (i = 0; i < db.Files.Size(); i++) + { + const CFileItem &file = db.Files[i]; + bool defined = !file.IsAltStream; + boolVector.Add(defined); + if (defined) + numIsDir++; + if (file.Parent >= 0) + numParentLinks++; + } + if (numParentLinks > 0) + { + // WriteAlignedBoolHeader(boolVector, numDefined, NID::kParent, 4); + 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); + + WriteByte(NID::kParent); + WriteNumber(dataSize); + if (numIsDir == boolVector.Size()) + WriteByte(1); + else + { + WriteByte(0); + WriteBoolVector(boolVector); + } + for (i = 0; i < db.Files.Size(); i++) + { + const CFileItem &file = db.Files[i]; + // if (file.Parent >= 0) + WriteUInt32(file.Parent); + } + } + } + + if (thereIsSecure) + { + UInt64 secureDataSize = 1 + 4 + + db.SecureBuf.Size() + + db.SecureSizes.Size() * 4; + // secureDataSize += db.SecureIDs.Size() * 4; + for (i = 0; i < db.SecureIDs.Size(); i++) + secureDataSize += GetBigNumberSize(db.SecureIDs[i]); + SkipAlign(2 + GetBigNumberSize(secureDataSize), 4); + WriteByte(NID::kNtSecure); + WriteNumber(secureDataSize); + WriteByte(0); + WriteUInt32(db.SecureSizes.Size()); + for (i = 0; i < db.SecureSizes.Size(); i++) + WriteUInt32(db.SecureSizes[i]); + WriteBytes(db.SecureBuf, db.SecureBuf.Size()); + for (i = 0; i < db.SecureIDs.Size(); i++) + { + WriteNumber(db.SecureIDs[i]); + // WriteUInt32(db.SecureIDs[i]); + } + } + */ + WriteByte(NID::kEnd); // for files WriteByte(NID::kEnd); // for headers } HRESULT COutArchive::WriteDatabase( DECL_EXTERNAL_CODECS_LOC_VARS - const CArchiveDatabase &db, + const CArchiveDatabaseOut &db, const CCompressionMethodMode *options, const CHeaderOptions &headerOptions) { @@ -773,17 +806,16 @@ HRESULT COutArchive::WriteDatabase( _countMode = encodeHeaders; _writeToStream = true; _countSize = 0; - WriteHeader(db, headerOptions, headerOffset); + WriteHeader(db, /* headerOptions, */ headerOffset); if (encodeHeaders) { - CByteBuffer buf; - buf.SetCapacity(_countSize); + CByteBuffer buf(_countSize); _outByte2.Init((Byte *)buf, _countSize); _countMode = false; _writeToStream = false; - WriteHeader(db, headerOptions, headerOffset); + WriteHeader(db, /* headerOptions, */ headerOffset); if (_countSize != _outByte2.GetPos()) return E_FAIL; @@ -794,10 +826,12 @@ HRESULT COutArchive::WriteDatabase( CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions); CRecordVector<UInt64> packSizes; CObjectVector<CFolder> folders; + COutFolders outFolders; + RINOK(EncodeStream( EXTERNAL_CODECS_LOC_VARS encoder, buf, - packSizes, folders)); + packSizes, folders, outFolders)); _writeToStream = true; @@ -805,11 +839,10 @@ HRESULT COutArchive::WriteDatabase( throw 1; WriteID(NID::kEncodedHeader); - WritePackInfo(headerOffset, packSizes, - CRecordVector<bool>(), CRecordVector<UInt32>()); - WriteUnpackInfo(folders); + WritePackInfo(headerOffset, packSizes, CUInt32DefVector()); + WriteUnpackInfo(folders, outFolders); WriteByte(NID::kEnd); - for (int i = 0; i < packSizes.Size(); i++) + FOR_VECTOR (i, packSizes) headerOffset += packSizes[i]; } RINOK(_outByte.Flush()); @@ -842,24 +875,28 @@ HRESULT COutArchive::WriteDatabase( } } -void CArchiveDatabase::GetFile(int index, CFileItem &file, CFileItem2 &file2) const +void CUInt64DefVector::SetItem(unsigned index, bool defined, UInt64 value) { - file = Files[index]; - file2.CTimeDefined = CTime.GetItem(index, file2.CTime); - file2.ATimeDefined = ATime.GetItem(index, file2.ATime); - file2.MTimeDefined = MTime.GetItem(index, file2.MTime); - file2.StartPosDefined = StartPos.GetItem(index, file2.StartPos); - file2.IsAnti = IsItemAnti(index); + while (index >= Defs.Size()) + Defs.Add(false); + Defs[index] = defined; + if (!defined) + return; + while (index >= Vals.Size()) + Vals.Add(0); + Vals[index] = value; } -void CArchiveDatabase::AddFile(const CFileItem &file, const CFileItem2 &file2) +void CArchiveDatabaseOut::AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name) { - int index = Files.Size(); + unsigned index = Files.Size(); CTime.SetItem(index, file2.CTimeDefined, file2.CTime); ATime.SetItem(index, file2.ATimeDefined, file2.ATime); MTime.SetItem(index, file2.MTimeDefined, file2.MTime); StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos); - SetItemAnti(index, file2.IsAnti); + SetItem_Anti(index, file2.IsAnti); + // SetItem_Aux(index, file2.IsAux); + Names.Add(name); Files.Add(file); } diff --git a/CPP/7zip/Archive/7z/7zOut.h b/CPP/7zip/Archive/7z/7zOut.h index 7b1b528e..cead4bce 100755..100644 --- a/CPP/7zip/Archive/7z/7zOut.h +++ b/CPP/7zip/Archive/7z/7zOut.h @@ -9,6 +9,7 @@ #include "7zItem.h" #include "../../Common/OutBuffer.h" +#include "../../Common/StreamUtils.h" namespace NArchive { namespace N7z { @@ -45,27 +46,191 @@ public: struct CHeaderOptions { bool CompressMainHeader; + /* bool WriteCTime; bool WriteATime; bool WriteMTime; + */ CHeaderOptions(): - CompressMainHeader(true), - WriteCTime(false), - WriteATime(false), - WriteMTime(true) + CompressMainHeader(true) + /* + , WriteCTime(false) + , WriteATime(false) + , WriteMTime(true) + */ {} }; + +struct CFileItem2 +{ + UInt64 CTime; + UInt64 ATime; + UInt64 MTime; + UInt64 StartPos; + bool CTimeDefined; + bool ATimeDefined; + bool MTimeDefined; + bool StartPosDefined; + bool IsAnti; + // bool IsAux; + + void Init() + { + CTimeDefined = false; + ATimeDefined = false; + MTimeDefined = false; + StartPosDefined = false; + IsAnti = false; + // IsAux = false; + } +}; + +struct COutFolders +{ + CUInt32DefVector FolderUnpackCRCs; // Now we use it for headers only. + + CRecordVector<CNum> NumUnpackStreamsVector; + CRecordVector<UInt64> CoderUnpackSizes; // including unpack sizes of bind coders + + void OutFoldersClear() + { + FolderUnpackCRCs.Clear(); + NumUnpackStreamsVector.Clear(); + CoderUnpackSizes.Clear(); + } + + void OutFoldersReserveDown() + { + FolderUnpackCRCs.ReserveDown(); + NumUnpackStreamsVector.ReserveDown(); + CoderUnpackSizes.ReserveDown(); + } +}; + +struct CArchiveDatabaseOut: public COutFolders +{ + CRecordVector<UInt64> PackSizes; + CUInt32DefVector PackCRCs; + CObjectVector<CFolder> Folders; + + CRecordVector<CFileItem> Files; + UStringVector Names; + CUInt64DefVector CTime; + CUInt64DefVector ATime; + CUInt64DefVector MTime; + CUInt64DefVector StartPos; + CRecordVector<bool> IsAnti; + + /* + CRecordVector<bool> IsAux; + + CByteBuffer SecureBuf; + CRecordVector<UInt32> SecureSizes; + CRecordVector<UInt32> SecureIDs; + + void ClearSecure() + { + SecureBuf.Free(); + SecureSizes.Clear(); + SecureIDs.Clear(); + } + */ + + void Clear() + { + OutFoldersClear(); + + PackSizes.Clear(); + PackCRCs.Clear(); + Folders.Clear(); + + Files.Clear(); + Names.Clear(); + CTime.Clear(); + ATime.Clear(); + MTime.Clear(); + StartPos.Clear(); + IsAnti.Clear(); + + /* + IsAux.Clear(); + ClearSecure(); + */ + } + + void ReserveDown() + { + OutFoldersReserveDown(); + + PackSizes.ReserveDown(); + PackCRCs.ReserveDown(); + Folders.ReserveDown(); + + Files.ReserveDown(); + Names.ReserveDown(); + CTime.ReserveDown(); + ATime.ReserveDown(); + MTime.ReserveDown(); + StartPos.ReserveDown(); + IsAnti.ReserveDown(); + + /* + IsAux.ReserveDown(); + */ + } + + bool IsEmpty() const + { + return ( + PackSizes.IsEmpty() && + NumUnpackStreamsVector.IsEmpty() && + Folders.IsEmpty() && + Files.IsEmpty()); + } + + bool CheckNumFiles() const + { + unsigned size = Files.Size(); + return ( + CTime.CheckSize(size) && + ATime.CheckSize(size) && + MTime.CheckSize(size) && + StartPos.CheckSize(size) && + (size == IsAnti.Size() || IsAnti.Size() == 0)); + } + + bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); } + // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); } + + void SetItem_Anti(unsigned index, bool isAnti) + { + while (index >= IsAnti.Size()) + IsAnti.Add(false); + IsAnti[index] = isAnti; + } + /* + void SetItem_Aux(unsigned index, bool isAux) + { + while (index >= IsAux.Size()) + IsAux.Add(false); + IsAux[index] = isAux; + } + */ + + void AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name); +}; + class COutArchive { UInt64 _prefixHeaderPos; - HRESULT WriteDirect(const void *data, UInt32 size); + HRESULT WriteDirect(const void *data, UInt32 size) { return WriteStream(SeqStream, data, size); } UInt64 GetPos() const; void WriteBytes(const void *data, size_t size); - void WriteBytes(const CByteBuffer &data) { WriteBytes(data, data.GetCapacity()); } + void WriteBytes(const CByteBuffer &data) { WriteBytes(data, data.Size()); } void WriteByte(Byte b); void WriteUInt32(UInt32 value); void WriteUInt64(UInt64 value); @@ -75,36 +240,36 @@ class COutArchive void WriteFolder(const CFolder &folder); HRESULT WriteFileHeader(const CFileItem &itemInfo); void WriteBoolVector(const CBoolVector &boolVector); - void WriteHashDigests( - const CRecordVector<bool> &digestsDefined, - const CRecordVector<UInt32> &hashDigests); + void WritePropBoolVector(Byte id, const CBoolVector &boolVector); + + void WriteHashDigests(const CUInt32DefVector &digests); void WritePackInfo( UInt64 dataOffset, const CRecordVector<UInt64> &packSizes, - const CRecordVector<bool> &packCRCsDefined, - const CRecordVector<UInt32> &packCRCs); + const CUInt32DefVector &packCRCs); - void WriteUnpackInfo(const CObjectVector<CFolder> &folders); + void WriteUnpackInfo( + const CObjectVector<CFolder> &folders, + const COutFolders &outFolders); void WriteSubStreamsInfo( const CObjectVector<CFolder> &folders, - const CRecordVector<CNum> &numUnpackStreamsInFolders, + const COutFolders &outFolders, const CRecordVector<UInt64> &unpackSizes, - const CRecordVector<bool> &digestsDefined, - const CRecordVector<UInt32> &hashDigests); + const CUInt32DefVector &digests); void SkipAlign(unsigned pos, unsigned alignSize); - void WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize); + void WriteAlignedBoolHeader(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSize); void WriteUInt64DefVector(const CUInt64DefVector &v, Byte type); HRESULT EncodeStream( DECL_EXTERNAL_CODECS_LOC_VARS CEncoder &encoder, const CByteBuffer &data, - CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders); + CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders, COutFolders &outFolders); void WriteHeader( - const CArchiveDatabase &db, - const CHeaderOptions &headerOptions, + const CArchiveDatabaseOut &db, + // const CHeaderOptions &headerOptions, UInt64 &headerOffset); bool _countMode; @@ -118,6 +283,8 @@ class COutArchive bool _endMarker; #endif + bool _useAlign; + HRESULT WriteSignature(); #ifdef _7Z_VOL HRESULT WriteFinishSignature(); @@ -136,7 +303,7 @@ public: HRESULT SkipPrefixArchiveHeader(); HRESULT WriteDatabase( DECL_EXTERNAL_CODECS_LOC_VARS - const CArchiveDatabase &db, + const CArchiveDatabaseOut &db, const CCompressionMethodMode *options, const CHeaderOptions &headerOptions); diff --git a/CPP/7zip/Archive/7z/7zProperties.cpp b/CPP/7zip/Archive/7z/7zProperties.cpp index fd4af49c..5ed36947 100755..100644 --- a/CPP/7zip/Archive/7z/7zProperties.cpp +++ b/CPP/7zip/Archive/7z/7zProperties.cpp @@ -17,7 +17,7 @@ struct CPropMap STATPROPSTG StatPROPSTG; }; -CPropMap kPropMap[] = +static const CPropMap kPropMap[] = { { NID::kName, { NULL, kpidPath, VT_BSTR } }, { NID::kSize, { NULL, kpidSize, VT_UI8 } }, @@ -34,11 +34,12 @@ CPropMap kPropMap[] = { NID::kCTime, { NULL, kpidCTime, VT_FILETIME } }, { NID::kMTime, { NULL, kpidMTime, VT_FILETIME } }, { NID::kATime, { NULL, kpidATime, VT_FILETIME } }, - { NID::kWinAttributes, { NULL, kpidAttrib, VT_UI4 } }, + { NID::kWinAttrib, { NULL, kpidAttrib, VT_UI4 } }, { NID::kStartPos, { NULL, kpidPosition, VT_UI4 } }, { NID::kCRC, { NULL, kpidCRC, VT_UI4 } }, +// { NID::kIsAux, { NULL, kpidIsAux, VT_BOOL } }, { NID::kAnti, { NULL, kpidIsAnti, VT_BOOL } } #ifndef _SFX @@ -49,11 +50,9 @@ CPropMap kPropMap[] = #endif }; -static const int kPropMapSize = sizeof(kPropMap) / sizeof(kPropMap[0]); - static int FindPropInMap(UInt64 filePropID) { - for (int i = 0; i < kPropMapSize; i++) + for (int i = 0; i < ARRAY_SIZE(kPropMap); i++) if (kPropMap[i].FilePropID == filePropID) return i; return -1; @@ -62,7 +61,7 @@ static int FindPropInMap(UInt64 filePropID) static void CopyOneItem(CRecordVector<UInt64> &src, CRecordVector<UInt64> &dest, UInt32 item) { - for (int i = 0; i < src.Size(); i++) + FOR_VECTOR (i, src) if (src[i] == item) { dest.Add(item); @@ -73,7 +72,7 @@ static void CopyOneItem(CRecordVector<UInt64> &src, static void RemoveOneItem(CRecordVector<UInt64> &src, UInt32 item) { - for (int i = 0; i < src.Size(); i++) + FOR_VECTOR (i, src) if (src[i] == item) { src.Delete(i); @@ -83,7 +82,7 @@ static void RemoveOneItem(CRecordVector<UInt64> &src, UInt32 item) static void InsertToHead(CRecordVector<UInt64> &dest, UInt32 item) { - for (int i = 0; i < dest.Size(); i++) + FOR_VECTOR (i, dest) if (dest[i] == item) { dest.Delete(i); @@ -92,6 +91,8 @@ static void InsertToHead(CRecordVector<UInt64> &dest, UInt32 item) dest.Insert(0, item); } +#define COPY_ONE_ITEM(id) CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::id); + void CHandler::FillPopIDs() { _fileInfoPopIDs.Clear(); @@ -103,21 +104,26 @@ void CHandler::FillPopIDs() const CArchiveDatabaseEx &_db = volume.Database; #endif - CRecordVector<UInt64> fileInfoPopIDs = _db.ArchiveInfo.FileInfoPopIDs; + CRecordVector<UInt64> fileInfoPopIDs = _db.ArcInfo.FileInfoPopIDs; RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream); RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile); + /* + RemoveOneItem(fileInfoPopIDs, NID::kParent); + RemoveOneItem(fileInfoPopIDs, NID::kNtSecure); + */ + + COPY_ONE_ITEM(kName); + COPY_ONE_ITEM(kAnti); + COPY_ONE_ITEM(kSize); + COPY_ONE_ITEM(kPackInfo); + COPY_ONE_ITEM(kCTime); + COPY_ONE_ITEM(kMTime); + COPY_ONE_ITEM(kATime); + COPY_ONE_ITEM(kWinAttrib); + COPY_ONE_ITEM(kCRC); + COPY_ONE_ITEM(kComment); - CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kName); - CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kAnti); - CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kSize); - CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kPackInfo); - CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCTime); - CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kMTime); - CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kATime); - CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kWinAttributes); - CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCRC); - CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kComment); _fileInfoPopIDs += fileInfoPopIDs; #ifndef _SFX @@ -141,9 +147,9 @@ void CHandler::FillPopIDs() #endif } -STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) +STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) { - *numProperties = _fileInfoPopIDs.Size(); + *numProps = _fileInfoPopIDs.Size(); return S_OK; } diff --git a/CPP/7zip/Archive/7z/7zProperties.h b/CPP/7zip/Archive/7z/7zProperties.h index 66181795..66181795 100755..100644 --- a/CPP/7zip/Archive/7z/7zProperties.h +++ b/CPP/7zip/Archive/7z/7zProperties.h diff --git a/CPP/7zip/Archive/7z/7zRegister.cpp b/CPP/7zip/Archive/7z/7zRegister.cpp index 6e9bf6b9..37ea29d3 100755..100644 --- a/CPP/7zip/Archive/7z/7zRegister.cpp +++ b/CPP/7zip/Archive/7z/7zRegister.cpp @@ -5,14 +5,21 @@ #include "../../Common/RegisterArc.h" #include "7zHandler.h" -static IInArchive *CreateArc() { return new NArchive::N7z::CHandler; } -#ifndef EXTRACT_ONLY -static IOutArchive *CreateArcOut() { return new NArchive::N7z::CHandler; } -#else -#define CreateArcOut 0 -#endif + +namespace NArchive { +namespace N7z { + +IMP_CreateArcIn +IMP_CreateArcOut static CArcInfo g_ArcInfo = - { L"7z", L"7z", 0, 7, {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}, 6, false, CreateArc, CreateArcOut }; + { "7z", "7z", 0, 7, + 6, {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C}, + 0, + NArcInfoFlags::kFindSignature, + REF_CreateArc_Pair }; + +REGISTER_ARC_DEC_SIG(7z) +// REGISTER_ARC(7z) -REGISTER_ARC(7z) +}} diff --git a/CPP/7zip/Archive/7z/7zSpecStream.cpp b/CPP/7zip/Archive/7z/7zSpecStream.cpp index 06969636..8e45d987 100755..100644 --- a/CPP/7zip/Archive/7z/7zSpecStream.cpp +++ b/CPP/7zip/Archive/7z/7zSpecStream.cpp @@ -9,16 +9,14 @@ STDMETHODIMP CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32 UInt32 realProcessedSize; HRESULT result = _stream->Read(data, size, &realProcessedSize); _size += realProcessedSize; - if (processedSize != 0) + if (processedSize) *processedSize = realProcessedSize; return result; } -STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize( - UInt64 subStream, UInt64 *value) +STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize(UInt64 subStream, UInt64 *value) { - if (_getSubStreamSize == NULL) + if (!_getSubStreamSize) return E_NOTIMPL; - return _getSubStreamSize->GetSubStreamSize(subStream, value); + return _getSubStreamSize->GetSubStreamSize(subStream, value); } - diff --git a/CPP/7zip/Archive/7z/7zSpecStream.h b/CPP/7zip/Archive/7z/7zSpecStream.h index 2e26efd5..2e26efd5 100755..100644 --- a/CPP/7zip/Archive/7z/7zSpecStream.h +++ b/CPP/7zip/Archive/7z/7zSpecStream.h diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp index e63b09d2..96befa23 100755..100644 --- a/CPP/7zip/Archive/7z/7zUpdate.cpp +++ b/CPP/7zip/Archive/7z/7zUpdate.cpp @@ -4,10 +4,11 @@ #include "../../../../C/CpuArch.h" -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" +#include "../../../Common/Wildcard.h" #include "../../Common/CreateCoder.h" +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" #include "../../Compress/CopyCoder.h" @@ -58,19 +59,20 @@ int CUpdateItem::GetExtensionPos() const int slashPos = GetReverseSlashPos(Name); int dotPos = Name.ReverseFind(L'.'); if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0)) - return Name.Length(); + return Name.Len(); return dotPos + 1; } UString CUpdateItem::GetExtension() const { - return Name.Mid(GetExtensionPos()); + return Name.Ptr(GetExtensionPos()); } #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } #define RINOZ_COMP(a, b) RINOZ(MyCompare(a, b)) +/* static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2) { size_t c1 = a1.GetCapacity(); @@ -110,11 +112,12 @@ static int CompareFolders(const CFolder &f1, const CFolder &f2) RINOZ(CompareBindPairs(f1.BindPairs[i], f2.BindPairs[i])); return 0; } +*/ /* static int CompareFiles(const CFileItem &f1, const CFileItem &f2) { - return MyStringCompareNoCase(f1.Name, f2.Name); + return CompareFileNames(f1.Name, f2.Name); } */ @@ -125,15 +128,19 @@ struct CFolderRepack CNum NumCopyFiles; }; -static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void *param) +static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void * /* param */) { RINOZ_COMP(p1->Group, p2->Group); int i1 = p1->FolderIndex; int i2 = p2->FolderIndex; - const CArchiveDatabaseEx &db = *(const CArchiveDatabaseEx *)param; + /* + // In that version we don't want to parse folders here, so we don't compare folders + // probably it must be improved in future + const CDbEx &db = *(const CDbEx *)param; RINOZ(CompareFolders( db.Folders[i1], db.Folders[i2])); + */ return MyCompare(i1, i2); /* RINOZ_COMP( @@ -147,25 +154,31 @@ static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2 */ } -//////////////////////////////////////////////////////////// +/* + we sort empty files and dirs in such order: + - Dir.NonAnti (name sorted) + - File.NonAnti (name sorted) + - File.Anti (name sorted) + - Dir.Anti (reverse name sorted) +*/ static int CompareEmptyItems(const int *p1, const int *p2, void *param) { const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param; const CUpdateItem &u1 = updateItems[*p1]; const CUpdateItem &u2 = updateItems[*p2]; + // NonAnti < Anti + if (u1.IsAnti != u2.IsAnti) + return (u1.IsAnti ? 1 : -1); if (u1.IsDir != u2.IsDir) - return (u1.IsDir) ? 1 : -1; - if (u1.IsDir) { - if (u1.IsAnti != u2.IsAnti) + // Dir.NonAnti < File < Dir.Anti + if (u1.IsDir) return (u1.IsAnti ? 1 : -1); - int n = MyStringCompareNoCase(u1.Name, u2.Name); - return -n; + return (u2.IsAnti ? -1 : 1); } - if (u1.IsAnti != u2.IsAnti) - return (u1.IsAnti ? 1 : -1); - return MyStringCompareNoCase(u1.Name, u2.Name); + int n = CompareFileNames(u1.Name, u2.Name); + return (u1.IsDir && u1.IsAnti) ? -n : n; } static const char *g_Exts = @@ -198,7 +211,7 @@ static const char *g_Exts = " exe dll ocx vbx sfx sys tlb awx com obj lib out o so " " pdb pch idb ncb opt"; -int GetExtIndex(const char *ext) +static int GetExtIndex(const char *ext) { int extIndex = 1; const char *p = g_Exts; @@ -237,7 +250,9 @@ struct CRefItem UInt32 Index; UInt32 ExtensionPos; UInt32 NamePos; - int ExtensionIndex; + unsigned ExtensionIndex; + + CRefItem() {}; CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType): UpdateItem(&ui), Index(index), @@ -248,64 +263,134 @@ struct CRefItem if (sortByType) { int slashPos = GetReverseSlashPos(ui.Name); - NamePos = ((slashPos >= 0) ? (slashPos + 1) : 0); + NamePos = slashPos + 1; int dotPos = ui.Name.ReverseFind(L'.'); - if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0)) - ExtensionPos = ui.Name.Length(); + if (dotPos < 0 || dotPos < slashPos) + ExtensionPos = ui.Name.Len(); else { ExtensionPos = dotPos + 1; - UString us = ui.Name.Mid(ExtensionPos); - if (!us.IsEmpty()) + if (ExtensionPos != ui.Name.Len()) { - us.MakeLower(); - int i; AString s; - for (i = 0; i < us.Length(); i++) + for (unsigned pos = ExtensionPos;; pos++) { - wchar_t c = us[i]; + wchar_t c = ui.Name[pos]; if (c >= 0x80) break; - s += (char)c; + if (c == 0) + { + ExtensionIndex = GetExtIndex(s); + break; + } + s += (char)MyCharLower_Ascii((char)c); } - if (i == us.Length()) - ExtensionIndex = GetExtIndex(s); - else - ExtensionIndex = 0; } } } } }; +struct CSortParam +{ + // const CObjectVector<CTreeFolder> *TreeFolders; + bool SortByType; +}; + +/* + we sort files in such order: + - Dir.NonAnti (name sorted) + - alt streams + - Dirs + - Dir.Anti (reverse name sorted) +*/ + + static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param) { const CRefItem &a1 = *p1; const CRefItem &a2 = *p2; const CUpdateItem &u1 = *a1.UpdateItem; const CUpdateItem &u2 = *a2.UpdateItem; - int n; + + /* + if (u1.IsAltStream != u2.IsAltStream) + return u1.IsAltStream ? 1 : -1; + */ + + // Actually there are no dirs that time. They were stored in other steps + // So that code is unused? if (u1.IsDir != u2.IsDir) - return (u1.IsDir) ? 1 : -1; + return u1.IsDir ? 1 : -1; if (u1.IsDir) { if (u1.IsAnti != u2.IsAnti) return (u1.IsAnti ? 1 : -1); - n = MyStringCompareNoCase(u1.Name, u2.Name); + int n = CompareFileNames(u1.Name, u2.Name); return -n; } - bool sortByType = *(bool *)param; + + // bool sortByType = *(bool *)param; + const CSortParam *sortParam = (const CSortParam *)param; + bool sortByType = sortParam->SortByType; if (sortByType) { RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex); - RINOZ(MyStringCompareNoCase(u1.Name + a1.ExtensionPos, u2.Name + a2.ExtensionPos)); - RINOZ(MyStringCompareNoCase(u1.Name + a1.NamePos, u2.Name + a2.NamePos)); + RINOZ(CompareFileNames(u1.Name.Ptr(a1.ExtensionPos), u2.Name.Ptr(a2.ExtensionPos))); + RINOZ(CompareFileNames(u1.Name.Ptr(a1.NamePos), u2.Name.Ptr(a2.NamePos))); if (!u1.MTimeDefined && u2.MTimeDefined) return 1; if (u1.MTimeDefined && !u2.MTimeDefined) return -1; if (u1.MTimeDefined && u2.MTimeDefined) RINOZ_COMP(u1.MTime, u2.MTime); RINOZ_COMP(u1.Size, u2.Size); } - return MyStringCompareNoCase(u1.Name, u2.Name); + /* + int par1 = a1.UpdateItem->ParentFolderIndex; + int par2 = a2.UpdateItem->ParentFolderIndex; + const CTreeFolder &tf1 = (*sortParam->TreeFolders)[par1]; + const CTreeFolder &tf2 = (*sortParam->TreeFolders)[par2]; + + int b1 = tf1.SortIndex, e1 = tf1.SortIndexEnd; + int b2 = tf2.SortIndex, e2 = tf2.SortIndexEnd; + if (b1 < b2) + { + if (e1 <= b2) + return -1; + // p2 in p1 + int par = par2; + for (;;) + { + const CTreeFolder &tf = (*sortParam->TreeFolders)[par]; + par = tf.Parent; + if (par == par1) + { + RINOZ(CompareFileNames(u1.Name, tf.Name)); + break; + } + } + } + else if (b2 < b1) + { + if (e2 <= b1) + return 1; + // p1 in p2 + int par = par1; + for (;;) + { + const CTreeFolder &tf = (*sortParam->TreeFolders)[par]; + par = tf.Parent; + if (par == par2) + { + RINOZ(CompareFileNames(tf.Name, u2.Name)); + break; + } + } + } + */ + // RINOZ_COMP(a1.UpdateItem->ParentSortIndex, a2.UpdateItem->ParentSortIndex); + RINOK(CompareFileNames(u1.Name, u2.Name)); + RINOZ_COMP(a1.UpdateItem->IndexInClient, a2.UpdateItem->IndexInClient); + RINOZ_COMP(a1.UpdateItem->IndexInArchive, a2.UpdateItem->IndexInArchive); + return 0; } struct CSolidGroup @@ -313,19 +398,19 @@ struct CSolidGroup CRecordVector<UInt32> Indices; }; -static wchar_t *g_ExeExts[] = +static const wchar_t *g_ExeExts[] = { - L"dll", - L"exe", - L"ocx", - L"sfx", - L"sys" + L"dll" + , L"exe" + , L"ocx" + , L"sfx" + , L"sys" }; -static bool IsExeExt(const UString &ext) +static bool IsExeExt(const wchar_t *ext) { - for (int i = 0; i < sizeof(g_ExeExts) / sizeof(g_ExeExts[0]); i++) - if (ext.CompareNoCase(g_ExeExts[i]) == 0) + for (int i = 0; i < ARRAY_SIZE(g_ExeExts); i++) + if (MyStringCompareNoCase(ext, g_ExeExts[i]) == 0) return true; return false; } @@ -402,7 +487,6 @@ static void MakeExeMethod(CCompressionMethodMode &mode, static void FromUpdateItemToFileItem(const CUpdateItem &ui, CFileItem &file, CFileItem2 &file2) { - file.Name = NItemName::MakeLegalName(ui.Name); if (ui.AttribDefined) file.SetAttrib(ui.Attrib); @@ -410,11 +494,13 @@ static void FromUpdateItemToFileItem(const CUpdateItem &ui, 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; file.Size = ui.Size; file.IsDir = ui.IsDir; file.HasStream = ui.HasStream(); + // file.IsAltStream = ui.IsAltStream; } class CFolderOutStream2: @@ -423,11 +509,11 @@ class CFolderOutStream2: { COutStreamWithCRC *_crcStreamSpec; CMyComPtr<ISequentialOutStream> _crcStream; - const CArchiveDatabaseEx *_db; + const CDbEx *_db; const CBoolVector *_extractStatuses; CMyComPtr<ISequentialOutStream> _outStream; UInt32 _startIndex; - int _currentIndex; + unsigned _currentIndex; bool _fileIsOpen; UInt64 _rem; @@ -444,7 +530,7 @@ public: _crcStream = _crcStreamSpec; } - HRESULT Init(const CArchiveDatabaseEx *db, UInt32 startIndex, + HRESULT Init(const CDbEx *db, UInt32 startIndex, const CBoolVector *extractStatuses, ISequentialOutStream *outStream); void ReleaseOutStream(); HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; } @@ -452,7 +538,7 @@ public: STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; -HRESULT CFolderOutStream2::Init(const CArchiveDatabaseEx *db, UInt32 startIndex, +HRESULT CFolderOutStream2::Init(const CDbEx *db, UInt32 startIndex, const CBoolVector *extractStatuses, ISequentialOutStream *outStream) { _db = db; @@ -551,13 +637,13 @@ public: CMyComPtr<ISequentialOutStream> Fos; UInt64 StartPos; - const UInt64 *PackSizes; - const CFolder *Folder; + const CFolders *Folders; + int FolderIndex; #ifndef _NO_CRYPTO - CMyComPtr<ICryptoGetTextPassword> GetTextPassword; + CMyComPtr<ICryptoGetTextPassword> getTextPassword; #endif - DECL_EXTERNAL_CODECS_VARS + DECL_EXTERNAL_CODECS_LOC_VARS2; CDecoder Decoder; #ifndef _7ZIP_ST @@ -585,21 +671,20 @@ void CThreadDecoder::Execute() try { #ifndef _NO_CRYPTO - bool passwordIsDefined; + bool isEncrypted = false; + bool passwordIsDefined = false; #endif + Result = Decoder.Decode( - EXTERNAL_CODECS_VARS + EXTERNAL_CODECS_LOC_VARS InStream, StartPos, - PackSizes, - *Folder, + *Folders, FolderIndex, Fos, NULL - #ifndef _NO_CRYPTO - , GetTextPassword, passwordIsDefined - #endif + _7Z_DECODER_CRYPRO_VARS #ifndef _7ZIP_ST - , MtMode, NumThreads + , MtMode, NumThreads #endif ); } @@ -614,7 +699,7 @@ void CThreadDecoder::Execute() bool static Is86FilteredFolder(const CFolder &f) { - for (int i = 0; i < f.Coders.Size(); i++) + FOR_VECTOR(i, f.Coders) { CMethodId m = f.Coders[i].MethodID; if (m == k_BCJ || m == k_BCJ2) @@ -650,13 +735,26 @@ static bool IsEncryptedGroup(int group) { return (group & 2) != 0; } static int GetGroupIndex(bool encrypted, int bcjFiltered) { return (encrypted ? 2 : 0) + (bcjFiltered ? 1 : 0); } +static void GetFile(const CDatabase &inDb, int index, CFileItem &file, CFileItem2 &file2) +{ + file = inDb.Files[index]; + file2.CTimeDefined = inDb.CTime.GetItem(index, file2.CTime); + 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.IsAnti = inDb.IsItemAnti(index); + // file2.IsAux = inDb.IsItemAux(index); +} + HRESULT Update( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, - const CArchiveDatabaseEx *db, + const CDbEx *db, const CObjectVector<CUpdateItem> &updateItems, + // const CObjectVector<CTreeFolder> &treeFolders, + // const CUniqBlocks &secureBlocks, COutArchive &archive, - CArchiveDatabase &newDatabase, + CArchiveDatabaseOut &newDatabase, ISequentialOutStream *seqOutStream, IArchiveUpdateCallback *updateCallback, const CUpdateOptions &options @@ -668,6 +766,9 @@ HRESULT Update( UInt64 numSolidFiles = options.NumSolidFiles; if (numSolidFiles == 0) numSolidFiles = 1; + + // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes(); + /* CMyComPtr<IOutStream> outStream; RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream)); @@ -675,23 +776,23 @@ HRESULT Update( return E_NOTIMPL; */ - UInt64 startBlockSize = db != 0 ? db->ArchiveInfo.StartPosition: 0; + UInt64 startBlockSize = db != 0 ? db->ArcInfo.StartPosition: 0; if (startBlockSize > 0 && !options.RemoveSfxBlock) { RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL)); } - CRecordVector<int> fileIndexToUpdateIndexMap; + CIntArr fileIndexToUpdateIndexMap; CRecordVector<CFolderRepack> folderRefs; UInt64 complexity = 0; UInt64 inSizeForReduce2 = 0; bool needEncryptedRepack = false; if (db != 0) { - fileIndexToUpdateIndexMap.Reserve(db->Files.Size()); - int i; + fileIndexToUpdateIndexMap.Alloc(db->Files.Size()); + unsigned i; for (i = 0; i < db->Files.Size(); i++) - fileIndexToUpdateIndexMap.Add(-1); + fileIndexToUpdateIndexMap[i] = -1; for (i = 0; i < updateItems.Size(); i++) { @@ -700,7 +801,7 @@ HRESULT Update( fileIndexToUpdateIndexMap[index] = i; } - for (i = 0; i < db->Folders.Size(); i++) + for (i = 0; i < (int)db->NumFolders; i++) { CNum indexInFolder = 0; CNum numCopyItems = 0; @@ -727,7 +828,8 @@ HRESULT Update( CFolderRepack rep; rep.FolderIndex = i; rep.NumCopyFiles = numCopyItems; - const CFolder &f = db->Folders[i]; + CFolder f; + db->ParseFolderInfo(i, f); bool isEncrypted = f.IsEncrypted(); rep.Group = GetGroupIndex(isEncrypted, Is86FilteredFolder(f)); folderRefs.Add(rep); @@ -746,7 +848,7 @@ HRESULT Update( } UInt64 inSizeForReduce = 0; - int i; + unsigned i; for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; @@ -776,18 +878,17 @@ HRESULT Update( if (!folderRefs.IsEmpty()) { #ifdef EXTERNAL_CODECS - threadDecoder._codecsInfo = codecsInfo; - threadDecoder._externalCodecs = *externalCodecs; + threadDecoder.__externalCodecs = __externalCodecs; #endif RINOK(threadDecoder.Create()); } CObjectVector<CSolidGroup> groups; for (i = 0; i < kNumGroupsMax; i++) - groups.Add(CSolidGroup()); + groups.AddNew(); { - // ---------- Split files to 2 groups ---------- + // ---------- Split files to groups ---------- bool useFilters = options.UseFilters; const CCompressionMethodMode &method = *options.Method; @@ -803,7 +904,7 @@ HRESULT Update( { int dotPos = ui.Name.ReverseFind(L'.'); if (dotPos >= 0) - filteredGroup = IsExeExt(ui.Name.Mid(dotPos + 1)); + filteredGroup = IsExeExt(ui.Name.Ptr(dotPos + 1)); } groups[GetGroupIndex(method.PasswordIsDefined, filteredGroup)].Indices.Add(i); } @@ -815,7 +916,7 @@ HRESULT Update( if (needEncryptedRepack) { getPasswordSpec = new CCryptoGetTextPassword; - threadDecoder.GetTextPassword = getPasswordSpec; + threadDecoder.getTextPassword = getPasswordSpec; if (options.Method->PasswordIsDefined) getPasswordSpec->Password = options.Method->Password; @@ -825,18 +926,111 @@ HRESULT Update( return E_NOTIMPL; CMyComBSTR password; RINOK(getDecoderPassword->CryptoGetTextPassword(&password)); - getPasswordSpec->Password = password; + if ((BSTR)password) + getPasswordSpec->Password = password; } } #endif + // ---------- Compress ---------- RINOK(archive.Create(seqOutStream, false)); RINOK(archive.SkipPrefixArchiveHeader()); - int folderRefIndex = 0; + /* + CIntVector treeFolderToArcIndex; + treeFolderToArcIndex.Reserve(treeFolders.Size()); + for (i = 0; i < treeFolders.Size(); i++) + treeFolderToArcIndex.Add(-1); + // ---------- Write Tree (only AUX dirs) ---------- + for (i = 1; i < treeFolders.Size(); i++) + { + const CTreeFolder &treeFolder = treeFolders[i]; + CFileItem file; + CFileItem2 file2; + file2.Init(); + int secureID = 0; + if (treeFolder.UpdateItemIndex < 0) + { + // we can store virtual dir item wuthout attrib, but we want all items have attrib. + file.SetAttrib(FILE_ATTRIBUTE_DIRECTORY); + file2.IsAux = true; + } + else + { + const CUpdateItem &ui = updateItems[treeFolder.UpdateItemIndex]; + // if item is not dir, then it's parent for alt streams. + // we will write such items later + if (!ui.IsDir) + continue; + secureID = ui.SecureIndex; + if (ui.NewProps) + FromUpdateItemToFileItem(ui, file, file2); + else + GetFile(*db, ui.IndexInArchive, file, file2); + } + file.Size = 0; + file.HasStream = false; + file.IsDir = true; + file.Parent = treeFolder.Parent; + + treeFolderToArcIndex[i] = newDatabase.Files.Size(); + newDatabase.AddFile(file, file2, treeFolder.Name); + + if (totalSecureDataSize != 0) + newDatabase.SecureIDs.Add(secureID); + } + */ + + { + /* ---------- Write non-AUX dirs and Empty files ---------- */ + CRecordVector<int> emptyRefs; + for (i = 0; i < updateItems.Size(); i++) + { + const CUpdateItem &ui = updateItems[i]; + if (ui.NewData) + { + if (ui.HasStream()) + continue; + } + else if (ui.IndexInArchive != -1 && db->Files[ui.IndexInArchive].HasStream) + continue; + /* + if (ui.TreeFolderIndex >= 0) + continue; + */ + emptyRefs.Add(i); + } + emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems); + for (i = 0; i < emptyRefs.Size(); i++) + { + const CUpdateItem &ui = updateItems[emptyRefs[i]]; + CFileItem file; + CFileItem2 file2; + UString name; + if (ui.NewProps) + { + FromUpdateItemToFileItem(ui, file, file2); + name = ui.Name; + } + else + { + GetFile(*db, ui.IndexInArchive, file, file2); + name = db->GetName(ui.IndexInArchive); + } + + /* + if (totalSecureDataSize != 0) + newDatabase.SecureIDs.Add(ui.SecureIndex); + file.Parent = ui.ParentFolderIndex; + */ + newDatabase.AddFile(file, file2, name); + } + } + + unsigned folderRefIndex = 0; lps->ProgressOffset = 0; for (int groupIndex = 0; groupIndex < kNumGroupsMax; groupIndex++) @@ -879,15 +1073,20 @@ HRESULT Update( db->GetFolderStreamPos(folderIndex, 0), packSize, progress)); lps->ProgressOffset += packSize; - const CFolder &folder = db->Folders[folderIndex]; - CNum startIndex = db->FolderStartPackStreamIndex[folderIndex]; - for (int j = 0; j < folder.PackStreams.Size(); j++) + CFolder &folder = newDatabase.Folders.AddNew(); + db->ParseFolderInfo(folderIndex, folder); + CNum startIndex = db->FoStartPackStreamIndex[folderIndex]; + for (unsigned j = 0; j < folder.PackStreams.Size(); j++) { - newDatabase.PackSizes.Add(db->PackSizes[startIndex + j]); + newDatabase.PackSizes.Add(db->GetStreamPackSize(startIndex + j)); // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]); // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]); } - newDatabase.Folders.Add(folder); + + UInt32 indexStart = db->FoToCoderUnpackSizes[folderIndex]; + UInt32 indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1]; + for (; indexStart < indexEnd; indexStart++) + newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes[indexStart]); } else { @@ -909,8 +1108,8 @@ HRESULT Update( extractStatuses.Add(needExtract); } - int startPackIndex = newDatabase.PackSizes.Size(); - CFolder newFolder; + unsigned startPackIndex = newDatabase.PackSizes.Size(); + UInt64 curUnpackSize; { CMyComPtr<ISequentialInStream> sbInStream; { @@ -921,16 +1120,17 @@ HRESULT Update( } threadDecoder.InStream = inStream; - threadDecoder.Folder = &db->Folders[folderIndex]; - threadDecoder.StartPos = db->GetFolderStreamPos(folderIndex, 0); - threadDecoder.PackSizes = &db->PackSizes[db->FolderStartPackStreamIndex[folderIndex]]; + threadDecoder.Folders = (const CFolders *)db; + threadDecoder.FolderIndex = folderIndex; + threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0); threadDecoder.Start(); RINOK(encoder.Encode( - EXTERNAL_CODECS_LOC_VARS - sbInStream, NULL, &inSizeForReduce, newFolder, - archive.SeqStream, newDatabase.PackSizes, progress)); + EXTERNAL_CODECS_LOC_VARS + sbInStream, NULL, &inSizeForReduce, + newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curUnpackSize, + archive.SeqStream, newDatabase.PackSizes, progress)); threadDecoder.WaitExecuteFinish(); } @@ -939,9 +1139,7 @@ HRESULT Update( for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) lps->OutSize += newDatabase.PackSizes[startPackIndex]; - lps->InSize += newFolder.GetUnpackSize(); - - newDatabase.Folders.Add(newFolder); + lps->InSize += curUnpackSize; } newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles); @@ -953,7 +1151,8 @@ HRESULT Update( { CFileItem file; CFileItem2 file2; - db->GetFile(fi, file, file2); + GetFile(*db, fi, file, file2); + UString name = db->GetName(fi); if (file.HasStream) { indexInFolder++; @@ -972,30 +1171,40 @@ HRESULT Update( uf.CrcDefined = file.CrcDefined; uf.HasStream = file.HasStream; file = uf; + name = ui.Name; } - newDatabase.AddFile(file, file2); + /* + file.Parent = ui.ParentFolderIndex; + if (ui.TreeFolderIndex >= 0) + treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size(); + if (totalSecureDataSize != 0) + newDatabase.SecureIDs.Add(ui.SecureIndex); + */ + newDatabase.AddFile(file, file2, name); } } } } - int numFiles = group.Indices.Size(); + unsigned numFiles = group.Indices.Size(); if (numFiles == 0) continue; CRecordVector<CRefItem> refItems; - refItems.Reserve(numFiles); + refItems.ClearAndSetSize(numFiles); bool sortByType = (numSolidFiles > 1); for (i = 0; i < numFiles; i++) - refItems.Add(CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType)); - refItems.Sort(CompareUpdateItems, (void *)&sortByType); + refItems[i] = CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType); + CSortParam sortParam; + // sortParam.TreeFolders = &treeFolders; + sortParam.SortByType = sortByType; + refItems.Sort(CompareUpdateItems, (void *)&sortParam); - CRecordVector<UInt32> indices; - indices.Reserve(numFiles); + CObjArray<UInt32> indices(numFiles); for (i = 0; i < numFiles; i++) { UInt32 index = refItems[i].Index; - indices.Add(index); + indices[i] = index; /* const CUpdateItem &ui = updateItems[index]; CFileItem file; @@ -1027,7 +1236,7 @@ HRESULT Update( if (numSubFiles == 0) prevExtension = ext; else - if (ext.CompareNoCase(prevExtension) != 0) + if (!ext.IsEqualToNoCase(prevExtension)) break; } } @@ -1038,34 +1247,39 @@ HRESULT Update( CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec); inStreamSpec->Init(updateCallback, &indices[i], numSubFiles); - CFolder folderItem; - - int startPackIndex = newDatabase.PackSizes.Size(); + unsigned startPackIndex = newDatabase.PackSizes.Size(); + UInt64 curFolderUnpackSize; RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS - solidInStream, NULL, &inSizeForReduce, folderItem, + solidInStream, NULL, &inSizeForReduce, + newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curFolderUnpackSize, archive.SeqStream, newDatabase.PackSizes, progress)); for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) lps->OutSize += newDatabase.PackSizes[startPackIndex]; - lps->InSize += folderItem.GetUnpackSize(); + lps->InSize += curFolderUnpackSize; // for () // newDatabase.PackCRCsDefined.Add(false); // newDatabase.PackCRCs.Add(0); - newDatabase.Folders.Add(folderItem); - CNum numUnpackStreams = 0; for (int subIndex = 0; subIndex < numSubFiles; subIndex++) { const CUpdateItem &ui = updateItems[indices[i + subIndex]]; CFileItem file; CFileItem2 file2; + UString name; if (ui.NewProps) + { FromUpdateItemToFileItem(ui, file, file2); + name = ui.Name; + } else - db->GetFile(ui.IndexInArchive, file, file2); + { + GetFile(*db, ui.IndexInArchive, file, file2); + name = db->GetName(ui.IndexInArchive); + } if (file2.IsAnti || file.IsDir) return E_FAIL; @@ -1092,7 +1306,14 @@ HRESULT Update( file.CrcDefined = false; file.HasStream = false; } - newDatabase.AddFile(file, file2); + /* + file.Parent = ui.ParentFolderIndex; + if (ui.TreeFolderIndex >= 0) + treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size(); + if (totalSecureDataSize != 0) + newDatabase.SecureIDs.Add(ui.SecureIndex); + */ + newDatabase.AddFile(file, file2, name); } // numUnpackStreams = 0 is very bad case for locked files // v3.13 doesn't understand it. @@ -1112,36 +1333,28 @@ HRESULT Update( groups.ClearAndFree(); */ + /* + for (i = 0; i < newDatabase.Files.Size(); i++) { - // ---------- Write Folders & Empty Files ---------- - - CRecordVector<int> emptyRefs; - for (i = 0; i < updateItems.Size(); i++) - { - const CUpdateItem &ui = updateItems[i]; - if (ui.NewData) - { - if (ui.HasStream()) - continue; - } - else if (ui.IndexInArchive != -1 && db->Files[ui.IndexInArchive].HasStream) - continue; - emptyRefs.Add(i); - } - emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems); - for (i = 0; i < emptyRefs.Size(); i++) + CFileItem &file = newDatabase.Files[i]; + file.Parent = treeFolderToArcIndex[file.Parent]; + } + + if (totalSecureDataSize != 0) + { + newDatabase.SecureBuf.SetCapacity(totalSecureDataSize); + size_t pos = 0; + newDatabase.SecureSizes.Reserve(secureBlocks.Sorted.Size()); + for (i = 0; i < secureBlocks.Sorted.Size(); i++) { - const CUpdateItem &ui = updateItems[emptyRefs[i]]; - CFileItem file; - CFileItem2 file2; - if (ui.NewProps) - FromUpdateItemToFileItem(ui, file, file2); - else - db->GetFile(ui.IndexInArchive, file, file2); - newDatabase.AddFile(file, file2); + const CByteBuffer &buf = secureBlocks.Bufs[secureBlocks.Sorted[i]]; + size_t size = buf.GetCapacity(); + memcpy(newDatabase.SecureBuf + pos, buf, size); + newDatabase.SecureSizes.Add((UInt32)size); + pos += size; } } - + */ newDatabase.ReserveDown(); return S_OK; } diff --git a/CPP/7zip/Archive/7z/7zUpdate.h b/CPP/7zip/Archive/7z/7zUpdate.h index 31e36224..d00276e0 100755..100644 --- a/CPP/7zip/Archive/7z/7zUpdate.h +++ b/CPP/7zip/Archive/7z/7zUpdate.h @@ -3,15 +3,31 @@ #ifndef __7Z_UPDATE_H #define __7Z_UPDATE_H +#include "../IArchive.h" + +// #include "../../Common/UniqBlocks.h" + #include "7zCompressionMode.h" #include "7zIn.h" #include "7zOut.h" -#include "../IArchive.h" - namespace NArchive { namespace N7z { +/* +struct CTreeFolder +{ + UString Name; + int Parent; + CIntVector SubFolders; + int UpdateItemIndex; + int SortIndex; + int SortIndexEnd; + + CTreeFolder(): UpdateItemIndex(-1) {} +}; +*/ + struct CUpdateItem { int IndexInArchive; @@ -23,6 +39,15 @@ struct CUpdateItem UInt64 Size; UString Name; + /* + bool IsAltStream; + int ParentFolderIndex; + int TreeFolderIndex; + */ + + // that code is not used in 9.26 + // int ParentSortIndex; + // int ParentSortIndexEnd; UInt32 Attrib; @@ -37,15 +62,20 @@ struct CUpdateItem bool ATimeDefined; bool MTimeDefined; + // int SecureIndex; // 0 means (no_security) + bool HasStream() const { return !IsDir && !IsAnti && Size != 0; } CUpdateItem(): + // ParentSortIndex(-1), + // IsAltStream(false), IsAnti(false), IsDir(false), AttribDefined(false), CTimeDefined(false), ATimeDefined(false), MTimeDefined(false) + // SecureIndex(0) {} void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); }; @@ -72,10 +102,12 @@ struct CUpdateOptions HRESULT Update( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, - const CArchiveDatabaseEx *db, + const CDbEx *db, const CObjectVector<CUpdateItem> &updateItems, + // const CObjectVector<CTreeFolder> &treeFolders, // treeFolders[0] is root + // const CUniqBlocks &secureBlocks, COutArchive &archive, - CArchiveDatabase &newDatabase, + CArchiveDatabaseOut &newDatabase, ISequentialOutStream *seqOutStream, IArchiveUpdateCallback *updateCallback, const CUpdateOptions &options diff --git a/CPP/7zip/Archive/7z/StdAfx.cpp b/CPP/7zip/Archive/7z/StdAfx.cpp index d0feea85..d0feea85 100755..100644 --- a/CPP/7zip/Archive/7z/StdAfx.cpp +++ b/CPP/7zip/Archive/7z/StdAfx.cpp diff --git a/CPP/7zip/Archive/7z/StdAfx.h b/CPP/7zip/Archive/7z/StdAfx.h index 2e4be10b..2854ff3e 100755..100644 --- a/CPP/7zip/Archive/7z/StdAfx.h +++ b/CPP/7zip/Archive/7z/StdAfx.h @@ -3,7 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" -#include "../../../Common/NewHandler.h" +#include "../../../Common/Common.h" #endif diff --git a/CPP/7zip/Archive/7z/makefile b/CPP/7zip/Archive/7z/makefile index 0abb3756..19982112 100755..100644 --- a/CPP/7zip/Archive/7z/makefile +++ b/CPP/7zip/Archive/7z/makefile @@ -1,6 +1,6 @@ PROG = 7z.dll -DEF_FILE = ../Archive.def -CFLAGS = $(CFLAGS) -I ../../../ \ +DEF_FILE = ../../Archive/Archive2.def +CFLAGS = $(CFLAGS) \ -DEXTERNAL_CODECS \ AR_OBJS = \ @@ -32,12 +32,14 @@ COMMON_OBJS = \ $O\StringConvert.obj \ $O\StringToInt.obj \ $O\MyVector.obj \ + $O\Wildcard.obj \ WIN_OBJS = \ $O\DLL.obj \ $O\FileDir.obj \ $O\FileFind.obj \ $O\FileIO.obj \ + $O\FileName.obj \ $O\PropVariant.obj \ $O\Synchronization.obj \ $O\System.obj \ @@ -52,6 +54,7 @@ WIN_OBJS = \ $O\MethodProps.obj \ $O\OutBuffer.obj \ $O\ProgressUtils.obj \ + $O\PropId.obj \ $O\StreamBinder.obj \ $O\StreamObjects.obj \ $O\StreamUtils.obj \ @@ -73,38 +76,4 @@ C_OBJS = \ $O\CpuArch.obj \ $O\Threads.obj \ -!include "../../Crc.mak" - -OBJS = \ - $O\StdAfx.obj \ - $(AR_OBJS) \ - $(7Z_OBJS) \ - $(COMMON_OBJS) \ - $(WIN_OBJS) \ - $(7ZIP_COMMON_OBJS) \ - $(AR_COMMON_OBJS) \ - $O\CopyCoder.obj \ - $(C_OBJS) \ - $(ASM_OBJS) \ - $O\resource.res - -!include "../../../Build.mak" - -$(AR_OBJS): ../$(*B).cpp - $(COMPL) -$(7Z_OBJS): $(*B).cpp - $(COMPL) -$(COMMON_OBJS): ../../../Common/$(*B).cpp - $(COMPL) -$(WIN_OBJS): ../../../Windows/$(*B).cpp - $(COMPL) -$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp - $(COMPL) -$(AR_COMMON_OBJS): ../Common/$(*B).cpp - $(COMPL) -$O\CopyCoder.obj: ../../Compress/$(*B).cpp - $(COMPL) -$(C_OBJS): ../../../../C/$(*B).c - $(COMPL_O2) - -!include "../../Asm.mak" +!include "../../7zip.mak" diff --git a/CPP/7zip/Archive/7z/resource.rc b/CPP/7zip/Archive/7z/resource.rc index f79dac08..f79dac08 100755..100644 --- a/CPP/7zip/Archive/7z/resource.rc +++ b/CPP/7zip/Archive/7z/resource.rc diff --git a/CPP/7zip/Archive/ApmHandler.cpp b/CPP/7zip/Archive/ApmHandler.cpp index a3b5e19b..04cd06fa 100755..100644 --- a/CPP/7zip/Archive/ApmHandler.cpp +++ b/CPP/7zip/Archive/ApmHandler.cpp @@ -4,11 +4,12 @@ #include "../../../C/CpuArch.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/MyString.h" +#include "../../Common/ComTry.h" +#include "../../Common/Defs.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyString.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -25,6 +26,9 @@ using namespace NWindows; namespace NArchive { namespace NApm { +static const Byte kSig0 = 'E'; +static const Byte kSig1 = 'R'; + struct CItem { UInt32 StartBlock; @@ -45,13 +49,13 @@ struct CItem bool Parse(const Byte *p, UInt32 &numBlocksInMap) { - if (p[0] != 0x50 || p[1] != 0x4D || p[2] != 0 || p[3] != 0) - return false; numBlocksInMap = Get32(p + 4); StartBlock = Get32(p + 8); NumBlocks = Get32(p + 0xC); memcpy(Name, p + 0x10, 32); memcpy(Type, p + 0x30, 32); + if (p[0] != 0x50 || p[1] != 0x4D || p[2] != 0 || p[3] != 0) + return false; /* DataStartBlock = Get32(p + 0x50); NumDataBlocks = Get32(p + 0x54); @@ -76,42 +80,56 @@ class CHandler: public IInArchiveGetStream, public CMyUnknownImp { - CMyComPtr<IInStream> _stream; CRecordVector<CItem> _items; - - int _blockSizeLog; + CMyComPtr<IInStream> _stream; + unsigned _blockSizeLog; UInt32 _numBlocks; + UInt64 _phySize; + bool _isArc; HRESULT ReadTables(IInStream *stream); UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; } - UInt64 GetItemSize(const CItem &item) { return BlocksToBytes(item.NumBlocks); } + UInt64 GetItemSize(const CItem &item) const { return BlocksToBytes(item.NumBlocks); } public: MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; -static inline int GetLog(UInt32 num) +static const UInt32 kSectorSize = 512; + +API_FUNC_static_IsArc IsArc_Apm(const Byte *p, size_t size) { - for (int i = 0; i < 31; i++) - if (((UInt32)1 << i) == num) - return i; - return -1; + if (size < kSectorSize) + return k_IsArc_Res_NEED_MORE; + if (p[0] != kSig0 || p[1] != kSig1) + return k_IsArc_Res_NO; + unsigned i; + for (i = 8; i < 16; i++) + if (p[i] != 0) + return k_IsArc_Res_NO; + UInt32 blockSize = Get16(p + 2); + for (i = 9; ((UInt32)1 << i) != blockSize; i++) + if (i >= 12) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; } HRESULT CHandler::ReadTables(IInStream *stream) { - const UInt32 kSectorSize = 512; Byte buf[kSectorSize]; { RINOK(ReadStream_FALSE(stream, buf, kSectorSize)); - if (buf[0] != 0x45 || buf[1] != 0x52) - return S_FALSE; - _blockSizeLog = GetLog(Get16(buf + 2)); - if (_blockSizeLog < 9 || _blockSizeLog > 14) + if (buf[0] != kSig0 || buf[1] != kSig1) return S_FALSE; + UInt32 blockSize = Get16(buf + 2); + unsigned i; + for (i = 9; ((UInt32)1 << i) != blockSize; i++) + if (i >= 12) + return S_FALSE; + _blockSizeLog = i; _numBlocks = Get32(buf + 4); - for (int i = 8; i < 16; i++) + for (i = 8; i < 16; i++) if (buf[i] != 0) return S_FALSE; } @@ -123,13 +141,14 @@ HRESULT CHandler::ReadTables(IInStream *stream) } UInt32 numBlocksInMap = 0; + for (unsigned i = 0;;) { RINOK(ReadStream_FALSE(stream, buf, kSectorSize)); CItem item; - UInt32 numBlocksInMap2; + UInt32 numBlocksInMap2 = 0; if (!item.Parse(buf, numBlocksInMap2)) return S_FALSE; if (i == 0) @@ -154,12 +173,13 @@ HRESULT CHandler::ReadTables(IInStream *stream) if (++i == numBlocksInMap) break; } + + _phySize = BlocksToBytes(_numBlocks); + _isArc = true; return S_OK; } -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */) { COM_TRY_BEGIN Close(); @@ -171,22 +191,23 @@ STDMETHODIMP CHandler::Open(IInStream *stream, STDMETHODIMP CHandler::Close() { + _isArc = false; + _phySize = 0; _items.Clear(); _stream.Release(); return S_OK; } -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidOffset, VT_UI8} + kpidPath, + kpidSize, + kpidOffset }; -STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidClusterSize, VT_UI4}, - { NULL, kpidPhySize, VT_UI8} + kpidClusterSize }; IMP_IInArchive_Props @@ -195,7 +216,7 @@ IMP_IInArchive_ArcProps static AString GetString(const char *s) { AString res; - for (int i = 0; i < 32 && s[i] != 0; i++) + for (unsigned i = 0; i < 32 && s[i] != 0; i++) res += s[i]; return res; } @@ -204,12 +225,12 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidMainSubfile: { int mainIndex = -1; - for (int i = 0; i < _items.Size(); i++) + FOR_VECTOR (i, _items) { AString s = GetString(_items[i].Type); if (s != "Apple_Free" && @@ -228,7 +249,15 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) break; } case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break; - case kpidPhySize: prop = BlocksToBytes(_numBlocks); break; + case kpidPhySize: prop = _phySize; break; + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + prop = v; + break; + } } prop.Detach(value); return S_OK; @@ -246,7 +275,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_BEGIN NCOM::CPropVariant prop; const CItem &item = _items[index]; - switch(propID) + switch (propID) { case kpidPath: { @@ -283,7 +312,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (numItems == 0) @@ -346,10 +375,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"APM", L"", 0, 0xD4, { 0x50, 0x4D, 0, 0, 0, 0, 0 }, 7, false, CreateArc, 0 }; + { "APM", "apm", 0, 0xD4, + 2, { kSig0, kSig1 }, + 0, + 0, + CreateArc, NULL, IsArc_Apm }; REGISTER_ARC(Apm) diff --git a/CPP/7zip/Archive/ArHandler.cpp b/CPP/7zip/Archive/ArHandler.cpp new file mode 100644 index 00000000..b7dcda85 --- /dev/null +++ b/CPP/7zip/Archive/ArHandler.cpp @@ -0,0 +1,857 @@ +// ArHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/StringConvert.h" +#include "../../Common/StringToInt.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#include "Common/ItemNameUtils.h" + +using namespace NWindows; +using namespace NTime; + +namespace NArchive { +namespace NAr { + +/* +The end of each file member (including last file in archive) is 2-bytes aligned. +It uses 0xA padding if required. + +File Names: + +GNU/SVR4 variant (.a static library): + / - archive symbol table + // - the list of the long filenames, separated by one or more LF characters. + /N - the reference to name string in long filenames list + name/ - the name + +Microsoft variant (.lib static library): + / - First linker file (archive symbol table) + / - Second linker file + // - the list of the long filenames, null-terminated. Each string begins + immediately after the null byte in the previous string. + /N - the reference to name string in long filenames list + name/ - the name + +BSD (Mac OS X) variant: + "__.SYMDEF" - archive symbol table + or + "__.SYMDEF SORTED" - archive symbol table + #1/N - the real filename of length N is appended to the file header. +*/ + +static const unsigned kSignatureLen = 8; + +#define SIGNATURE { '!', '<', 'a', 'r', 'c', 'h', '>', 0x0A } + +static const Byte kSignature[kSignatureLen] = SIGNATURE; + +static const unsigned kNameSize = 16; +static const unsigned kTimeSize = 12; +static const unsigned kUserSize = 6; +static const unsigned kModeSize = 8; +static const unsigned kSizeSize = 10; + +static const unsigned kHeaderSize = kNameSize + kTimeSize + kUserSize * 2 + kModeSize + kSizeSize + 1 + 1; + +enum EType +{ + kType_Ar, + kType_ALib, + kType_Deb, + kType_Lib +}; + +static const char *k_TypeExtionsions[] = +{ + "ar" + , "a" + , "deb" + , "lib" +}; + +enum ESubType +{ + kSubType_None, + kSubType_BSD +}; + +/* +struct CHeader +{ + char Name[kNameSize]; + char MTime[kTimeSize]; + char User[kUserSize]; + char Group[kUserSize]; + char Mode[kModeSize]; + char Size[kSizeSize]; + char Quote; + char NewLine; +}; +*/ + +struct CItem +{ + AString Name; + UInt64 Size; + UInt32 MTime; + UInt32 User; + UInt32 Group; + UInt32 Mode; + + UInt64 HeaderPos; + UInt64 HeaderSize; + + int TextFileIndex; + int SameNameIndex; + + CItem(): TextFileIndex(-1), SameNameIndex(-1) {} + UInt64 GetDataPos() const { return HeaderPos + HeaderSize; }; +}; + +class CInArchive +{ + CMyComPtr<IInStream> m_Stream; + +public: + UInt64 Position; + ESubType SubType; + + HRESULT GetNextItem(CItem &itemInfo, bool &filled); + HRESULT Open(IInStream *inStream); + HRESULT SkipData(UInt64 dataSize) + { + return m_Stream->Seek(dataSize + (dataSize & 1), STREAM_SEEK_CUR, &Position); + } +}; + +HRESULT CInArchive::Open(IInStream *inStream) +{ + SubType = kSubType_None; + RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &Position)); + char signature[kSignatureLen]; + RINOK(ReadStream_FALSE(inStream, signature, kSignatureLen)); + Position += kSignatureLen; + if (memcmp(signature, kSignature, kSignatureLen) != 0) + return S_FALSE; + m_Stream = inStream; + return S_OK; +} + +static unsigned RemoveTailSpaces(char *dest, const char *s, unsigned size) +{ + memcpy(dest, s, size); + for (; size != 0; size--) + { + if (dest[size - 1] != ' ') + break; + } + dest[size] = 0; + return size; +} + +static bool OctalToNumber32(const char *s, unsigned size, UInt32 &res) +{ + res = 0; + char sz[32]; + size = RemoveTailSpaces(sz, s, size); + if (size == 0) + return true; // some items doesn't contaion any numbers + const char *end; + UInt64 res64 = ConvertOctStringToUInt64(sz, &end); + if ((unsigned)(end - sz) != size) + return false; + res = (UInt32)res64; + return (res64 <= 0xFFFFFFFF); +} + +static bool DecimalToNumber(const char *s, unsigned size, UInt64 &res) +{ + res = 0; + char sz[32]; + size = RemoveTailSpaces(sz, s, size); + if (size == 0) + return true; // some items doesn't contaion any numbers + const char *end; + res = ConvertStringToUInt64(sz, &end); + return ((unsigned)(end - sz) == size); +} + +static bool DecimalToNumber32(const char *s, unsigned size, UInt32 &res) +{ + UInt64 res64; + if (!DecimalToNumber(s, size, res64)) + return false; + res = (UInt32)res64; + return (res64 <= 0xFFFFFFFF); +} + +#define RIF(x) { if (!(x)) return S_FALSE; } + + +HRESULT CInArchive::GetNextItem(CItem &item, bool &filled) +{ + filled = false; + + char header[kHeaderSize]; + const char *cur = header; + + { + size_t processedSize = sizeof(header); + item.HeaderPos = Position; + item.HeaderSize = kHeaderSize; + RINOK(ReadStream(m_Stream, header, &processedSize)); + if (processedSize != sizeof(header)) + return S_OK; + if (header[kHeaderSize - 2] != 0x60 || + header[kHeaderSize - 1] != 0x0A) + return S_OK; + for (unsigned i = 0; i < kHeaderSize - 2; i++) + // if (header[i] < 0x20) + if (header[i] == 0) + return S_OK; + Position += processedSize; + } + + UInt32 longNameLen = 0; + if (cur[0] == '#' && + cur[1] == '1' && + cur[2] == '/' && + cur[3] != 0) + { + // BSD variant + RIF(DecimalToNumber32(cur + 3, kNameSize - 3 , longNameLen)); + if (longNameLen >= (1 << 12)) + longNameLen = 0; + } + else + { + char tempString[kNameSize + 1]; + RemoveTailSpaces(tempString, cur, kNameSize); + item.Name = tempString; + } + cur += kNameSize; + + RIF(DecimalToNumber32(cur, kTimeSize, item.MTime)); cur += kTimeSize; + RIF(DecimalToNumber32(cur, kUserSize, item.User)); cur += kUserSize; + RIF(DecimalToNumber32(cur, kUserSize, item.Group)); cur += kUserSize; + RIF(OctalToNumber32(cur, kModeSize, item.Mode)); cur += kModeSize; + RIF(DecimalToNumber(cur, kSizeSize, item.Size)); cur += kSizeSize; + + if (longNameLen != 0 && longNameLen <= item.Size) + { + SubType = kSubType_BSD; + size_t processedSize = longNameLen; + char *s = item.Name.GetBuffer(longNameLen); + HRESULT res = ReadStream(m_Stream, s, &processedSize); + s[longNameLen] = 0; + item.Name.ReleaseBuffer(); + RINOK(res); + if (processedSize != longNameLen) + return S_OK; + item.Size -= longNameLen; + item.HeaderSize += longNameLen; + Position += processedSize; + } + + filled = true; + return S_OK; +} + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CObjectVector<CItem> _items; + CMyComPtr<IInStream> _stream; + Int32 _mainSubfile; + UInt64 _phySize; + + EType _type; + ESubType _subType; + int _longNames_FileIndex; + AString _libFiles[2]; + unsigned _numLibFiles; + AString _errorMessage; + bool _isArc; + + + void UpdateErrorMessage(const char *s); + + HRESULT ParseLongNames(IInStream *stream); + void ChangeDuplicateNames(); + int FindItem(UInt32 offset) const; + HRESULT AddFunc(UInt32 offset, const Byte *data, size_t size, size_t &pos); + HRESULT ParseLibSymbols(IInStream *stream, unsigned fileIndex); +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +void CHandler::UpdateErrorMessage(const char *s) +{ + if (!_errorMessage.IsEmpty()) + _errorMessage += '\n'; + _errorMessage += s; +} + +static const Byte kArcProps[] = +{ + kpidSubType +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidMTime, + kpidPosixAttrib, + kpidUser, + kpidGroup +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +HRESULT CHandler::ParseLongNames(IInStream *stream) +{ + unsigned i; + for (i = 0; i < _items.Size(); i++) + if (_items[i].Name == "//") + break; + if (i == _items.Size()) + return S_OK; + + unsigned fileIndex = i; + const CItem &item = _items[fileIndex]; + if (item.Size > ((UInt32)1 << 30)) + return S_FALSE; + RINOK(stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL)); + size_t size = (size_t)item.Size; + + CByteArr p(size); + RINOK(ReadStream_FALSE(stream, p, size)); + for (i = 0; i < _items.Size(); i++) + { + CItem &item = _items[i]; + if (item.Name[0] != '/') + continue; + const char *ptr = item.Name.Ptr(1); + const char *end; + UInt32 pos = ConvertStringToUInt32(ptr, &end); + if (*end != 0 || end == ptr) + continue; + if (pos >= size) + continue; + UInt32 start = pos; + for (;;) + { + if (pos >= size) + return S_FALSE; + char c = p[pos]; + if (c == 0 || c == 0x0A) + break; + pos++; + } + item.Name.SetFrom((const char *)(p + start), pos - start); + } + _longNames_FileIndex = fileIndex; + return S_OK; +} + +void CHandler::ChangeDuplicateNames() +{ + unsigned i; + for (i = 1; i < _items.Size(); i++) + { + CItem &item = _items[i]; + if (item.Name[0] == '/') + continue; + CItem &prev = _items[i - 1]; + if (item.Name == prev.Name) + { + if (prev.SameNameIndex < 0) + prev.SameNameIndex = 0; + item.SameNameIndex = prev.SameNameIndex + 1; + } + } + for (i = 0; i < _items.Size(); i++) + { + CItem &item = _items[i]; + if (item.SameNameIndex < 0) + continue; + char sz[32]; + ConvertUInt32ToString(item.SameNameIndex + 1, sz); + unsigned len = MyStringLen(sz); + sz[len++] = '.'; + sz[len] = 0; + item.Name.Insert(0, sz); + } +} + +int CHandler::FindItem(UInt32 offset) const +{ + unsigned left = 0, right = _items.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + UInt64 midVal = _items[mid].HeaderPos; + if (offset == midVal) + return mid; + if (offset < midVal) + right = mid; + else + left = mid + 1; + } + return -1; +} + +HRESULT CHandler::AddFunc(UInt32 offset, const Byte *data, size_t size, size_t &pos) +{ + int fileIndex = FindItem(offset); + if (fileIndex < (int)0) + return S_FALSE; + + size_t i = pos; + do + { + if (i >= size) + return S_FALSE; + } + while (data[i++] != 0); + + AString &s = _libFiles[_numLibFiles]; + const AString &name = _items[fileIndex].Name; + s += name; + if (!name.IsEmpty() && name.Back() == '/') + s.DeleteBack(); + s += " "; + s += (const char *)(data + pos); + s += (char)0xD; + s += (char)0xA; + pos = i; + return S_OK; +} + +static UInt32 Get32(const Byte *p, unsigned be) { if (be) return GetBe32(p); return GetUi32(p); } + +HRESULT CHandler::ParseLibSymbols(IInStream *stream, unsigned fileIndex) +{ + CItem &item = _items[fileIndex]; + if (item.Name != "/" && + item.Name != "__.SYMDEF" && + item.Name != "__.SYMDEF SORTED") + return S_OK; + if (item.Size > ((UInt32)1 << 30) || + item.Size < 4) + return S_OK; + RINOK(stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL)); + size_t size = (size_t)item.Size; + CByteArr p(size); + RINOK(ReadStream_FALSE(stream, p, size)); + + size_t pos = 0; + + if (item.Name != "/") + { + // __.SYMDEF parsing (BSD) + unsigned be; + for (be = 0; be < 2; be++) + { + UInt32 tableSize = Get32(p, be); + pos = 4; + if (size - pos < tableSize || (tableSize & 7) != 0) + continue; + size_t namesStart = pos + tableSize; + UInt32 namesSize = Get32(p + namesStart, be); + namesStart += 4; + if (namesStart > size || namesStart + namesSize != size) + continue; + + UInt32 numSymbols = tableSize >> 3; + UInt32 i; + for (i = 0; i < numSymbols; i++, pos += 8) + { + size_t namePos = Get32(p + pos, be); + UInt32 offset = Get32(p + pos + 4, be); + if (AddFunc(offset, p + namesStart, namesSize, namePos) != S_OK) + break; + } + if (i == numSymbols) + { + pos = size; + _type = kType_ALib; + _subType = kSubType_BSD; + break; + } + } + if (be == 2) + return S_FALSE; + } + else if (_numLibFiles == 0) + { + // archive symbol table (GNU) + UInt32 numSymbols = GetBe32(p); + pos = 4; + if (numSymbols > (size - pos) / 4) + return S_FALSE; + pos += 4 * numSymbols; + + for (UInt32 i = 0; i < numSymbols; i++) + { + UInt32 offset = GetBe32(p + 4 + i * 4); + RINOK(AddFunc(offset, p, size, pos)); + } + _type = kType_ALib; + } + else + { + // Second linker file (Microsoft .lib) + UInt32 numMembers = GetUi32(p); + pos = 4; + if (numMembers > (size - pos) / 4) + return S_FALSE; + pos += 4 * numMembers; + + if (size - pos < 4) + return S_FALSE; + UInt32 numSymbols = GetUi32(p + pos); + pos += 4; + if (numSymbols > (size - pos) / 2) + return S_FALSE; + size_t indexStart = pos; + pos += 2 * numSymbols; + + for (UInt32 i = 0; i < numSymbols; i++) + { + // index is 1-based. So 32-bit numSymbols field works as item[0] + UInt32 index = GetUi16(p + indexStart + i * 2); + if (index == 0 || index > numMembers) + return S_FALSE; + UInt32 offset = GetUi32(p + index * 4); + RINOK(AddFunc(offset, p, size, pos)); + } + _type = kType_Lib; + } + // size can be 2-byte aligned in linux files + if (pos != size && pos + (pos & 1) != size) + return S_FALSE; + item.TextFileIndex = _numLibFiles++; + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + { + Close(); + + UInt64 fileSize = 0; + RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + + CInArchive arc; + RINOK(arc.Open(stream)); + + if (callback) + { + RINOK(callback->SetTotal(NULL, &fileSize)); + UInt64 numFiles = _items.Size(); + RINOK(callback->SetCompleted(&numFiles, &arc.Position)); + } + + CItem item; + for (;;) + { + bool filled; + RINOK(arc.GetNextItem(item, filled)); + if (!filled) + break; + _items.Add(item); + arc.SkipData(item.Size); + if (callback && (_items.Size() & 0xFF) == 0) + { + UInt64 numFiles = _items.Size(); + RINOK(callback->SetCompleted(&numFiles, &arc.Position)); + } + } + + if (_items.IsEmpty()) + { + // we don't need false empty archives (8-bytes signature only) + if (arc.Position != fileSize) + return S_FALSE; + } + + _isArc = true; + + _subType = arc.SubType; + + if (ParseLongNames(stream) != S_OK) + UpdateErrorMessage("Long file names parsing error"); + if (_longNames_FileIndex >= 0) + _items.Delete(_longNames_FileIndex); + + if (!_items.IsEmpty() && _items[0].Name == "debian-binary") + { + _type = kType_Deb; + _items.DeleteFrontal(1); + for (unsigned i = 0; i < _items.Size(); i++) + if (_items[i].Name.IsPrefixedBy("data.tar.")) + if (_mainSubfile < 0) + _mainSubfile = i; + else + { + _mainSubfile = -1; + break; + } + } + else + { + ChangeDuplicateNames(); + bool error = false; + for (unsigned li = 0; li < 2 && li < _items.Size(); li++) + if (ParseLibSymbols(stream, li) != S_OK) + error = true; + if (error) + UpdateErrorMessage("Library symbols information error"); + } + + _stream = stream; + _phySize = arc.Position; + + /* + if (fileSize < _phySize) + UpdateErrorMessage("Unexpected end of archive"); + */ + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _isArc = false; + _phySize = 0; + + _errorMessage.Empty(); + _stream.Release(); + _items.Clear(); + + _type = kType_Ar; + _subType = kSubType_None; + _mainSubfile = -1; + _longNames_FileIndex = -1; + + _numLibFiles = 0; + _libFiles[0].Empty(); + _libFiles[1].Empty(); + + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: prop = _phySize; break; + case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; + case kpidExtension: prop = k_TypeExtionsions[_type]; break; + case kpidShortComment: + case kpidSubType: + { + AString s = k_TypeExtionsions[_type]; + if (_subType == kSubType_BSD) + s += ":BSD"; + prop = s; + break; + } + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + prop = v; + break; + } + case kpidWarning: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + case kpidIsNotArcType: if (_type != kType_Deb) prop = true; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem &item = _items[index]; + switch (propID) + { + case kpidPath: + if (item.TextFileIndex >= 0) + prop = (item.TextFileIndex == 0) ? "1.txt" : "2.txt"; + else + prop = (const wchar_t *)NItemName::GetOSName2(MultiByteToUnicodeString(item.Name, CP_OEMCP)); + break; + case kpidSize: + case kpidPackSize: + if (item.TextFileIndex >= 0) + prop = (UInt64)_libFiles[item.TextFileIndex].Len(); + else + prop = item.Size; + break; + case kpidMTime: + { + if (item.MTime != 0) + { + FILETIME fileTime; + NTime::UnixTimeToFileTime(item.MTime, fileTime); + prop = fileTime; + } + break; + } + case kpidUser: if (item.User != 0) prop = item.User; break; + case kpidGroup: if (item.Group != 0) prop = item.Group; break; + case kpidPosixAttrib: + if (item.TextFileIndex < 0) + prop = item.Mode; + break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const CItem &item = _items[allFilesMode ? i : indices[i]]; + totalSize += + (item.TextFileIndex >= 0) ? + (UInt64)_libFiles[item.TextFileIndex].Len() : item.Size; + } + extractCallback->SetTotal(totalSize); + + UInt64 currentTotalSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream(streamSpec); + streamSpec->SetStream(_stream); + + for (i = 0; i < numItems; i++) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + CMyComPtr<ISequentialOutStream> realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + currentTotalSize += (item.TextFileIndex >= 0) ? + (UInt64)_libFiles[item.TextFileIndex].Len() : item.Size; + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + if (testMode) + { + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + bool isOk = true; + if (item.TextFileIndex >= 0) + { + const AString &f = _libFiles[item.TextFileIndex]; + if (realOutStream) + RINOK(WriteStream(realOutStream, f, f.Len())); + } + else + { + RINOK(_stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL)); + streamSpec->Init(item.Size); + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + isOk = (copyCoderSpec->TotalSize == item.Size); + } + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(isOk ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + const CItem &item = _items[index]; + if (item.TextFileIndex >= 0) + { + const AString &f = _libFiles[item.TextFileIndex]; + Create_BufInStream_WithNewBuf((const void *)(const char *)f, f.Len(), stream); + return S_OK; + } + else + return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream); + COM_TRY_END +} + +IMP_CreateArcIn + +static CArcInfo g_ArcInfo = + { "Ar", "ar a deb lib", 0, 0xEC, + kSignatureLen, SIGNATURE, + 0, + 0, + CreateArc }; + +REGISTER_ARC(Ar) + +}} diff --git a/CPP/7zip/Archive/Archive.def b/CPP/7zip/Archive/Archive.def index 55b530b2..55b530b2 100755..100644 --- a/CPP/7zip/Archive/Archive.def +++ b/CPP/7zip/Archive/Archive.def diff --git a/CPP/7zip/Archive/Archive2.def b/CPP/7zip/Archive/Archive2.def index 885d39d1..66feb41d 100755..100644 --- a/CPP/7zip/Archive/Archive2.def +++ b/CPP/7zip/Archive/Archive2.def @@ -3,7 +3,9 @@ EXPORTS GetHandlerProperty PRIVATE GetNumberOfFormats PRIVATE GetHandlerProperty2 PRIVATE - CreateObject PRIVATE GetNumberOfMethods PRIVATE GetMethodProperty PRIVATE + GetHashers PRIVATE SetLargePageMode PRIVATE + SetCaseSensitive PRIVATE + GetIsArc PRIVATE
\ No newline at end of file diff --git a/CPP/7zip/Archive/ArchiveExports.cpp b/CPP/7zip/Archive/ArchiveExports.cpp index c7908b59..c7d6611b 100755..100644 --- a/CPP/7zip/Archive/ArchiveExports.cpp +++ b/CPP/7zip/Archive/ArchiveExports.cpp @@ -2,24 +2,28 @@ #include "StdAfx.h" +#include "../../../C/7zVersion.h" + #include "../../Common/ComTry.h" #include "../../Windows/PropVariant.h" #include "../Common/RegisterArc.h" -static const unsigned int kNumArcsMax = 48; -static unsigned int g_NumArcs = 0; -static unsigned int g_DefaultArcIndex = 0; +static const unsigned kNumArcsMax = 64; +static unsigned g_NumArcs = 0; +static unsigned g_DefaultArcIndex = 0; static const CArcInfo *g_Arcs[kNumArcsMax]; + void RegisterArc(const CArcInfo *arcInfo) { if (g_NumArcs < kNumArcsMax) { - const wchar_t *p = arcInfo->Name; + const char *p = arcInfo->Name; if (p[0] == '7' && p[1] == 'z' && p[2] == 0) g_DefaultArcIndex = g_NumArcs; - g_Arcs[g_NumArcs++] = arcInfo; + g_Arcs[g_NumArcs] = arcInfo; + g_NumArcs++; } } @@ -28,7 +32,7 @@ DEFINE_GUID(CLSID_CArchiveHandler, #define CLS_ARC_ID_ITEM(cls) ((cls).Data4[5]) -static inline HRESULT SetPropString(const char *s, unsigned int size, PROPVARIANT *value) +static inline HRESULT SetPropString(const char *s, unsigned size, PROPVARIANT *value) { if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != 0) value->vt = VT_BSTR; @@ -86,37 +90,38 @@ STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject) STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN + NWindows::NCOM::PropVariant_Clear(value); if (formatIndex >= g_NumArcs) return E_INVALIDARG; const CArcInfo &arc = *g_Arcs[formatIndex]; NWindows::NCOM::CPropVariant prop; - switch(propID) + switch (propID) { - case NArchive::kName: - prop = arc.Name; - break; - case NArchive::kClassID: + case NArchive::NHandlerPropID::kName: prop = arc.Name; break; + case NArchive::NHandlerPropID::kClassID: { GUID clsId = CLSID_CArchiveHandler; CLS_ARC_ID_ITEM(clsId) = arc.ClassId; return SetPropGUID(clsId, value); } - case NArchive::kExtension: - if (arc.Ext != 0) - prop = arc.Ext; - break; - case NArchive::kAddExtension: - if (arc.AddExt != 0) - prop = arc.AddExt; - break; - case NArchive::kUpdate: - prop = (bool)(arc.CreateOutArchive != 0); + case NArchive::NHandlerPropID::kExtension: if (arc.Ext) prop = arc.Ext; break; + case NArchive::NHandlerPropID::kAddExtension: if (arc.AddExt) prop = arc.AddExt; break; + case NArchive::NHandlerPropID::kUpdate: prop = (bool)(arc.CreateOutArchive != NULL); break; + case NArchive::NHandlerPropID::kKeepName: prop = ((arc.Flags & NArcInfoFlags::kKeepName) != 0); break; + case NArchive::NHandlerPropID::kAltStreams: prop = ((arc.Flags & NArcInfoFlags::kAltStreams) != 0); break; + case NArchive::NHandlerPropID::kNtSecure: prop = ((arc.Flags & NArcInfoFlags::kNtSecure) != 0); break; + case NArchive::NHandlerPropID::kFlags: prop = (UInt32)arc.Flags; break; + case NArchive::NHandlerPropID::kSignatureOffset: prop = (UInt32)arc.SignatureOffset; break; + // case NArchive::NHandlerPropID::kVersion: prop = (UInt32)MY_VER_MIX; break; + + case NArchive::NHandlerPropID::kSignature: + if (!arc.IsMultiSignature()) + return SetPropString((const char *)arc.Signature, arc.SignatureSize, value); break; - case NArchive::kKeepName: - prop = arc.KeepName; + case NArchive::NHandlerPropID::kMultiSignature: + if (arc.IsMultiSignature()) + return SetPropString((const char *)arc.Signature, arc.SignatureSize, value); break; - case NArchive::kStartSignature: - return SetPropString((const char *)arc.Signature, arc.SignatureSize, value); } prop.Detach(value); return S_OK; @@ -133,3 +138,12 @@ STDAPI GetNumberOfFormats(UINT32 *numFormats) *numFormats = g_NumArcs; return S_OK; } + +STDAPI GetIsArc(UInt32 formatIndex, Func_IsArc *isArc) +{ + *isArc = NULL; + if (formatIndex >= g_NumArcs) + return E_INVALIDARG; + *isArc = g_Arcs[formatIndex]->IsArc; + return S_OK; +} diff --git a/CPP/7zip/Archive/ArjHandler.cpp b/CPP/7zip/Archive/ArjHandler.cpp index 4dd686ec..ad44c62a 100755..100644 --- a/CPP/7zip/Archive/ArjHandler.cpp +++ b/CPP/7zip/Archive/ArjHandler.cpp @@ -4,11 +4,12 @@ #include "../../../C/CpuArch.h" -#include "Common/ComTry.h" -#include "Common/StringConvert.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/StringConvert.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -31,74 +32,85 @@ using namespace NWindows; namespace NArchive { namespace NArj { -const int kBlockSizeMin = 30; -const int kBlockSizeMax = 2600; +static const unsigned kBlockSizeMin = 30; +static const unsigned kBlockSizeMax = 2600; -namespace NSignature +static const Byte kSig0 = 0x60; +static const Byte kSig1 = 0xEA; + +namespace NCompressionMethod { - const Byte kSig0 = 0x60; - const Byte kSig1 = 0xEA; + enum + { + kStored = 0, + kCompressed1a = 1, + kCompressed1b = 2, + kCompressed1c = 3, + kCompressed2 = 4, + kNoDataNoCRC = 8, + kNoData = 9 + }; } -namespace NFileHeader +namespace NFileType { - namespace NCompressionMethod + enum { - enum - { - kStored = 0, - kCompressed1a = 1, - kCompressed1b = 2, - kCompressed1c = 3, - kCompressed2 = 4, - kNoDataNoCRC = 8, - kNoData = 9 - }; - } + kBinary = 0, + k7BitText, + kArchiveHeader, + kDirectory, + kVolumeLablel, + kChapterLabel + }; +} - namespace NFileType - { - enum - { - kBinary = 0, - k7BitText = 1, - kArchiveHeader = 2, - kDirectory = 3, - kVolumeLablel = 4, - kChapterLabel = 5 - }; - } - - namespace NFlags - { - const Byte kGarbled = 1; - const Byte kVolume = 4; - const Byte kExtFile = 8; - const Byte kPathSym = 0x10; - const Byte kBackup = 0x20; - } +namespace NFlags +{ + const Byte kGarbled = 1 << 0; + const Byte kAnsiPage = 1 << 1; // or (OLD_SECURED_FLAG) obsolete + const Byte kVolume = 1 << 2; + const Byte kExtFile = 1 << 3; + const Byte kPathSym = 1 << 4; + const Byte kBackup = 1 << 5; // obsolete + const Byte kSecured = 1 << 6; + const Byte kDualName = 1 << 7; +} - namespace NHostOS +namespace NHostOS +{ + enum EEnum { - enum EEnum - { - kMSDOS = 0, // filesystem used by MS-DOS, OS/2, Win32 - // pkarj 2.50 (FAT / VFAT / FAT32 file systems) - kPRIMOS, - kUnix, - kAMIGA, - kMac, - kOS_2, - kAPPLE_GS, - kAtari_ST, - kNext, - kVAX_VMS, - kWIN95 - }; - } + kMSDOS = 0, // MS-DOS, OS/2, Win32, pkarj 2.50 (FAT / VFAT / FAT32) + kPRIMOS, + kUnix, + kAMIGA, + kMac, + kOS_2, + kAPPLE_GS, + kAtari_ST, + kNext, + kVAX_VMS, + kWIN95 + }; } -struct CArchiveHeader +static const char *kHostOS[] = +{ + "MSDOS" + , "PRIMOS" + , "UNIX" + , "AMIGA" + , "MAC" + , "OS/2" + , "APPLE GS" + , "ATARI ST" + , "NEXT" + , "VAX VMS" + , "WIN95" +}; + +struct CArcHeader { // Byte ArchiverVersion; // Byte ExtractVersion; @@ -110,9 +122,9 @@ struct CArchiveHeader UInt32 CTime; UInt32 MTime; UInt32 ArchiveSize; - // UInt32 SecurityEnvelopeFilePosition; - // UInt16 FilespecPositionInFilename; - // UInt16 LengthOfSecurityEnvelopeSata; + // UInt32 SecurPos; + // UInt16 FilespecPosInFilename; + UInt16 SecurSize; // Byte EncryptionVersion; // Byte LastChapter; AString Name; @@ -121,47 +133,71 @@ struct CArchiveHeader HRESULT Parse(const Byte *p, unsigned size); }; +API_FUNC_static_IsArc IsArc_Arj(const Byte *p, size_t size) +{ + if (size < kBlockSizeMin + 4) + return k_IsArc_Res_NEED_MORE; + if (p[0] != kSig0 || p[1] != kSig1) + return k_IsArc_Res_NO; + UInt32 blockSize = Get16(p + 2); + if (blockSize < kBlockSizeMin || + blockSize > kBlockSizeMax) + return k_IsArc_Res_NO; + + p += 4; + size -= 4; + + Byte headerSize = p[0]; + if (headerSize < kBlockSizeMin || + headerSize > blockSize || + p[6] != NFileType::kArchiveHeader || + p[28] > 8) // EncryptionVersion + return k_IsArc_Res_NO; + + if (blockSize + 4 <= size) + if (Get32(p + blockSize) != CrcCalc(p, blockSize)) + return k_IsArc_Res_NO; + + return k_IsArc_Res_YES; +} + static HRESULT ReadString(const Byte *p, unsigned &size, AString &res) { - AString s; for (unsigned i = 0; i < size;) { char c = (char)p[i++]; if (c == 0) { size = i; - res = s; + res = (const char *)p; return S_OK; } - s += c; } return S_FALSE; } -HRESULT CArchiveHeader::Parse(const Byte *p, unsigned size) +HRESULT CArcHeader::Parse(const Byte *p, unsigned size) { - if (size < kBlockSizeMin) - return S_FALSE; - Byte firstHeaderSize = p[0]; - if (firstHeaderSize > size) + Byte headerSize = p[0]; + if (headerSize < kBlockSizeMin || headerSize > size) return S_FALSE; // ArchiverVersion = p[1]; // ExtractVersion = p[2]; HostOS = p[3]; // Flags = p[4]; // SecuryVersion = p[5]; - if (p[6] != NFileHeader::NFileType::kArchiveHeader) + if (p[6] != NFileType::kArchiveHeader) return S_FALSE; // Reserved = p[7]; CTime = Get32(p + 8); MTime = Get32(p + 12); - ArchiveSize = Get32(p + 16); - // SecurityEnvelopeFilePosition = Get32(p + 20); + ArchiveSize = Get32(p + 16); // it can be zero. (currently used only for secured archives) + // SecurPos = Get32(p + 20); // UInt16 filespecPositionInFilename = Get16(p + 24); - // LengthOfSecurityEnvelopeSata = Get16(p + 26); + SecurSize = Get16(p + 26); // EncryptionVersion = p[28]; // LastChapter = p[29]; - unsigned pos = firstHeaderSize; + unsigned pos = headerSize; unsigned size1 = size - pos; RINOK(ReadString(p + pos, size1, Name)); pos += size1; @@ -189,32 +225,30 @@ struct CItem Byte Method; Byte FileType; - // UInt16 FilespecPositionInFilename; + // UInt16 FilespecPosInFilename; UInt16 FileAccessMode; // Byte FirstChapter; // Byte LastChapter; UInt64 DataPosition; - bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kGarbled) != 0; } - bool IsDir() const { return (FileType == NFileHeader::NFileType::kDirectory); } - bool IsSplitAfter() const { return (Flags & NFileHeader::NFlags::kVolume) != 0; } - bool IsSplitBefore() const { return (Flags & NFileHeader::NFlags::kExtFile) != 0; } - UInt32 GetWinAttributes() const + bool IsEncrypted() const { return (Flags & NFlags::kGarbled) != 0; } + bool IsDir() const { return (FileType == NFileType::kDirectory); } + bool IsSplitAfter() const { return (Flags & NFlags::kVolume) != 0; } + bool IsSplitBefore() const { return (Flags & NFlags::kExtFile) != 0; } + UInt32 GetWinAttrib() const { - UInt32 winAtrributes; - switch(HostOS) + UInt32 atrrib = 0; + switch (HostOS) { - case NFileHeader::NHostOS::kMSDOS: - case NFileHeader::NHostOS::kWIN95: - winAtrributes = FileAccessMode; + case NHostOS::kMSDOS: + case NHostOS::kWIN95: + atrrib = FileAccessMode; break; - default: - winAtrributes = 0; } if (IsDir()) - winAtrributes |= FILE_ATTRIBUTE_DIRECTORY; - return winAtrributes; + atrrib |= FILE_ATTRIBUTE_DIRECTORY; + return atrrib; } HRESULT Parse(const Byte *p, unsigned size); @@ -222,11 +256,9 @@ struct CItem HRESULT CItem::Parse(const Byte *p, unsigned size) { - if (size < kBlockSizeMin) + Byte headerSize = p[0]; + if (headerSize < kBlockSizeMin || headerSize > size) return S_FALSE; - - Byte firstHeaderSize = p[0]; - Version = p[1]; ExtractVersion = p[2]; HostOS = p[3]; @@ -238,16 +270,16 @@ HRESULT CItem::Parse(const Byte *p, unsigned size) PackSize = Get32(p + 12); Size = Get32(p + 16); FileCRC = Get32(p + 20); - // FilespecPositionInFilename = Get16(p + 24); + // FilespecPosInFilename = Get16(p + 24); FileAccessMode = Get16(p + 26); // FirstChapter = p[28]; // FirstChapter = p[29]; SplitPos = 0; - if (IsSplitBefore() && firstHeaderSize >= 34) + if (IsSplitBefore() && headerSize >= 34) SplitPos = Get32(p + 30); - unsigned pos = firstHeaderSize; + unsigned pos = headerSize; unsigned size1 = size - pos; RINOK(ReadString(p + pos, size1, Name)); pos += size1; @@ -258,180 +290,121 @@ HRESULT CItem::Parse(const Byte *p, unsigned size) return S_OK; } -struct CInArchiveException +enum EErrorType { - enum CCauseType - { - kUnexpectedEndOfArchive = 0, - kCRCError, - kIncorrectArchive - } - Cause; - CInArchiveException(CCauseType cause): Cause(cause) {}; + k_ErrorType_OK, + k_ErrorType_Corrupted, + k_ErrorType_UnexpectedEnd, }; -class CInArchive +class CArc { - UInt32 _blockSize; - Byte _block[kBlockSizeMax + 4]; - - HRESULT ReadBlock(bool &filled); - HRESULT ReadSignatureAndBlock(bool &filled); - HRESULT SkipExtendedHeaders(); - - HRESULT SafeReadBytes(void *data, UInt32 size); - public: - CArchiveHeader Header; - + UInt64 Processed; + EErrorType Error; + bool IsArc; IInStream *Stream; IArchiveOpenCallback *Callback; UInt64 NumFiles; - UInt64 NumBytes; + CArcHeader Header; - HRESULT Open(const UInt64 *searchHeaderSizeLimit); - HRESULT GetNextItem(bool &filled, CItem &item); -}; - -static inline bool TestMarkerCandidate(const Byte *p, unsigned maxSize) -{ - if (p[0] != NSignature::kSig0 || p[1] != NSignature::kSig1) - return false; - UInt32 blockSize = Get16(p + 2); - p += 4; - if (p[6] != NFileHeader::NFileType::kArchiveHeader || - p[0] > blockSize || - maxSize < 2 + 2 + blockSize + 4 || - blockSize < kBlockSizeMin || blockSize > kBlockSizeMax || - p[28] > 8) // EncryptionVersion - return false; - // return (Get32(p + blockSize) == CrcCalc(p, blockSize)); - return true; -} - -static HRESULT FindAndReadMarker(ISequentialInStream *stream, const UInt64 *searchHeaderSizeLimit, UInt64 &position) -{ - position = 0; - - const int kMarkerSizeMin = 2 + 2 + kBlockSizeMin + 4; - const int kMarkerSizeMax = 2 + 2 + kBlockSizeMax + 4; - - CByteBuffer byteBuffer; - const UInt32 kBufSize = 1 << 16; - byteBuffer.SetCapacity(kBufSize); - Byte *buf = byteBuffer; - - size_t processedSize = kMarkerSizeMax; - RINOK(ReadStream(stream, buf, &processedSize)); - if (processedSize < kMarkerSizeMin) - return S_FALSE; - if (TestMarkerCandidate(buf, (unsigned)processedSize)) - return S_OK; - - UInt32 numBytesPrev = (UInt32)processedSize - 1; - memmove(buf, buf + 1, numBytesPrev); - UInt64 curTestPos = 1; - for (;;) + HRESULT Open(); + HRESULT GetNextItem(CItem &item, bool &filled); + void Close() { - if (searchHeaderSizeLimit != NULL) - if (curTestPos > *searchHeaderSizeLimit) - return S_FALSE; - processedSize = kBufSize - numBytesPrev; - RINOK(ReadStream(stream, buf + numBytesPrev, &processedSize)); - UInt32 numBytesInBuffer = numBytesPrev + (UInt32)processedSize; - if (numBytesInBuffer < kMarkerSizeMin) - return S_FALSE; - UInt32 numTests = numBytesInBuffer - kMarkerSizeMin + 1; - UInt32 pos; - for (pos = 0; pos < numTests; pos++) - { - for (; buf[pos] != NSignature::kSig0 && pos < numTests; pos++); - if (pos == numTests) - break; - if (TestMarkerCandidate(buf + pos, numBytesInBuffer - pos)) - { - position = curTestPos + pos; - return S_OK; - } - } - curTestPos += pos; - numBytesPrev = numBytesInBuffer - numTests; - memmove(buf, buf + numTests, numBytesPrev); + IsArc = false; + Error = k_ErrorType_OK; } -} +private: + UInt32 _blockSize; + Byte _block[kBlockSizeMax + 4]; -HRESULT CInArchive::SafeReadBytes(void *data, UInt32 size) + HRESULT ReadBlock(bool &filled, bool readSignature); + HRESULT SkipExtendedHeaders(); + HRESULT Read(void *data, size_t *size); +}; + +HRESULT CArc::Read(void *data, size_t *size) { - size_t processed = size; - RINOK(ReadStream(Stream, data, &processed)); - if (processed != size) - throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive); - return S_OK; + HRESULT res = ReadStream(Stream, data, size); + Processed += *size; + return res; } -HRESULT CInArchive::ReadBlock(bool &filled) +#define READ_STREAM(_dest_, _size_) \ + { size_t _processed_ = (_size_); RINOK(Read(_dest_, &_processed_)); \ + if (_processed_ != (_size_)) { Error = k_ErrorType_UnexpectedEnd; return S_OK; } } + +HRESULT CArc::ReadBlock(bool &filled, bool readSignature) { + Error = k_ErrorType_OK; filled = false; - Byte buf[2]; - RINOK(SafeReadBytes(buf, 2)); - _blockSize = Get16(buf); - if (_blockSize == 0) + Byte buf[4]; + unsigned signSize = readSignature ? 2 : 0; + READ_STREAM(buf, signSize + 2) + if (readSignature) + if (buf[0] != kSig0 || buf[1] != kSig1) + { + Error = k_ErrorType_Corrupted; + return S_OK; + } + _blockSize = Get16(buf + signSize); + if (_blockSize == 0) // end of archive + return S_OK; + if (_blockSize < kBlockSizeMin || + _blockSize > kBlockSizeMax) + { + Error = k_ErrorType_Corrupted; return S_OK; - if (_blockSize > kBlockSizeMax) - throw CInArchiveException(CInArchiveException::kIncorrectArchive); - RINOK(SafeReadBytes(_block, _blockSize + 4)); - NumBytes += _blockSize + 6; + } + READ_STREAM(_block, _blockSize + 4); if (Get32(_block + _blockSize) != CrcCalc(_block, _blockSize)) - throw CInArchiveException(CInArchiveException::kCRCError); + { + Error = k_ErrorType_Corrupted; + return S_OK; + } filled = true; return S_OK; } -HRESULT CInArchive::ReadSignatureAndBlock(bool &filled) -{ - Byte id[2]; - RINOK(SafeReadBytes(id, 2)); - if (id[0] != NSignature::kSig0 || id[1] != NSignature::kSig1) - throw CInArchiveException(CInArchiveException::kIncorrectArchive); - return ReadBlock(filled); -} - -HRESULT CInArchive::SkipExtendedHeaders() +HRESULT CArc::SkipExtendedHeaders() { for (UInt32 i = 0;; i++) { bool filled; - RINOK(ReadBlock(filled)); + RINOK(ReadBlock(filled, false)); if (!filled) return S_OK; if (Callback && (i & 0xFF) == 0) - RINOK(Callback->SetCompleted(&NumFiles, &NumBytes)); + RINOK(Callback->SetCompleted(&NumFiles, &Processed)); } } -HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit) +HRESULT CArc::Open() { - UInt64 position = 0; - RINOK(FindAndReadMarker(Stream, searchHeaderSizeLimit, position)); - RINOK(Stream->Seek(position, STREAM_SEEK_SET, NULL)); bool filled; - RINOK(ReadSignatureAndBlock(filled)); + RINOK(ReadBlock(filled, true)); if (!filled) return S_FALSE; RINOK(Header.Parse(_block, _blockSize)); + IsArc = true; return SkipExtendedHeaders(); } -HRESULT CInArchive::GetNextItem(bool &filled, CItem &item) +HRESULT CArc::GetNextItem(CItem &item, bool &filled) { - RINOK(ReadSignatureAndBlock(filled)); + RINOK(ReadBlock(filled, true)); if (!filled) return S_OK; filled = false; - RINOK(item.Parse(_block, _blockSize)); + if (item.Parse(_block, _blockSize) != S_OK) + { + Error = k_ErrorType_Corrupted; + return S_OK; + } /* UInt32 extraData; - if ((header.Flags & NFileHeader::NFlags::kExtFile) != 0) + if ((header.Flags & NFlags::kExtFile) != 0) extraData = GetUi32(_block + pos); */ @@ -444,67 +417,47 @@ class CHandler: public IInArchive, public CMyUnknownImp { + CObjectVector<CItem> _items; + CMyComPtr<IInStream> _stream; + UInt64 _phySize; + CArc _arc; public: MY_UNKNOWN_IMP1(IInArchive) INTERFACE_IInArchive(;) - HRESULT Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *callback); -private: - CInArchive _archive; - CObjectVector<CItem> _items; - CMyComPtr<IInStream> _stream; + HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback); }; -const wchar_t *kHostOS[] = +static const Byte kArcProps[] = { - L"MSDOS", - L"PRIMOS", - L"UNIX", - L"AMIGA", - L"MAC", - L"OS/2", - L"APPLE GS", - L"ATARI ST", - L"NEXT", - L"VAX VMS", - L"WIN95" + kpidName, + kpidCTime, + kpidMTime, + kpidHostOS, + kpidComment }; -const wchar_t *kUnknownOS = L"Unknown"; - -const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]); - -STATPROPSTG kArcProps[] = +static const Byte kProps[] = { - { NULL, kpidName, VT_BSTR}, - { NULL, kpidCTime, VT_BSTR}, - { NULL, kpidMTime, VT_BSTR}, - { NULL, kpidHostOS, VT_BSTR}, - { NULL, kpidComment, VT_BSTR} -}; - -STATPROPSTG kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI4}, - { NULL, kpidPosition, VT_UI8}, - { NULL, kpidPackSize, VT_UI4}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidAttrib, VT_UI4}, - { NULL, kpidEncrypted, VT_BOOL}, - { NULL, kpidCRC, VT_UI4}, - { NULL, kpidMethod, VT_UI1}, - { NULL, kpidHostOS, VT_BSTR}, - { NULL, kpidComment, VT_BSTR} + kpidPath, + kpidIsDir, + kpidSize, + kpidPosition, + kpidPackSize, + kpidMTime, + kpidAttrib, + kpidEncrypted, + kpidCRC, + kpidMethod, + kpidHostOS, + kpidComment }; IMP_IInArchive_Props IMP_IInArchive_ArcProps -static void SetTime(UInt32 dosTime, NWindows::NCOM::CPropVariant &prop) +static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop) { if (dosTime == 0) return; @@ -519,12 +472,21 @@ static void SetTime(UInt32 dosTime, NWindows::NCOM::CPropVariant &prop) prop = utc; } -static void SetHostOS(Byte hostOS, NWindows::NCOM::CPropVariant &prop) +static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop) { - prop = hostOS < kNumHostOSes ? kHostOS[hostOS] : kUnknownOS; + char temp[16]; + const char *s = NULL; + if (hostOS < ARRAY_SIZE(kHostOS)) + s = kHostOS[hostOS]; + else + { + ConvertUInt32ToString(hostOS, temp); + s = temp; + } + prop = s; } -static void SetUnicodeString(const AString &s, NWindows::NCOM::CPropVariant &prop) +static void SetUnicodeString(const AString &s, NCOM::CPropVariant &prop) { if (!s.IsEmpty()) prop = MultiByteToUnicodeString(s, CP_OEMCP); @@ -533,14 +495,27 @@ static void SetUnicodeString(const AString &s, NWindows::NCOM::CPropVariant &pro STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) + NCOM::CPropVariant prop; + switch (propID) { - case kpidName: SetUnicodeString(_archive.Header.Name, prop); break; - case kpidCTime: SetTime(_archive.Header.CTime, prop); break; - case kpidMTime: SetTime(_archive.Header.MTime, prop); break; - case kpidHostOS: SetHostOS(_archive.Header.HostOS, prop); break; - case kpidComment: SetUnicodeString(_archive.Header.Comment, prop); break; + case kpidPhySize: prop = _phySize; break; + case kpidName: SetUnicodeString(_arc.Header.Name, prop); break; + case kpidCTime: SetTime(_arc.Header.CTime, prop); break; + case kpidMTime: SetTime(_arc.Header.MTime, prop); break; + case kpidHostOS: SetHostOS(_arc.Header.HostOS, prop); break; + case kpidComment: SetUnicodeString(_arc.Header.Comment, prop); break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_arc.IsArc) v |= kpv_ErrorFlags_IsNotArc; + switch (_arc.Error) + { + case k_ErrorType_UnexpectedEnd: v |= kpv_ErrorFlags_UnexpectedEnd; break; + case k_ErrorType_Corrupted: v |= kpv_ErrorFlags_HeadersError; break; + } + prop = v; + break; + } } prop.Detach(value); return S_OK; @@ -556,16 +531,16 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; const CItem &item = _items[index]; - switch(propID) + switch (propID) { case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break; case kpidIsDir: prop = item.IsDir(); break; case kpidSize: prop = item.Size; break; case kpidPackSize: prop = item.PackSize; break; case kpidPosition: if (item.IsSplitBefore() || item.IsSplitAfter()) prop = (UInt64)item.SplitPos; break; - case kpidAttrib: prop = item.GetWinAttributes(); break; + case kpidAttrib: prop = item.GetWinAttrib(); break; case kpidEncrypted: prop = item.IsEncrypted(); break; case kpidCRC: prop = item.FileCRC; break; case kpidMethod: prop = item.Method; break; @@ -578,75 +553,88 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_END } -HRESULT CHandler::Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *callback) +HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback) { Close(); UInt64 endPos = 0; - if (callback != NULL) - { - RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); - RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); - } + RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); - _archive.Stream = inStream; - _archive.Callback = callback; - _archive.NumFiles = _archive.NumBytes = 0; + _arc.Stream = inStream; + _arc.Callback = callback; + _arc.NumFiles = 0; + _arc.Processed = 0; + + RINOK(_arc.Open()); + + _phySize = _arc.Processed; + if (_arc.Header.ArchiveSize != 0) + _phySize = (UInt64)_arc.Header.ArchiveSize + _arc.Header.SecurSize; - RINOK(_archive.Open(maxCheckStartPosition)); - if (callback != NULL) - RINOK(callback->SetTotal(NULL, &endPos)); for (;;) { CItem item; bool filled; + _arc.Error = k_ErrorType_OK; + RINOK(_arc.GetNextItem(item, filled)); - RINOK(_archive.GetNextItem(filled, item)); - - RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &item.DataPosition)); + if (_arc.Error != k_ErrorType_OK) + break; if (!filled) + { + if (_arc.Error == k_ErrorType_OK) + if (_arc.Header.ArchiveSize == 0) + _phySize = _arc.Processed; break; + } + item.DataPosition = _arc.Processed; _items.Add(item); - if (inStream->Seek(item.PackSize, STREAM_SEEK_CUR, NULL) != S_OK) - throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive); + UInt64 pos = item.DataPosition + item.PackSize; + if (_arc.Header.ArchiveSize == 0) + _phySize = pos; + if (pos > endPos) + { + _arc.Error = k_ErrorType_UnexpectedEnd; + break; + } - _archive.NumFiles = _items.Size(); - _archive.NumBytes = item.DataPosition; + RINOK(inStream->Seek(pos, STREAM_SEEK_SET, NULL)); + _arc.NumFiles = _items.Size(); + _arc.Processed = pos; - if (callback != NULL && _items.Size() % 100 == 0) + if (callback && (_items.Size() & 0xFF) == 0) { - RINOK(callback->SetCompleted(&_archive.NumFiles, &_archive.NumBytes)); + RINOK(callback->SetCompleted(&_arc.NumFiles, &_arc.Processed)); } } return S_OK; } STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) + const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback) { COM_TRY_BEGIN HRESULT res; - try { - res = Open2(inStream, maxCheckStartPosition, callback); + res = Open2(inStream, callback); if (res == S_OK) { _stream = inStream; return S_OK; } } - catch(const CInArchiveException &) { res = S_FALSE; } - Close(); return res; COM_TRY_END } STDMETHODIMP CHandler::Close() { + _arc.Close(); + _phySize = 0; _items.Clear(); _stream.Release(); return S_OK; @@ -657,7 +645,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { COM_TRY_BEGIN UInt64 totalUnpacked = 0, totalPacked = 0; - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (numItems == 0) @@ -736,28 +724,28 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 opRes = NExtract::NOperationResult::kOK; if (item.IsEncrypted()) - opRes = NExtract::NOperationResult::kUnSupportedMethod; + opRes = NExtract::NOperationResult::kUnsupportedMethod; else { - switch(item.Method) + switch (item.Method) { - case NFileHeader::NCompressionMethod::kStored: + case NCompressionMethod::kStored: { result = copyCoder->Code(inStream, outStream, NULL, NULL, progress); if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize) result = S_FALSE; break; } - case NFileHeader::NCompressionMethod::kCompressed1a: - case NFileHeader::NCompressionMethod::kCompressed1b: - case NFileHeader::NCompressionMethod::kCompressed1c: + case NCompressionMethod::kCompressed1a: + case NCompressionMethod::kCompressed1b: + case NCompressionMethod::kCompressed1c: { if (!arj1Decoder) arj1Decoder = new NCompress::NArj::NDecoder1::CCoder; result = arj1Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress); break; } - case NFileHeader::NCompressionMethod::kCompressed2: + case NCompressionMethod::kCompressed2: { if (!arj2Decoder) arj2Decoder = new NCompress::NArj::NDecoder2::CCoder; @@ -765,7 +753,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, break; } default: - opRes = NExtract::NOperationResult::kUnSupportedMethod; + opRes = NExtract::NOperationResult::kUnsupportedMethod; } } if (opRes == NExtract::NOperationResult::kOK) @@ -788,10 +776,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"Arj", L"arj", 0, 4, { 0x60, 0xEA }, 2, false, CreateArc, 0 }; + { "Arj", "arj", 0, 4, + 2, { kSig0, kSig1 }, + 0, + 0, + CreateArc, NULL, IsArc_Arj }; REGISTER_ARC(Arj) diff --git a/CPP/7zip/Archive/Bz2Handler.cpp b/CPP/7zip/Archive/Bz2Handler.cpp index 49ae8c79..704cdc73 100755..100644 --- a/CPP/7zip/Archive/Bz2Handler.cpp +++ b/CPP/7zip/Archive/Bz2Handler.cpp @@ -2,7 +2,7 @@ #include "StdAfx.h" -#include "Common/ComTry.h" +#include "../../Common/ComTry.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" @@ -29,37 +29,70 @@ class CHandler: { CMyComPtr<IInStream> _stream; CMyComPtr<ISequentialInStream> _seqStream; + + bool _isArc; + bool _needSeekToStart; + bool _dataAfterEnd; + bool _needMoreInput; + + bool _packSize_Defined; + bool _unpackSize_Defined; + bool _numStreams_Defined; + bool _numBlocks_Defined; + UInt64 _packSize; - UInt64 _startPosition; - bool _packSizeDefined; + UInt64 _unpackSize; + UInt64 _numStreams; + UInt64 _numBlocks; CSingleMethodProps _props; public: - MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties) - + MY_UNKNOWN_IMP4( + IInArchive, + IArchiveOpenSeq, + IOutArchive, + ISetProperties) INTERFACE_IInArchive(;) INTERFACE_IOutArchive(;) STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps); + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); CHandler() { } }; -static const STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPackSize, VT_UI8} + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidNumStreams, + kpidNumBlocks }; IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table +IMP_IInArchive_ArcProps STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { - case kpidPhySize: if (_packSizeDefined) prop = _packSize; break; + case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; + case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break; + case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break; + case kpidNumBlocks: if (_numBlocks_Defined) prop = _numBlocks; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; + if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; + prop = v; + } } prop.Detach(value); return S_OK; @@ -71,54 +104,75 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; switch (propID) { - case kpidPackSize: if (_packSizeDefined) prop = _packSize; break; + case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; + case kpidSize: if (_unpackSize_Defined) prop = _unpackSize; break; } prop.Detach(value); return S_OK; } -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) +static const unsigned kSignatureCheckSize = 10; + +API_FUNC_static_IsArc IsArc_BZip2(const Byte *p, size_t size) +{ + if (size < kSignatureCheckSize) + return k_IsArc_Res_NEED_MORE; + if (p[0] != 'B' || p[1] != 'Z' || p[2] != 'h' || p[3] < '1' || p[3] > '9') + return k_IsArc_Res_NO; + p += 4; + if (NCompress::NBZip2::IsBlockSig(p)) + return k_IsArc_Res_YES; + if (NCompress::NBZip2::IsEndSig(p)) + return k_IsArc_Res_YES; + return k_IsArc_Res_NO; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) { COM_TRY_BEGIN - try + Close(); { - Close(); - RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPosition)); - const int kSignatureSize = 3; - Byte buf[kSignatureSize]; - RINOK(ReadStream_FALSE(stream, buf, kSignatureSize)); - if (buf[0] != 'B' || buf[1] != 'Z' || buf[2] != 'h') + Byte buf[kSignatureCheckSize]; + RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize)); + if (IsArc_BZip2(buf, kSignatureCheckSize) == k_IsArc_Res_NO) return S_FALSE; - - UInt64 endPosition; - RINOK(stream->Seek(0, STREAM_SEEK_END, &endPosition)); - _packSize = endPosition - _startPosition; - _packSizeDefined = true; + _isArc = true; _stream = stream; _seqStream = stream; + _needSeekToStart = true; } - catch(...) { return S_FALSE; } return S_OK; COM_TRY_END } + STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) { Close(); + _isArc = true; _seqStream = stream; return S_OK; } STDMETHODIMP CHandler::Close() { - _packSizeDefined = false; + _isArc = false; + _needSeekToStart = false; + _dataAfterEnd = false; + _needMoreInput = false; + + _packSize_Defined = false; + _unpackSize_Defined = false; + _numStreams_Defined = false; + _numBlocks_Defined = false; + + _packSize = 0; + _seqStream.Release(); _stream.Release(); return S_OK; @@ -130,13 +184,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_BEGIN if (numItems == 0) return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; - if (_stream) + if (_packSize_Defined) extractCallback->SetTotal(_packSize); - UInt64 currentTotalPacked = 0; - RINOK(extractCallback->SetCompleted(¤tTotalPacked)); + + // RINOK(extractCallback->SetCompleted(&packSize)); + CMyComPtr<ISequentialOutStream> realOutStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : @@ -147,14 +202,23 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, extractCallback->PrepareOperation(askMode); - NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder; - CMyComPtr<ICompressCoder> decoder = decoderSpec; - if (_stream) + if (_needSeekToStart) { - RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL)); + if (!_stream) + return E_FAIL; + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); } + else + _needSeekToStart = true; + + Int32 opRes; + + try + { + NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder; + CMyComPtr<ICompressCoder> decoder = decoderSpec; decoderSpec->SetInStream(_seqStream); #ifndef _7ZIP_ST @@ -172,43 +236,104 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, true); + UInt64 packSize = 0; + UInt64 unpackedSize = 0; + UInt64 numStreams = 0; + + decoderSpec->InitNumBlocks(); + HRESULT result = S_OK; - bool firstItem = true; for (;;) { - lps->InSize = currentTotalPacked; - lps->OutSize = outStreamSpec->GetSize(); + lps->InSize = packSize; + lps->OutSize = unpackedSize; RINOK(lps->SetCur()); - bool isBz2; - result = decoderSpec->CodeResume(outStream, isBz2, progress); + result = decoderSpec->CodeResume(outStream, progress); - if (result != S_OK) + if (result != S_FALSE && result != S_OK) + return result; + + if (decoderSpec->IsBz) + numStreams++; + else if (numStreams == 0) + { + _isArc = false; + result = S_FALSE; + break; + } + + unpackedSize = outStreamSpec->GetSize(); + UInt64 streamSize = decoderSpec->GetStreamSize(); + + if (streamSize == packSize) + { + // no new bytes in input stream, So it's good end of archive. + result = S_OK; + break; + } + + if (!decoderSpec->IsBz) + { + _dataAfterEnd = true; + result = S_FALSE; break; - if (!isBz2) + } + + if (decoderSpec->Base.BitDecoder.ExtraBitsWereRead()) { - if (firstItem) - result = S_FALSE; + _needMoreInput = true; + packSize = streamSize; + result = S_FALSE; break; } - firstItem = false; - _packSize = currentTotalPacked = decoderSpec->GetInputProcessedSize(); - _packSizeDefined = true; + packSize = decoderSpec->GetInputProcessedSize(); + + if (packSize > streamSize) + return E_FAIL; + + if (result != S_OK) + break; } + + if (numStreams != 0) + { + _packSize = packSize; + _unpackSize = unpackedSize; + _numStreams = numStreams; + _numBlocks = decoderSpec->GetNumBlocks(); + + _packSize_Defined = true; + _unpackSize_Defined = true; + _numStreams_Defined = true; + _numBlocks_Defined = true; + } + decoderSpec->ReleaseInStream(); outStream.Release(); - Int32 retResult; - if (result == S_OK) - retResult = NExtract::NOperationResult::kOK; + if (!_isArc) + opRes = NExtract::NOperationResult::kIsNotArc; + else if (_needMoreInput) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + else if (decoderSpec->CrcError) + opRes = NExtract::NOperationResult::kCRCError; + else if (_dataAfterEnd) + opRes = NExtract::NOperationResult::kDataAfterEnd; else if (result == S_FALSE) - retResult = NExtract::NOperationResult::kDataError; + opRes = NExtract::NOperationResult::kDataError; + else if (result == S_OK) + opRes = NExtract::NOperationResult::kOK; else return result; - return extractCallback->SetOperationResult(retResult); + + } + catch(const CInBufferException &e) { return e.ErrorCode; } + + return extractCallback->SetOperationResult(opRes); COM_TRY_END } @@ -280,24 +405,24 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (indexInArchive != 0) return E_INVALIDARG; if (_stream) - RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL)); + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); return NCompress::CopyStream(_stream, outStream, NULL); } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { return _props.SetProperties(names, values, numProps); } -static IInArchive *CreateArc() { return new CHandler; } -#ifndef EXTRACT_ONLY -static IOutArchive *CreateArcOut() { return new CHandler; } -#else -#define CreateArcOut 0 -#endif +IMP_CreateArcIn +IMP_CreateArcOut static CArcInfo g_ArcInfo = - { L"bzip2", L"bz2 bzip2 tbz2 tbz", L"* * .tar .tar", 2, { 'B', 'Z', 'h' }, 3, true, CreateArc, CreateArcOut }; + { "bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2, + 3, { 'B', 'Z', 'h' }, + 0, + NArcInfoFlags::kKeepName, + REF_CreateArc_Pair, IsArc_BZip2 }; REGISTER_ARC(BZip2) diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp index 12c73eb5..cebec610 100755..100644 --- a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp +++ b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp @@ -3,8 +3,7 @@ #include "StdAfx.h" #include "../../../../C/Alloc.h" - -#include "Common/Defs.h" +#include "../../../../C/CpuArch.h" #include "../../Common/StreamUtils.h" @@ -17,173 +16,73 @@ static const UInt32 kBlockSize = (1 << 16); bool CCabBlockInStream::Create() { - if (!_buffer) - _buffer = (Byte *)::MyAlloc(kBlockSize); - return (_buffer != 0); + if (!_buf) + _buf = (Byte *)::MyAlloc(kBlockSize); + return _buf != 0; } CCabBlockInStream::~CCabBlockInStream() { - MyFree(_buffer); + ::MyFree(_buf); } -class CCheckSum2 -{ - UInt32 m_Value; - int m_Pos; - Byte m_Hist[4]; -public: - CCheckSum2(): m_Value(0){}; - void Init() { m_Value = 0; m_Pos = 0; } - void Update(const void *data, UInt32 size); - void FinishDataUpdate() - { - for (int i = 0; i < m_Pos; i++) - m_Value ^= ((UInt32)(m_Hist[i])) << (8 * (m_Pos - i - 1)); - } - void UpdateUInt32(UInt32 v) { m_Value ^= v; } - UInt32 GetResult() const { return m_Value; } -}; - -void CCheckSum2::Update(const void *data, UInt32 size) +static UInt32 CheckSum(const Byte *p, UInt32 size) { - UInt32 checkSum = m_Value; - const Byte *dataPointer = (const Byte *)data; - - while (size != 0 && m_Pos != 0) - { - m_Hist[m_Pos] = *dataPointer++; - m_Pos = (m_Pos + 1) & 3; - size--; - if (m_Pos == 0) - for (int i = 0; i < 4; i++) - checkSum ^= ((UInt32)m_Hist[i]) << (8 * i); - } - - int numWords = size / 4; - - while (numWords-- != 0) + UInt32 sum = 0; + for (UInt32 i = size >> 2; i != 0; i--) { - UInt32 temp = *dataPointer++; - temp |= ((UInt32)(*dataPointer++)) << 8; - temp |= ((UInt32)(*dataPointer++)) << 16; - temp |= ((UInt32)(*dataPointer++)) << 24; - checkSum ^= temp; + sum ^= GetUi32(p); + p += 4; } - m_Value = checkSum; - size &= 3; - - while (size != 0) - { - m_Hist[m_Pos] = *dataPointer++; - m_Pos = (m_Pos + 1) & 3; - size--; - } + if (size > 2) sum ^= (UInt32)(*p++) << 16; + if (size > 1) sum ^= (UInt32)(*p++) << 8; + if (size > 0) sum ^= (UInt32)(*p++); + return sum; } -static const UInt32 kDataBlockHeaderSize = 8; - -class CTempCabInBuffer2 +HRESULT CCabBlockInStream::PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize) { -public: - Byte Buffer[kDataBlockHeaderSize]; - UInt32 Pos; - Byte ReadByte() - { - return Buffer[Pos++]; - } - UInt32 ReadUInt32() - { - UInt32 value = 0; - for (int i = 0; i < 4; i++) - value |= (((UInt32)ReadByte()) << (8 * i)); - return value; - } - UInt16 ReadUInt16() - { - UInt16 value = 0; - for (int i = 0; i < 2; i++) - value |= (((UInt16)ReadByte()) << (8 * i)); - return value; - } -}; - -HRESULT CCabBlockInStream::PreRead(UInt32 &packSize, UInt32 &unpackSize) -{ - CTempCabInBuffer2 inBuffer; - inBuffer.Pos = 0; - RINOK(ReadStream_FALSE(_stream, inBuffer.Buffer, kDataBlockHeaderSize)) - - UInt32 checkSum = inBuffer.ReadUInt32(); - packSize = inBuffer.ReadUInt16(); - unpackSize = inBuffer.ReadUInt16(); - if (ReservedSize != 0) - { - RINOK(ReadStream_FALSE(_stream, _buffer, ReservedSize)); - } - _pos = 0; - CCheckSum2 checkSumCalc; - checkSumCalc.Init(); - UInt32 packSize2 = packSize; - if (MsZip && _size == 0) + const UInt32 kHeaderSize = 8; + const UInt32 kReservedMax = 256; + Byte header[kHeaderSize + kReservedMax]; + RINOK(ReadStream_FALSE(stream, header, kHeaderSize + ReservedSize)) + packSize = GetUi16(header + 4); + unpackSize = GetUi16(header + 6); + if (packSize > kBlockSize - _size) + return S_FALSE; + RINOK(ReadStream_FALSE(stream, _buf + _size, packSize)); + + if (MsZip) { - if (packSize < 2) - return S_FALSE; // bad block; - Byte sig[2]; - RINOK(ReadStream_FALSE(_stream, sig, 2)); - if (sig[0] != 0x43 || sig[1] != 0x4B) + if (_size == 0) + { + if (packSize < 2 || _buf[0] != 0x43 || _buf[1] != 0x4B) + return S_FALSE; + _pos = 2; + } + if (_size + packSize > ((UInt32)1 << 15) + 12) /* v9.31 fix. MSZIP specification */ return S_FALSE; - packSize2 -= 2; - checkSumCalc.Update(sig, 2); } - if (kBlockSize - _size < packSize2) - return S_FALSE; - - UInt32 curSize = packSize2; - if (curSize != 0) - { - size_t processedSizeLoc = curSize; - RINOK(ReadStream(_stream, _buffer + _size, &processedSizeLoc)); - checkSumCalc.Update(_buffer + _size, (UInt32)processedSizeLoc); - _size += (UInt32)processedSizeLoc; - if (processedSizeLoc != curSize) + if (GetUi32(header) != 0) // checkSum + if (CheckSum(header, kHeaderSize + ReservedSize) != CheckSum(_buf + _size, packSize)) return S_FALSE; - } - TotalPackSize = _size; - checkSumCalc.FinishDataUpdate(); - - bool dataError; - if (checkSum == 0) - dataError = false; - else - { - checkSumCalc.UpdateUInt32(packSize | (((UInt32)unpackSize) << 16)); - dataError = (checkSumCalc.GetResult() != checkSum); - } - DataError |= dataError; - return dataError ? S_FALSE : S_OK; + _size += packSize; + return S_OK; } STDMETHODIMP CCabBlockInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { - if (processedSize != 0) - *processedSize = 0; - if (size == 0) - return S_OK; - if (_size != 0) - { - size = MyMin(_size, size); - memmove(data, _buffer + _pos, size); - _pos += size; - _size -= size; - if (processedSize != 0) - *processedSize = size; - return S_OK; - } - return S_OK; // no blocks data + UInt32 rem = _size - _pos; + if (size > rem) + size = rem; + memcpy(data, _buf + _pos, size); + _pos += size; + if (processedSize) + *processedSize = size; + return S_OK; } }} diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.h b/CPP/7zip/Archive/Cab/CabBlockInStream.h index 1db3835b..b795ed97 100755..100644 --- a/CPP/7zip/Archive/Cab/CabBlockInStream.h +++ b/CPP/7zip/Archive/Cab/CabBlockInStream.h @@ -1,9 +1,9 @@ -// CabBlockInStream.cpp +// CabBlockInStream.h -#ifndef __CABBLOCKINSTREAM_H -#define __CABBLOCKINSTREAM_H +#ifndef __CAB_BLOCK_IN_STREAM_H +#define __CAB_BLOCK_IN_STREAM_H -#include "Common/MyCom.h" +#include "../../../Common/MyCom.h" #include "../../IStream.h" namespace NArchive { @@ -13,30 +13,23 @@ class CCabBlockInStream: public ISequentialInStream, public CMyUnknownImp { - CMyComPtr<ISequentialInStream> _stream; - Byte *_buffer; - UInt32 _pos; + Byte *_buf; UInt32 _size; + UInt32 _pos; public: - UInt32 TotalPackSize; - UInt32 ReservedSize; - bool DataError; + UInt32 ReservedSize; // < 256 bool MsZip; - CCabBlockInStream(): _buffer(0), ReservedSize(0), MsZip(false), DataError(false), TotalPackSize(0) {} + MY_UNKNOWN_IMP + + CCabBlockInStream(): _buf(0), ReservedSize(0), MsZip(false) {} ~CCabBlockInStream(); bool Create(); - void SetStream(ISequentialInStream *stream) { _stream = stream; } - - void InitForNewFolder() { TotalPackSize = 0; } - void InitForNewBlock() { _size = 0; } - - MY_UNKNOWN_IMP + void InitForNewBlock() { _size = 0; _pos = 0; } + HRESULT PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize); STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - - HRESULT PreRead(UInt32 &packSize, UInt32 &unpackSize); }; }} diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp index fd707fe5..22bc93a0 100755..100644 --- a/CPP/7zip/Archive/Cab/CabHandler.cpp +++ b/CPP/7zip/Archive/Cab/CabHandler.cpp @@ -2,15 +2,17 @@ #include "StdAfx.h" +// #include <stdio.h> + #include "../../../../C/Alloc.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/StringConvert.h" -#include "Common/UTFConvert.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamUtils.h" @@ -39,102 +41,243 @@ enum }; #endif -static STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidAttrib, VT_UI4}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidBlock, VT_I4} + kpidPath, + kpidSize, + kpidMTime, + kpidAttrib, + kpidMethod, + kpidBlock #ifdef _CAB_DETAILS , - { L"BlockReal", kpidBlockReal, VT_UI4}, - { NULL, kpidOffset, VT_UI4}, - { NULL, kpidVolume, VT_UI4} + // kpidBlockReal, // L"BlockReal", + kpidOffset, + kpidVolume #endif }; -static const char *kMethods[] = +static const Byte kArcProps[] = { - "None", - "MSZip", - "Quantum", - "LZX" + kpidTotalPhySize, + kpidMethod, + // kpidSolid, + kpidNumBlocks, + kpidNumVolumes, + kpidVolumeIndex, + kpidId }; -static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]); -static const char *kUnknownMethod = "Unknown"; +IMP_IInArchive_Props +IMP_IInArchive_ArcProps -static STATPROPSTG kArcProps[] = +static const char *kMethods[] = { - { NULL, kpidMethod, VT_BSTR}, - // { NULL, kpidSolid, VT_BOOL}, - { NULL, kpidNumBlocks, VT_UI4}, - { NULL, kpidNumVolumes, VT_UI4} + "None" + , "MSZip" + , "Quantum" + , "LZX" }; -IMP_IInArchive_Props -IMP_IInArchive_ArcProps +static const unsigned kMethodNameBufSize = 32; // "Quantum:255" + +static void SetMethodName(char *s, unsigned method, unsigned param) +{ + if (method < ARRAY_SIZE(kMethods)) + { + s = MyStpCpy(s, kMethods[method]); + if (method != NHeader::NMethod::kLZX && + method != NHeader::NMethod::kQuantum) + return; + *s++ = ':'; + method = param; + } + ConvertUInt32ToString(method, s); +} STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) + NCOM::CPropVariant prop; + switch (propID) { case kpidMethod: { - AString resString; - CRecordVector<Byte> ids; - int i; - for (int v = 0; v < m_Database.Volumes.Size(); v++) + UInt32 mask = 0; + UInt32 params[2] = { 0, 0 }; { - const CDatabaseEx &de = m_Database.Volumes[v]; - for (i = 0; i < de.Folders.Size(); i++) - ids.AddToUniqueSorted(de.Folders[i].GetCompressionMethod()); + FOR_VECTOR (v, m_Database.Volumes) + { + const CRecordVector<CFolder> &folders = m_Database.Volumes[v].Folders; + FOR_VECTOR (i, folders) + { + const CFolder &folder = folders[i]; + unsigned method = folder.GetMethod(); + mask |= ((UInt32)1 << method); + if (method == NHeader::NMethod::kLZX || + method == NHeader::NMethod::kQuantum) + { + unsigned di = (method == NHeader::NMethod::kQuantum) ? 0 : 1; + if (params[di] < folder.MethodMinor) + params[di] = folder.MethodMinor; + } + } + } } - for (i = 0; i < ids.Size(); i++) + AString s; + for (unsigned i = 0; i < kNumMethodsMax; i++) { - Byte id = ids[i]; - AString method = (id < kNumMethods) ? kMethods[id] : kUnknownMethod; - if (!resString.IsEmpty()) - resString += ' '; - resString += method; + if ((mask & (1 << i)) == 0) + continue; + if (!s.IsEmpty()) + s += ' '; + char temp[kMethodNameBufSize]; + SetMethodName(temp, i, params[i == NHeader::NMethod::kQuantum ? 0 : 1]); + s += temp; } - prop = resString; + prop = s; break; } // case kpidSolid: prop = _database.IsSolid(); break; case kpidNumBlocks: { UInt32 numFolders = 0; - for (int v = 0; v < m_Database.Volumes.Size(); v++) + FOR_VECTOR (v, m_Database.Volumes) numFolders += m_Database.Volumes[v].Folders.Size(); prop = numFolders; break; } - case kpidNumVolumes: + + case kpidTotalPhySize: { + if (m_Database.Volumes.Size() > 1) + { + UInt64 sum = 0; + FOR_VECTOR (v, m_Database.Volumes) + sum += m_Database.Volumes[v].ArcInfo.Size; + prop = sum; + } + break; + } + + case kpidNumVolumes: prop = (UInt32)m_Database.Volumes.Size(); break; + + case kpidVolumeIndex: + { + if (m_Database.Volumes.Size() == 1) + { + const CDatabaseEx &db = m_Database.Volumes[0]; + const CInArcInfo &ai = db.ArcInfo; + prop = (UInt32)ai.CabinetNumber; + } + break; + } + + case kpidId: + { + if (m_Database.Volumes.Size() != 0) + { + prop = (UInt32)m_Database.Volumes[0].ArcInfo.SetID; + } + break; + } + + case kpidOffset: + /* + if (m_Database.Volumes.Size() == 1) + prop = m_Database.Volumes[0].StartPosition; + */ + prop = _offset; + break; + + case kpidPhySize: + /* + if (m_Database.Volumes.Size() == 1) + prop = (UInt64)m_Database.Volumes[0].ArcInfo.Size; + */ + prop = (UInt64)_phySize; + break; + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_errorInHeaders) v |= kpv_ErrorFlags_HeadersError; + if (_unexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + prop = v; + break; + } + + case kpidError: + if (!_errorMessage.IsEmpty()) + prop = _errorMessage; + break; + + case kpidName: + { + if (m_Database.Volumes.Size() == 1) + { + const CDatabaseEx &db = m_Database.Volumes[0]; + const CInArcInfo &ai = db.ArcInfo; + if (ai.SetID != 0) + { + AString s; + char temp[32]; + ConvertUInt32ToString(ai.SetID, temp); + s += temp; + ConvertUInt32ToString(ai.CabinetNumber + 1, temp); + s += '_'; + s += temp; + s += ".cab"; + prop = s; + } + /* + // that code is incomplete. It gcan give accurate name of volume + char s[32]; + ConvertUInt32ToString(ai.CabinetNumber + 2, s); + unsigned len = MyStringLen(s); + if (ai.IsThereNext()) + { + AString fn = ai.NextArc.FileName; + if (fn.Len() > 4 && StringsAreEqualNoCase_Ascii(fn.RightPtr(4), ".cab")) + fn.DeleteFrom(fn.Len() - 4); + if (len < fn.Len()) + { + if (strcmp(s, fn.RightPtr(len)) == 0) + { + AString s2 = fn; + s2.DeleteFrom(fn.Len() - len); + ConvertUInt32ToString(ai.CabinetNumber + 1, s); + s2 += s; + s2 += ".cab"; + prop = GetUnicodeString(s2); + } + } + } + */ + } + break; } + + // case kpidShortComment: } prop.Detach(value); return S_OK; COM_TRY_END } -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; const CMvItem &mvItem = m_Database.Items[index]; const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; - int itemIndex = mvItem.ItemIndex; + unsigned itemIndex = mvItem.ItemIndex; const CItem &item = db.Items[itemIndex]; - switch(propID) + switch (propID) { case kpidPath: { @@ -146,9 +289,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va prop = (const wchar_t *)NItemName::WinNameToOSName(unicodeName); break; } + case kpidIsDir: prop = item.IsDir(); break; case kpidSize: prop = item.Size; break; - case kpidAttrib: prop = item.GetWinAttributes(); break; + case kpidAttrib: prop = item.GetWinAttrib(); break; case kpidMTime: { @@ -168,24 +312,17 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va { UInt32 realFolderIndex = item.GetFolderIndex(db.Folders.Size()); const CFolder &folder = db.Folders[realFolderIndex]; - int methodIndex = folder.GetCompressionMethod(); - AString method = (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod; - if (methodIndex == NHeader::NCompressionMethodMajor::kLZX || - methodIndex == NHeader::NCompressionMethodMajor::kQuantum) - { - method += ':'; - char temp[32]; - ConvertUInt64ToString(folder.CompressionTypeMinor, temp); - method += temp; - } - prop = method; + char s[kMethodNameBufSize];; + SetMethodName(s, folder.GetMethod(), folder.MethodMinor); + prop = s; break; } + case kpidBlock: prop = (Int32)m_Database.GetFolderIndex(&mvItem); break; #ifdef _CAB_DETAILS - case kpidBlockReal: prop = (UInt32)item.FolderIndex; break; + // case kpidBlockReal: prop = (UInt32)item.FolderIndex; break; case kpidOffset: prop = (UInt32)item.Offset; break; case kpidVolume: prop = (UInt32)mvItem.VolumeIndex; break; @@ -196,39 +333,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va COM_TRY_END } -/* -class CProgressImp: public CProgressVirt -{ - CMyComPtr<IArchiveOpenCallback> m_OpenArchiveCallback; -public: - STDMETHOD(SetTotal)(const UInt64 *numFiles); - STDMETHOD(SetCompleted)(const UInt64 *numFiles); - void Init(IArchiveOpenCallback *openArchiveCallback) - { m_OpenArchiveCallback = openArchiveCallback; } -}; - -STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles) -{ - if (m_OpenArchiveCallback) - return m_OpenArchiveCallback->SetCompleted(numFiles, NULL); - return S_OK; -} - -STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles) -{ - if (m_OpenArchiveCallback) - return m_OpenArchiveCallback->SetCompleted(numFiles, NULL); - return S_OK; -} -*/ - STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) { COM_TRY_BEGIN Close(); - HRESULT res = S_FALSE; + CInArchive archive; CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); @@ -236,96 +347,169 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, CMyComPtr<IInStream> nextStream = inStream; bool prevChecked = false; UInt64 numItems = 0; - try + unsigned numTempVolumes = 0; + // try { - while (nextStream != 0) + while (nextStream != NULL) { CDatabaseEx db; db.Stream = nextStream; - res = archive.Open(maxCheckStartPosition, db); - if (res == S_OK) + HRESULT res = archive.Open(db, maxCheckStartPosition); + _errorInHeaders |= archive.HeaderError; + _errorInHeaders |= archive.ErrorInNames; + _unexpectedEnd |= archive.UnexpectedEnd; + + if (res == S_OK && !m_Database.Volumes.IsEmpty()) { - if (!m_Database.Volumes.IsEmpty()) + const CArchInfo &lastArc = m_Database.Volumes.Back().ArcInfo; + unsigned cabNumber = db.ArcInfo.CabinetNumber; + if (lastArc.SetID != db.ArcInfo.SetID) + res = S_FALSE; + else if (prevChecked) + { + if (cabNumber != lastArc.CabinetNumber + 1) + res = S_FALSE; + } + else if (cabNumber >= lastArc.CabinetNumber) + res = S_FALSE; + else if (numTempVolumes != 0) { - const CDatabaseEx &dbPrev = m_Database.Volumes[prevChecked ? m_Database.Volumes.Size() - 1 : 0]; - if (dbPrev.ArchiveInfo.SetID != db.ArchiveInfo.SetID || - dbPrev.ArchiveInfo.CabinetNumber + (prevChecked ? 1: - 1) != - db.ArchiveInfo.CabinetNumber) + const CArchInfo &prevArc = m_Database.Volumes[numTempVolumes - 1].ArcInfo; + if (cabNumber != prevArc.CabinetNumber + 1) res = S_FALSE; } } + + if (archive.IsArc || res == S_OK) + { + _isArc = true; + if (m_Database.Volumes.IsEmpty()) + { + _offset = db.StartPosition; + _phySize = db.ArcInfo.Size; + } + } + if (res == S_OK) - m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : 0, db); - else if (res != S_FALSE) - return res; + { + numItems += db.Items.Size(); + m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : numTempVolumes, db); + if (!prevChecked && m_Database.Volumes.Size() > 1) + { + numTempVolumes++; + if (db.ArcInfo.CabinetNumber + 1 == m_Database.Volumes[numTempVolumes].ArcInfo.CabinetNumber) + numTempVolumes = 0; + } + } else { + if (res != S_FALSE) + return res; if (m_Database.Volumes.IsEmpty()) return S_FALSE; if (prevChecked) break; prevChecked = true; + if (numTempVolumes != 0) + { + m_Database.Volumes.DeleteFrontal(numTempVolumes); + numTempVolumes = 0; + } } - numItems += db.Items.Size(); RINOK(callback->SetCompleted(&numItems, NULL)); - nextStream = 0; + nextStream = NULL; + for (;;) { - const COtherArchive *otherArchive = 0; + const COtherArc *otherArc = NULL; if (!prevChecked) { - const CInArchiveInfo &ai = m_Database.Volumes.Front().ArchiveInfo; - if (ai.IsTherePrev()) - otherArchive = &ai.PrevArc; + if (numTempVolumes == 0) + { + const CInArcInfo &ai = m_Database.Volumes[0].ArcInfo; + if (ai.IsTherePrev()) + otherArc = &ai.PrevArc; + else + prevChecked = true; + } else - prevChecked = true; + { + const CInArcInfo &ai = m_Database.Volumes[numTempVolumes - 1].ArcInfo; + if (ai.IsThereNext()) + otherArc = &ai.NextArc; + else + { + prevChecked = true; + m_Database.Volumes.DeleteFrontal(numTempVolumes); + numTempVolumes = 0; + } + } } - if (otherArchive == 0) + if (!otherArc) { - const CInArchiveInfo &ai = m_Database.Volumes.Back().ArchiveInfo; + const CInArcInfo &ai = m_Database.Volumes.Back().ArcInfo; if (ai.IsThereNext()) - otherArchive = &ai.NextArc; + otherArc = &ai.NextArc; } - if (!otherArchive) + if (!otherArc) break; - const UString fullName = MultiByteToUnicodeString(otherArchive->FileName, CP_ACP); if (!openVolumeCallback) break; - + // printf("\n%s", otherArc->FileName); + const UString fullName = MultiByteToUnicodeString(otherArc->FileName, CP_ACP); HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream); if (result == S_OK) break; if (result != S_FALSE) return result; + + if (!_errorMessage.IsEmpty()) + _errorMessage += L"\n"; + _errorMessage += L"Can't open volume: "; + _errorMessage += fullName; + if (prevChecked) break; prevChecked = true; + if (numTempVolumes != 0) + { + m_Database.Volumes.DeleteFrontal(numTempVolumes); + numTempVolumes = 0; + } } + + } // read nextStream iteration + + if (numTempVolumes != 0) + { + m_Database.Volumes.DeleteFrontal(numTempVolumes); + numTempVolumes = 0; } - if (res == S_OK) + if (m_Database.Volumes.IsEmpty()) + return S_FALSE; + else { m_Database.FillSortAndShrink(); if (!m_Database.Check()) - res = S_FALSE; + return S_FALSE; } } - catch(...) - { - res = S_FALSE; - } - if (res != S_OK) - { - Close(); - return res; - } COM_TRY_END return S_OK; } STDMETHODIMP CHandler::Close() { + _errorMessage.Empty(); + _isArc = false; + _errorInHeaders = false; + _unexpectedEnd = false; + // _mainVolIndex = -1; + _phySize = 0; + _offset = 0; + m_Database.Clear(); return S_OK; } @@ -348,8 +532,8 @@ private: bool TempBufMode; UInt32 m_BufStartFolderOffset; - int m_StartIndex; - int m_CurrentIndex; + unsigned m_StartIndex; + unsigned m_CurrentIndex; CMyComPtr<IArchiveExtractCallback> m_ExtractCallback; bool m_TestMode; @@ -379,7 +563,7 @@ public: void Init( const CMvDatabaseEx *database, const CRecordVector<bool> *extractStatuses, - int startIndex, + unsigned startIndex, UInt64 folderSize, IArchiveExtractCallback *extractCallback, bool testMode); @@ -393,7 +577,7 @@ public: void CFolderOutStream::Init( const CMvDatabaseEx *database, const CRecordVector<bool> *extractStatuses, - int startIndex, + unsigned startIndex, UInt64 folderSize, IArchiveExtractCallback *extractCallback, bool testMode) @@ -436,7 +620,7 @@ HRESULT CFolderOutStream::OpenFile() const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; int numExtractItems = 0; - int curIndex; + unsigned curIndex; for (curIndex = m_CurrentIndex; curIndex < m_ExtractStatuses->Size(); curIndex++) { const CMvItem &mvItem2 = m_Database->Items[m_StartIndex + curIndex]; @@ -559,7 +743,7 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe if (!TempBuf && TempBufMode && m_RealOutStream) { - RINOK(CloseFileWithResOp(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(CloseFileWithResOp(NExtract::NOperationResult::kUnsupportedMethod)); } else { @@ -638,7 +822,7 @@ HRESULT CFolderOutStream::Unsupported() if (result != S_FALSE && result != S_OK) return result; m_RealOutStream.Release(); - RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); m_CurrentIndex++; } return S_OK; @@ -649,7 +833,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testModeSpec, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = m_Database.Items.Size(); if (numItems == 0) @@ -709,7 +893,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, const CMvItem &mvItem = m_Database.Items[index]; const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; - int itemIndex = mvItem.ItemIndex; + unsigned itemIndex = mvItem.ItemIndex; const CItem &item = db.Items[itemIndex]; i++; @@ -747,7 +931,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, extractStatuses.Add(true); startIndex++; UInt64 curUnpack = item.GetEndOffset(); - for(;i < numItems; i++) + for (; i < numItems; i++) { int indexNext = allFilesMode ? i : indices[i]; const CMvItem &mvItem = m_Database.Items[indexNext]; @@ -779,11 +963,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, cabBlockInStreamSpec->MsZip = false; HRESULT res = S_OK; - switch(folder.GetCompressionMethod()) + switch (folder.GetMethod()) { - case NHeader::NCompressionMethodMajor::kNone: + case NHeader::NMethod::kNone: break; - case NHeader::NCompressionMethodMajor::kMSZip: + case NHeader::NMethod::kMSZip: if (!deflateDecoder) { deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder; @@ -791,21 +975,21 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } cabBlockInStreamSpec->MsZip = true; break; - case NHeader::NCompressionMethodMajor::kLZX: + case NHeader::NMethod::kLZX: if (!lzxDecoder) { lzxDecoderSpec = new NCompress::NLzx::CDecoder; lzxDecoder = lzxDecoderSpec; } - res = lzxDecoderSpec->SetParams(folder.CompressionTypeMinor); + res = lzxDecoderSpec->SetParams(folder.MethodMinor); break; - case NHeader::NCompressionMethodMajor::kQuantum: + case NHeader::NMethod::kQuantum: if (!quantumDecoder) { quantumDecoderSpec = new NCompress::NQuantum::CDecoder; quantumDecoder = quantumDecoderSpec; } - res = quantumDecoderSpec->SetParams(folder.CompressionTypeMinor); + res = quantumDecoderSpec->SetParams(folder.MethodMinor); break; default: res = E_INVALIDARG; @@ -820,9 +1004,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } RINOK(res); - cabBlockInStreamSpec->InitForNewFolder(); { - int volIndex = mvItem.VolumeIndex; + unsigned volIndex = mvItem.VolumeIndex; int locFolderIndex = item.GetFolderIndex(db.Folders.Size()); bool keepHistory = false; bool keepInputBuffer = false; @@ -838,8 +1021,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, const CFolder &folder = db.Folders[locFolderIndex]; if (f == 0) { - cabBlockInStreamSpec->SetStream(db.Stream); - cabBlockInStreamSpec->ReservedSize = db.ArchiveInfo.GetDataBlockReserveSize(); + cabBlockInStreamSpec->ReservedSize = db.ArcInfo.GetDataBlockReserveSize(); RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL)); } if (f == folder.NumDataBlocks) @@ -851,13 +1033,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } f++; - cabBlockInStreamSpec->DataError = false; - if (!keepInputBuffer) cabBlockInStreamSpec->InitForNewBlock(); UInt32 packSize, unpackSize; - res = cabBlockInStreamSpec->PreRead(packSize, unpackSize); + res = cabBlockInStreamSpec->PreRead(db.Stream, packSize, unpackSize); if (res == S_FALSE) break; RINOK(res); @@ -878,22 +1058,36 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (unpackRemain > kBlockSizeMax) unpackRemain = kBlockSizeMax; if (unpackRemain > unpackSize) - unpackRemain = unpackSize; + unpackRemain = unpackSize; - switch(folder.GetCompressionMethod()) + switch (folder.GetMethod()) { - case NHeader::NCompressionMethodMajor::kNone: + case NHeader::NMethod::kNone: res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; - case NHeader::NCompressionMethodMajor::kMSZip: - deflateDecoderSpec->SetKeepHistory(keepHistory); + case NHeader::NMethod::kMSZip: + deflateDecoderSpec->Set_KeepHistory(keepHistory); + /* v9.31: now we follow MSZIP specification that requires to finish deflate stream at the end of each block. + But PyCabArc can create CAB archives that doesn't have finish marker at the end of block. + Cabarc probably ignores such errors in cab archives. + Maybe we also should ignore that error? + Or we should extract full file and show the warning? */ + deflateDecoderSpec->Set_NeedFinishInput(true); res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + if (res == S_OK) + { + if (!deflateDecoderSpec->IsFinished()) + res = S_FALSE; + if (!deflateDecoderSpec->IsFinalBlock()) + res = S_FALSE; + } + break; - case NHeader::NCompressionMethodMajor::kLZX: + case NHeader::NMethod::kLZX: lzxDecoderSpec->SetKeepHistory(keepHistory); res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; - case NHeader::NCompressionMethodMajor::kQuantum: + case NHeader::NMethod::kQuantum: quantumDecoderSpec->SetKeepHistory(keepHistory); res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; diff --git a/CPP/7zip/Archive/Cab/CabHandler.h b/CPP/7zip/Archive/Cab/CabHandler.h index 1edcd11e..6f44b875 100755..100644 --- a/CPP/7zip/Archive/Cab/CabHandler.h +++ b/CPP/7zip/Archive/Cab/CabHandler.h @@ -3,8 +3,10 @@ #ifndef __CAB_HANDLER_H #define __CAB_HANDLER_H -#include "Common/MyCom.h" +#include "../../../Common/MyCom.h" + #include "../IArchive.h" + #include "CabIn.h" namespace NArchive { @@ -21,6 +23,13 @@ public: private: CMvDatabaseEx m_Database; + UString _errorMessage; + bool _isArc; + bool _errorInHeaders; + bool _unexpectedEnd; + // int _mainVolIndex; + UInt32 _phySize; + UInt64 _offset; }; }} diff --git a/CPP/7zip/Archive/Cab/CabHeader.cpp b/CPP/7zip/Archive/Cab/CabHeader.cpp index 0cba1b0b..0cba1b0b 100755..100644 --- a/CPP/7zip/Archive/Cab/CabHeader.cpp +++ b/CPP/7zip/Archive/Cab/CabHeader.cpp diff --git a/CPP/7zip/Archive/Cab/CabHeader.h b/CPP/7zip/Archive/Cab/CabHeader.h index 0f0d2af3..9ec0760a 100755..100644 --- a/CPP/7zip/Archive/Cab/CabHeader.h +++ b/CPP/7zip/Archive/Cab/CabHeader.h @@ -3,7 +3,7 @@ #ifndef __ARCHIVE_CAB_HEADER_H #define __ARCHIVE_CAB_HEADER_H -#include "Common/Types.h" +#include "../../../Common/MyTypes.h" namespace NArchive { namespace NCab { @@ -12,17 +12,14 @@ namespace NHeader { const unsigned kMarkerSize = 8; extern Byte kMarker[kMarkerSize]; -namespace NArchive +namespace NArcFlags { - namespace NFlags - { - const int kPrevCabinet = 0x0001; - const int kNextCabinet = 0x0002; - const int kReservePresent = 0x0004; - } + const unsigned kPrevCabinet = 1; + const unsigned kNextCabinet = 2; + const unsigned kReservePresent = 4; } -namespace NCompressionMethodMajor +namespace NMethod { const Byte kNone = 0; const Byte kMSZip = 1; @@ -30,13 +27,13 @@ namespace NCompressionMethodMajor const Byte kLZX = 3; } -const int kFileNameIsUTFAttributeMask = 0x80; +const unsigned kFileNameIsUtf8_Mask = 0x80; namespace NFolderIndex { - const int kContinuedFromPrev = 0xFFFD; - const int kContinuedToNext = 0xFFFE; - const int kContinuedPrevAndNext = 0xFFFF; + const unsigned kContinuedFromPrev = 0xFFFD; + const unsigned kContinuedToNext = 0xFFFE; + const unsigned kContinuedPrevAndNext = 0xFFFF; } }}} diff --git a/CPP/7zip/Archive/Cab/CabIn.cpp b/CPP/7zip/Archive/Cab/CabIn.cpp index c0bffa2d..c499f05f 100755..100644 --- a/CPP/7zip/Archive/Cab/CabIn.cpp +++ b/CPP/7zip/Archive/Cab/CabIn.cpp @@ -2,154 +2,353 @@ #include "StdAfx.h" -#include "../Common/FindSignature.h" +// #include <stdio.h> + +#include "../../../../C/CpuArch.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/StreamUtils.h" #include "CabIn.h" +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + namespace NArchive { namespace NCab { -Byte CInArchive::Read8() +struct CUnexpectedEndException {}; + +void CInArchive::Skip(unsigned size) { - Byte b; - if (!inBuffer.ReadByte(b)) - throw CInArchiveException(CInArchiveException::kUnsupported); - return b; + if (_inBuffer.Skip(size) != size) + throw CUnexpectedEndException(); } -UInt16 CInArchive::Read16() +void CInArchive::Read(Byte *data, unsigned size) { - UInt16 value = 0; - for (int i = 0; i < 2; i++) - { - Byte b = Read8(); - value |= (UInt16(b) << (8 * i)); - } - return value; + if (_inBuffer.ReadBytes(data, size) != size) + throw CUnexpectedEndException(); } -UInt32 CInArchive::Read32() +void CInArchive::ReadName(AString &s) { - UInt32 value = 0; - for (int i = 0; i < 4; i++) + for (size_t i = 0; i < ((size_t)1 << 13); i++) { - Byte b = Read8(); - value |= (UInt32(b) << (8 * i)); + Byte b; + if (!_inBuffer.ReadByte(b)) + throw CUnexpectedEndException(); + if (b == 0) + { + memcpy(s.GetBuffer((unsigned)i), _tempBuf, i); + s.ReleaseBuffer((unsigned)i); + return; + } + if (_tempBuf.Size() == i) + _tempBuf.ChangeSize_KeepData(i * 2, i); + _tempBuf[i] = b; } - return value; -} - -AString CInArchive::SafeReadName() -{ - AString name; + for (;;) { - Byte b = Read8(); + Byte b; + if (!_inBuffer.ReadByte(b)) + throw CUnexpectedEndException(); if (b == 0) - return name; - name += (char)b; + break; } + + ErrorInNames = true; + s = "[ERROR-LONG-PATH]"; } -void CInArchive::ReadOtherArchive(COtherArchive &oa) +void CInArchive::ReadOtherArc(COtherArc &oa) { - oa.FileName = SafeReadName(); - oa.DiskName = SafeReadName(); + ReadName(oa.FileName); + ReadName(oa.DiskName); } -void CInArchive::Skip(UInt32 size) +struct CSignatureFinder +{ + Byte *Buf; + UInt32 Pos; + UInt32 End; + const Byte *Signature; + UInt32 SignatureSize; + + UInt32 _HeaderSize; + UInt32 _AlignSize; + UInt32 _BufUseCapacity; + + ISequentialInStream *Stream; + UInt64 Processed; // Global offset of start of Buf + + const UInt64 *SearchLimit; + + UInt32 GetTotalCapacity(UInt32 basicSize, UInt32 headerSize) + { + _HeaderSize = headerSize; + for (_AlignSize = (1 << 5); _AlignSize < _HeaderSize; _AlignSize <<= 1); + _BufUseCapacity = basicSize + _AlignSize; + return _BufUseCapacity + 16; + } + + /* + returns: + S_OK - signature found (at Pos) + S_FALSE - signature not found + */ + HRESULT Find(); +}; + +HRESULT CSignatureFinder::Find() { - while (size-- != 0) - Read8(); + for (;;) + { + Buf[End] = Signature[0]; // it's for fast search; + + while (End - Pos >= _HeaderSize) + { + const Byte *p = Buf + Pos; + Byte b = Signature[0]; + for (;;) + { + if (*p == b) break; p++; + if (*p == b) break; p++; + } + Pos = (UInt32)(p - Buf); + if (End - Pos < _HeaderSize) + { + Pos = End - _HeaderSize + 1; + break; + } + UInt32 i; + for (i = 1; i < SignatureSize && p[i] == Signature[i]; i++); + if (i == SignatureSize) + return S_OK; + Pos++; + } + + if (Pos >= _AlignSize) + { + UInt32 num = (Pos & ~(_AlignSize - 1)); + Processed += num; + Pos -= num; + End -= num; + memmove(Buf, Buf + num, End); + } + UInt32 rem = _BufUseCapacity - End; + if (SearchLimit) + { + if (Processed + Pos > *SearchLimit) + return S_FALSE; + UInt64 rem2 = *SearchLimit - (Processed + End) + _HeaderSize; + if (rem > rem2) + rem = (UInt32)rem2; + } + + UInt32 processedSize; + if (Processed == 0 && rem == _BufUseCapacity - _HeaderSize) + rem -= _AlignSize; // to make reads more aligned. + RINOK(Stream->Read(Buf + End, rem, &processedSize)); + if (processedSize == 0) + return S_FALSE; + End += processedSize; + } } -HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db) +bool CInArcInfo::Parse(const Byte *p) +{ + if (Get32(p + 0x0C) != 0 || + Get32(p + 0x14) != 0) + return false; + Size = Get32(p + 8); + if (Size < 36) + return false; + Flags = Get16(p + 0x1E); + if (Flags > 7) + return false; + FileHeadersOffset = Get32(p + 0x10); + if (FileHeadersOffset != 0 && FileHeadersOffset > Size) + return false; + VersionMinor = p[0x18]; + VersionMajor = p[0x19]; + NumFolders = Get16(p + 0x1A); + NumFiles = Get16(p + 0x1C); + return true; +} + +HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) { - IInStream *stream = db.Stream; + IsArc = false; + ErrorInNames = false; + UnexpectedEnd = false; + HeaderError = false; + db.Clear(); - RINOK(stream->Seek(0, STREAM_SEEK_SET, &db.StartPosition)); - - RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize, - searchHeaderSizeLimit, db.StartPosition)); - - RINOK(stream->Seek(db.StartPosition + NHeader::kMarkerSize, STREAM_SEEK_SET, NULL)); - if (!inBuffer.Create(1 << 17)) - return E_OUTOFMEMORY; - inBuffer.SetStream(stream); - inBuffer.Init(); - - CInArchiveInfo &ai = db.ArchiveInfo; - - ai.Size = Read32(); - if (Read32() != 0) - return S_FALSE; - ai.FileHeadersOffset = Read32(); - if (Read32() != 0) - return S_FALSE; - - ai.VersionMinor = Read8(); - ai.VersionMajor = Read8(); - ai.NumFolders = Read16(); - ai.NumFiles = Read16(); - ai.Flags = Read16(); - if (ai.Flags > 7) - return S_FALSE; - ai.SetID = Read16(); - ai.CabinetNumber = Read16(); + RINOK(db.Stream->Seek(0, STREAM_SEEK_CUR, &db.StartPosition)); + // UInt64 temp = db.StartPosition; - if (ai.ReserveBlockPresent()) + CByteBuffer buffer; + CInArcInfo &ai = db.ArcInfo; + UInt64 startInBuf = 0; + + CLimitedSequentialInStream *limitedStreamSpec = NULL; + CMyComPtr<ISequentialInStream> limitedStream; + + // for (int iii = 0; iii < 10000; iii++) { - ai.PerCabinetAreaSize = Read16(); - ai.PerFolderAreaSize = Read8(); - ai.PerDataBlockAreaSize = Read8(); + // db.StartPosition = temp; RINOK(db.Stream->Seek(db.StartPosition, STREAM_SEEK_SET, NULL)); + + const UInt32 kMainHeaderSize = 32; + Byte header[kMainHeaderSize]; + const UInt32 kBufSize = 1 << 15; + RINOK(ReadStream_FALSE(db.Stream, header, kMainHeaderSize)); + if (memcmp(header, NHeader::kMarker, NHeader::kMarkerSize) == 0 && ai.Parse(header)) + { + limitedStreamSpec = new CLimitedSequentialInStream; + limitedStream = limitedStreamSpec; + limitedStreamSpec->SetStream(db.Stream); + limitedStreamSpec->Init(ai.Size - NHeader::kMarkerSize); + buffer.Alloc(kBufSize); + memcpy(buffer, header, kMainHeaderSize); + UInt32 numProcessedBytes; + RINOK(limitedStream->Read(buffer + kMainHeaderSize, kBufSize - kMainHeaderSize, &numProcessedBytes)); + _inBuffer.SetBuf(buffer, (UInt32)kBufSize, kMainHeaderSize + numProcessedBytes, kMainHeaderSize); + } + else + { + if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) + return S_FALSE; + + CSignatureFinder finder; + + finder.Stream = db.Stream; + finder.Signature = NHeader::kMarker; + finder.SignatureSize = NHeader::kMarkerSize; + finder.SearchLimit = searchHeaderSizeLimit; - Skip(ai.PerCabinetAreaSize); + buffer.Alloc(finder.GetTotalCapacity(kBufSize, kMainHeaderSize)); + finder.Buf = buffer; + + memcpy(buffer, header, kMainHeaderSize); + finder.Processed = db.StartPosition; + finder.End = kMainHeaderSize; + finder.Pos = 1; + + for (;;) + { + RINOK(finder.Find()); + if (ai.Parse(finder.Buf + finder.Pos)) + { + db.StartPosition = finder.Processed + finder.Pos; + limitedStreamSpec = new CLimitedSequentialInStream; + limitedStreamSpec->SetStream(db.Stream); + limitedStream = limitedStreamSpec; + UInt32 remInFinder = finder.End - finder.Pos; + if (ai.Size <= remInFinder) + { + limitedStreamSpec->Init(0); + finder.End = finder.Pos + ai.Size; + } + else + limitedStreamSpec->Init(ai.Size - remInFinder); + + startInBuf = finder.Pos; + _inBuffer.SetBuf(buffer, (UInt32)kBufSize, finder.End, finder.Pos + kMainHeaderSize); + break; + } + finder.Pos++; + } + } } + + IsArc = true; + _inBuffer.SetStream(limitedStream); + if (_tempBuf.Size() == 0) + _tempBuf.Alloc(1 << 12); + + Byte p[16]; + unsigned nextSize = 4 + (ai.ReserveBlockPresent() ? 4 : 0); + Read(p, nextSize); + ai.SetID = Get16(p); + ai.CabinetNumber = Get16(p + 2); + + if (ai.ReserveBlockPresent()) { - if (ai.IsTherePrev()) - ReadOtherArchive(ai.PrevArc); - if (ai.IsThereNext()) - ReadOtherArchive(ai.NextArc); + ai.PerCabinet_AreaSize = Get16(p + 4); + ai.PerFolder_AreaSize = p[6]; + ai.PerDataBlock_AreaSize = p[7]; + Skip(ai.PerCabinet_AreaSize); } + + if (ai.IsTherePrev()) ReadOtherArc(ai.PrevArc); + if (ai.IsThereNext()) ReadOtherArc(ai.NextArc); - int i; + UInt32 i; + db.Folders.ClearAndReserve(ai.NumFolders); for (i = 0; i < ai.NumFolders; i++) { + Read(p, 8); CFolder folder; - - folder.DataStart = Read32(); - folder.NumDataBlocks = Read16(); - folder.CompressionTypeMajor = Read8(); - folder.CompressionTypeMinor = Read8(); - - Skip(ai.PerFolderAreaSize); - db.Folders.Add(folder); + folder.DataStart = Get32(p); + folder.NumDataBlocks = Get16(p + 4); + folder.MethodMajor = p[6]; + folder.MethodMinor = p[7]; + Skip(ai.PerFolder_AreaSize); + db.Folders.AddInReserved(folder); } - RINOK(stream->Seek(db.StartPosition + ai.FileHeadersOffset, STREAM_SEEK_SET, NULL)); + // for (int iii = 0; iii < 10000; iii++) { + + if (_inBuffer.GetProcessedSize() - startInBuf != ai.FileHeadersOffset) + { + // printf("\n!!! Seek Error !!!!\n"); + // fflush(stdout); + RINOK(db.Stream->Seek(db.StartPosition + ai.FileHeadersOffset, STREAM_SEEK_SET, NULL)); + limitedStreamSpec->Init(ai.Size - ai.FileHeadersOffset); + _inBuffer.Init(); + } - inBuffer.SetStream(stream); - inBuffer.Init(); + db.Items.ClearAndReserve(ai.NumFiles); for (i = 0; i < ai.NumFiles; i++) { - CItem item; - item.Size = Read32(); - item.Offset = Read32(); - item.FolderIndex = Read16(); - UInt16 pureDate = Read16(); - UInt16 pureTime = Read16(); - item.Time = ((UInt32(pureDate) << 16)) | pureTime; - item.Attributes = Read16(); - item.Name = SafeReadName(); - int folderIndex = item.GetFolderIndex(db.Folders.Size()); - if (folderIndex >= db.Folders.Size()) + Read(p, 16); + CItem &item = db.Items.AddNewInReserved(); + item.Size = Get32(p); + item.Offset = Get32(p + 4); + item.FolderIndex = Get16(p + 8); + UInt16 pureDate = Get16(p + 10); + UInt16 pureTime = Get16(p + 12); + item.Time = (((UInt32)pureDate << 16)) | pureTime; + item.Attributes = Get16(p + 14); + + ReadName(item.Name); + if (item.GetFolderIndex(db.Folders.Size()) >= (int)db.Folders.Size()) + { + HeaderError = true; return S_FALSE; - db.Items.Add(item); + } } + + // } + return S_OK; } +HRESULT CInArchive::Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) +{ + try + { + return Open2(db, searchHeaderSizeLimit); + } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; } +} + + + #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param) @@ -161,10 +360,8 @@ static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param) const CItem &item2 = db2.Items[p2->ItemIndex];; bool isDir1 = item1.IsDir(); bool isDir2 = item2.IsDir(); - if (isDir1 && !isDir2) - return -1; - if (isDir2 && !isDir1) - return 1; + if (isDir1 && !isDir2) return -1; + if (isDir2 && !isDir1) return 1; int f1 = mvDb.GetFolderIndex(p1); int f2 = mvDb.GetFolderIndex(p2); RINOZ(MyCompare(f1, f2)); @@ -174,7 +371,7 @@ static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param) return MyCompare(p1->ItemIndex, p2->ItemIndex); } -bool CMvDatabaseEx::AreItemsEqual(int i1, int i2) +bool CMvDatabaseEx::AreItemsEqual(unsigned i1, unsigned i2) { const CMvItem *p1 = &Items[i1]; const CMvItem *p2 = &Items[i2]; @@ -182,10 +379,10 @@ bool CMvDatabaseEx::AreItemsEqual(int i1, int i2) const CDatabaseEx &db2 = Volumes[p2->VolumeIndex]; const CItem &item1 = db1.Items[p1->ItemIndex]; const CItem &item2 = db2.Items[p2->ItemIndex];; - return GetFolderIndex(p1) == GetFolderIndex(p2) && - item1.Offset == item2.Offset && - item1.Size == item2.Size && - item1.Name == item2.Name; + return GetFolderIndex(p1) == GetFolderIndex(p2) + && item1.Offset == item2.Offset + && item1.Size == item2.Size + && item1.Name == item2.Name; } void CMvDatabaseEx::FillSortAndShrink() @@ -194,7 +391,7 @@ void CMvDatabaseEx::FillSortAndShrink() StartFolderOfVol.Clear(); FolderStartFileIndex.Clear(); int offset = 0; - for (int v = 0; v < Volumes.Size(); v++) + FOR_VECTOR (v, Volumes) { const CDatabaseEx &db = Volumes[v]; int curOffset = offset; @@ -205,32 +402,35 @@ void CMvDatabaseEx::FillSortAndShrink() CMvItem mvItem; mvItem.VolumeIndex = v; - for (int i = 0 ; i < db.Items.Size(); i++) + FOR_VECTOR (i, db.Items) { mvItem.ItemIndex = i; Items.Add(mvItem); } } - Items.Sort(CompareMvItems, (void *)this); - int j = 1; - int i; - for (i = 1; i < Items.Size(); i++) - if (!AreItemsEqual(i, i -1)) - Items[j++] = Items[i]; - Items.DeleteFrom(j); + if (Items.Size() > 1) + { + Items.Sort(CompareMvItems, (void *)this); + unsigned j = 1; + unsigned i = 1; + for (; i < Items.Size(); i++) + if (!AreItemsEqual(i, i - 1)) + Items[j++] = Items[i]; + Items.DeleteFrom(j); + } - for (i = 0; i < Items.Size(); i++) + FOR_VECTOR (i, Items) { int folderIndex = GetFolderIndex(&Items[i]); - if (folderIndex >= FolderStartFileIndex.Size()) + if (folderIndex >= (int)FolderStartFileIndex.Size()) FolderStartFileIndex.Add(i); } } bool CMvDatabaseEx::Check() { - for (int v = 1; v < Volumes.Size(); v++) + for (unsigned v = 1; v < Volumes.Size(); v++) { const CDatabaseEx &db1 = Volumes[v]; if (db1.IsTherePrevFolder()) @@ -240,19 +440,19 @@ bool CMvDatabaseEx::Check() return false; const CFolder &f0 = db0.Folders.Back(); const CFolder &f1 = db1.Folders.Front(); - if (f0.CompressionTypeMajor != f1.CompressionTypeMajor || - f0.CompressionTypeMinor != f1.CompressionTypeMinor) + if (f0.MethodMajor != f1.MethodMajor || + f0.MethodMinor != f1.MethodMinor) return false; } } UInt32 beginPos = 0; UInt64 endPos = 0; int prevFolder = -2; - for (int i = 0; i < Items.Size(); i++) + FOR_VECTOR (i, Items) { const CMvItem &mvItem = Items[i]; int fIndex = GetFolderIndex(&mvItem); - if (fIndex >= FolderStartFileIndex.Size()) + if (fIndex >= (int)FolderStartFileIndex.Size()) return false; const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; if (item.IsDir()) diff --git a/CPP/7zip/Archive/Cab/CabIn.h b/CPP/7zip/Archive/Cab/CabIn.h index 1e9b188b..4fdab77b 100755..100644 --- a/CPP/7zip/Archive/Cab/CabIn.h +++ b/CPP/7zip/Archive/Cab/CabIn.h @@ -3,96 +3,88 @@ #ifndef __ARCHIVE_CAB_IN_H #define __ARCHIVE_CAB_IN_H -#include "../../IStream.h" +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyCom.h" + #include "../../Common/InBuffer.h" -#include "CabHeader.h" + #include "CabItem.h" namespace NArchive { namespace NCab { -class CInArchiveException -{ -public: - enum CCauseType - { - kUnexpectedEndOfArchive = 0, - kIncorrectArchive, - kUnsupported - } Cause; - CInArchiveException(CCauseType cause) : Cause(cause) {} -}; - -struct COtherArchive +struct COtherArc { AString FileName; AString DiskName; }; -struct CArchiveInfo +struct CArchInfo { - Byte VersionMinor; /* cabinet file format version, minor */ - Byte VersionMajor; /* cabinet file format version, major */ - UInt16 NumFolders; /* number of CFFOLDER entries in this cabinet */ - UInt16 NumFiles; /* number of CFFILE entries in this cabinet */ - UInt16 Flags; /* cabinet file option indicators */ - UInt16 SetID; /* must be the same for all cabinets in a set */ - UInt16 CabinetNumber; /* number of this cabinet file in a set */ - - bool ReserveBlockPresent() const { return (Flags & NHeader::NArchive::NFlags::kReservePresent) != 0; } - - bool IsTherePrev() const { return (Flags & NHeader::NArchive::NFlags::kPrevCabinet) != 0; } - bool IsThereNext() const { return (Flags & NHeader::NArchive::NFlags::kNextCabinet) != 0; } - - UInt16 PerCabinetAreaSize; // (optional) size of per-cabinet reserved area - Byte PerFolderAreaSize; // (optional) size of per-folder reserved area - Byte PerDataBlockAreaSize; // (optional) size of per-datablock reserved area - - Byte GetDataBlockReserveSize() const { return (Byte)(ReserveBlockPresent() ? PerDataBlockAreaSize : 0); } - - COtherArchive PrevArc; - COtherArchive NextArc; - - CArchiveInfo() + Byte VersionMinor; // cabinet file format version, minor + Byte VersionMajor; // cabinet file format version, major + UInt32 NumFolders; // number of CFFOLDER entries in this cabinet + UInt32 NumFiles; // number of CFFILE entries in this cabinet + UInt32 Flags; // cabinet file option indicators + UInt32 SetID; // must be the same for all cabinets in a set + UInt32 CabinetNumber; // number of this cabinet file in a set + + UInt16 PerCabinet_AreaSize; // (optional) size of per-cabinet reserved area + Byte PerFolder_AreaSize; // (optional) size of per-folder reserved area + Byte PerDataBlock_AreaSize; // (optional) size of per-datablock reserved area + + COtherArc PrevArc; // prev link can skip some volumes !!! + COtherArc NextArc; + + bool ReserveBlockPresent() const { return (Flags & NHeader::NArcFlags::kReservePresent) != 0; } + bool IsTherePrev() const { return (Flags & NHeader::NArcFlags::kPrevCabinet) != 0; } + bool IsThereNext() const { return (Flags & NHeader::NArcFlags::kNextCabinet) != 0; } + Byte GetDataBlockReserveSize() const { return (Byte)(ReserveBlockPresent() ? PerDataBlock_AreaSize : 0); } + + CArchInfo() { Clear(); } void Clear() { - PerCabinetAreaSize = 0; - PerFolderAreaSize = 0; - PerDataBlockAreaSize = 0; + PerCabinet_AreaSize = 0; + PerFolder_AreaSize = 0; + PerDataBlock_AreaSize = 0; } }; -struct CInArchiveInfo: public CArchiveInfo +struct CInArcInfo: public CArchInfo { - UInt32 Size; /* size of this cabinet file in bytes */ + UInt32 Size; // size of this cabinet file in bytes UInt32 FileHeadersOffset; // offset of the first CFFILE entry + + bool Parse(const Byte *p); }; struct CDatabase { - UInt64 StartPosition; - CInArchiveInfo ArchiveInfo; - CObjectVector<CFolder> Folders; + CRecordVector<CFolder> Folders; CObjectVector<CItem> Items; + UInt64 StartPosition; + CInArcInfo ArcInfo; void Clear() { - ArchiveInfo.Clear(); + ArcInfo.Clear(); Folders.Clear(); Items.Clear(); } + bool IsTherePrevFolder() const { - for (int i = 0; i < Items.Size(); i++) + FOR_VECTOR (i, Items) if (Items[i].ContinuedFromPrev()) return true; return false; } + int GetNumberOfNewFolders() const { int res = Folders.Size(); @@ -100,8 +92,6 @@ struct CDatabase res--; return res; } - UInt32 GetFileOffset(int index) const { return Items[index].Offset; } - UInt32 GetFileSize(int index) const { return Items[index].Size; } }; struct CDatabaseEx: public CDatabase @@ -111,25 +101,27 @@ struct CDatabaseEx: public CDatabase struct CMvItem { - int VolumeIndex; - int ItemIndex; + unsigned VolumeIndex; + unsigned ItemIndex; }; class CMvDatabaseEx { - bool AreItemsEqual(int i1, int i2); + bool AreItemsEqual(unsigned i1, unsigned i2); + public: CObjectVector<CDatabaseEx> Volumes; CRecordVector<CMvItem> Items; - CRecordVector<int> StartFolderOfVol; - CRecordVector<int> FolderStartFileIndex; - + CRecordVector<int> StartFolderOfVol; // can be negative + CRecordVector<unsigned> FolderStartFileIndex; + int GetFolderIndex(const CMvItem *mvi) const { const CDatabaseEx &db = Volumes[mvi->VolumeIndex]; return StartFolderOfVol[mvi->VolumeIndex] + db.Items[mvi->ItemIndex].GetFolderIndex(db.Folders.Size()); } + void Clear() { Volumes.Clear(); @@ -137,23 +129,30 @@ public: StartFolderOfVol.Clear(); FolderStartFileIndex.Clear(); } + void FillSortAndShrink(); bool Check(); }; + class CInArchive { - CInBuffer inBuffer; + CInBufferBase _inBuffer; + CByteBuffer _tempBuf; - Byte Read8(); - UInt16 Read16(); - UInt32 Read32(); - AString SafeReadName(); - void Skip(UInt32 size); - void ReadOtherArchive(COtherArchive &oa); + void Skip(unsigned size); + void Read(Byte *data, unsigned size); + void ReadName(AString &s); + void ReadOtherArc(COtherArc &oa); + HRESULT Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit); public: - HRESULT Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db); + bool IsArc; + bool ErrorInNames; + bool UnexpectedEnd; + bool HeaderError; + + HRESULT Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit); }; }} diff --git a/CPP/7zip/Archive/Cab/CabItem.h b/CPP/7zip/Archive/Cab/CabItem.h index 63a1e856..eda62bda 100755..100644 --- a/CPP/7zip/Archive/Cab/CabItem.h +++ b/CPP/7zip/Archive/Cab/CabItem.h @@ -3,20 +3,23 @@ #ifndef __ARCHIVE_CAB_ITEM_H #define __ARCHIVE_CAB_ITEM_H -#include "Common/Types.h" -#include "Common/MyString.h" +#include "../../../Common/MyString.h" + #include "CabHeader.h" namespace NArchive { namespace NCab { +const unsigned kNumMethodsMax = 16; + struct CFolder { UInt32 DataStart; // offset of the first CFDATA block in this folder UInt16 NumDataBlocks; // number of CFDATA blocks in this folder - Byte CompressionTypeMajor; - Byte CompressionTypeMinor; - Byte GetCompressionMethod() const { return (Byte)(CompressionTypeMajor & 0xF); } + Byte MethodMajor; + Byte MethodMinor; + + Byte GetMethod() const { return (Byte)(MethodMajor & 0xF); } }; struct CItem @@ -25,27 +28,27 @@ struct CItem UInt32 Offset; UInt32 Size; UInt32 Time; - UInt16 FolderIndex; + UInt32 FolderIndex; UInt16 Flags; UInt16 Attributes; UInt64 GetEndOffset() const { return (UInt64)Offset + Size; } - UInt32 GetWinAttributes() const { return (Attributes & ~NHeader::kFileNameIsUTFAttributeMask); } - bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUTFAttributeMask) != 0; } + UInt32 GetWinAttrib() const { return (UInt32)Attributes & ~(UInt32)NHeader::kFileNameIsUtf8_Mask; } + bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUtf8_Mask) != 0; } bool IsDir() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } bool ContinuedFromPrev() const { return - (FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev) || - (FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext); + FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev || + FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext; } bool ContinuedToNext() const { return - (FolderIndex == NHeader::NFolderIndex::kContinuedToNext) || - (FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext); + FolderIndex == NHeader::NFolderIndex::kContinuedToNext || + FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext; } int GetFolderIndex(int numFolders) const @@ -53,7 +56,7 @@ struct CItem if (ContinuedFromPrev()) return 0; if (ContinuedToNext()) - return (numFolders - 1); + return numFolders - 1; return FolderIndex; } }; diff --git a/CPP/7zip/Archive/Cab/CabRegister.cpp b/CPP/7zip/Archive/Cab/CabRegister.cpp index 15fe4099..acad4c4a 100755..100644 --- a/CPP/7zip/Archive/Cab/CabRegister.cpp +++ b/CPP/7zip/Archive/Cab/CabRegister.cpp @@ -5,9 +5,19 @@ #include "../../Common/RegisterArc.h" #include "CabHandler.h" -static IInArchive *CreateArc() { return new NArchive::NCab::CHandler; } + +namespace NArchive { +namespace NCab { + +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"Cab", L"cab", 0, 8, { 0x4D, 0x53, 0x43, 0x46 }, 4, false, CreateArc, 0 }; + { "Cab", "cab", 0, 8, + 8, { 'M', 'S', 'C', 'F', 0, 0, 0, 0 }, + 0, + NArcInfoFlags::kFindSignature, + CreateArc }; REGISTER_ARC(Cab) + +}} diff --git a/CPP/7zip/Archive/Cab/StdAfx.h b/CPP/7zip/Archive/Cab/StdAfx.h index e7fb6986..2854ff3e 100755..100644 --- a/CPP/7zip/Archive/Cab/StdAfx.h +++ b/CPP/7zip/Archive/Cab/StdAfx.h @@ -3,6 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" +#include "../../../Common/Common.h" #endif diff --git a/CPP/7zip/Archive/Chm/ChmHandler.cpp b/CPP/7zip/Archive/Chm/ChmHandler.cpp index a9e334b0..c67ded28 100755..100644 --- a/CPP/7zip/Archive/Chm/ChmHandler.cpp +++ b/CPP/7zip/Archive/Chm/ChmHandler.cpp @@ -2,17 +2,17 @@ #include "StdAfx.h" -#include "Common/ComTry.h" -#include "Common/Defs.h" -#include "Common/StringConvert.h" -#include "Common/UTFConvert.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" #include "../../Common/LimitedStreams.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamUtils.h" +#include "../../Common/RegisterArc.h" #include "../../Compress/CopyCoder.h" #include "../../Compress/LzxDecoder.h" @@ -38,44 +38,45 @@ enum #endif -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidBlock, VT_UI4} + kpidPath, + kpidSize, + kpidMethod, + kpidBlock #ifdef _CHM_DETAILS , - { L"Section", kpidSection, VT_UI4}, - { NULL, kpidOffset, VT_UI4} + L"Section", kpidSection, + kpidOffset #endif }; -STATPROPSTG kArcProps[] = +/* +static const Byte kArcProps[] = { - { NULL, kpidNumBlocks, VT_UI8} + // kpidNumBlocks, }; +*/ IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO -/* -IMP_IInArchive_ArcProps +IMP_IInArchive_ArcProps_NO_Table STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) + // COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) { + /* case kpidNumBlocks: { UInt64 numBlocks = 0; - for (int i = 0; i < m_Database.Sections.Size(); i++) + FOR_VECTOR(i, m_Database.Sections) { const CSectionInfo &s = m_Database.Sections[i]; - for (int j = 0; j < s.Methods.Size(); j++) + FOR_VECTOR(j, s.Methods) { const CMethodInfo &m = s.Methods[j]; if (m.IsLzx()) @@ -85,23 +86,27 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) prop = numBlocks; break; } + */ + case kpidOffset: prop = m_Database.StartPosition; break; + case kpidPhySize: prop = m_Database.PhySize; break; + + case kpidErrorFlags: prop = m_ErrorFlags; break; } prop.Detach(value); return S_OK; - COM_TRY_END + // COM_TRY_END } -*/ -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; if (m_Database.NewFormat) { switch(propID) { case kpidSize: - prop = (UInt64)m_Database.NewFormatString.Length(); + prop = (UInt64)m_Database.NewFormatString.Len(); break; } prop.Detach(value); @@ -113,7 +118,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va else entryIndex = m_Database.Indices[index]; const CItem &item = m_Database.Items[entryIndex]; - switch(propID) + switch (propID) { case kpidPath: { @@ -122,7 +127,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va { if (!m_Database.LowLevel) { - if (us.Length() > 1) + if (us.Len() > 1) if (us[0] == L'/') us.Delete(0); } @@ -160,6 +165,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va COM_TRY_END } +/* class CProgressImp: public CProgressVirt { CMyComPtr<IArchiveOpenCallback> _callback; @@ -182,18 +188,25 @@ STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles) return _callback->SetCompleted(numFiles, NULL); return S_OK; } +*/ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback * /* openArchiveCallback */) { COM_TRY_BEGIN - m_Stream.Release(); + Close(); try { - CInArchive archive; + CInArchive archive(_help2); // CProgressImp progressImp(openArchiveCallback); - RINOK(archive.Open(inStream, maxCheckStartPosition, m_Database)); + HRESULT res = archive.Open(inStream, maxCheckStartPosition, m_Database); + if (!archive.IsArc) m_ErrorFlags |= kpv_ErrorFlags_IsNotArc; + if (archive.HeadersError) m_ErrorFlags |= kpv_ErrorFlags_HeadersError; + if (archive.UnexpectedEnd) m_ErrorFlags |= kpv_ErrorFlags_UnexpectedEnd; + if (archive.UnsupportedFeature) m_ErrorFlags |= kpv_ErrorFlags_UnsupportedFeature; + + RINOK(res); /* if (m_Database.LowLevel) return S_FALSE; @@ -210,6 +223,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, STDMETHODIMP CHandler::Close() { + m_ErrorFlags = 0; m_Database.Clear(); m_Stream.Release(); return S_OK; @@ -402,7 +416,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testModeSpec, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = m_Database.NewFormat ? 1: @@ -432,7 +446,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt64 currentItemSize = 0; UInt64 totalSize = 0; if (m_Database.NewFormat) - totalSize = m_Database.NewFormatString.Length(); + totalSize = m_Database.NewFormatString.Len(); else for (i = 0; i < numItems; i++) totalSize += m_Database.Items[allFilesMode ? i : indices[i]].Size; @@ -460,7 +474,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; if (!testMode) { - UInt32 size = m_Database.NewFormatString.Length(); + UInt32 size = m_Database.NewFormatString.Len(); RINOK(WriteStream(realOutStream, (const char *)m_Database.NewFormatString, size)); } RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); @@ -475,7 +489,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->PrepareOperation(askMode)); if (item.Section != 0) { - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); continue; } @@ -589,7 +603,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); continue; } @@ -718,4 +732,32 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } +namespace NChm { + +IMP_CreateArcIn_2(CHandler(false)) + +static CArcInfo g_ArcInfo = + { "Chm", "chm chi chq chw", 0, 0xE9, + 12, { 'I', 'T', 'S', 'F', 3, 0, 0, 0, 0x60, 0, 0, 0 }, + 0, + 0, + CreateArc }; + +REGISTER_ARC(Chm) +} + +namespace NHxs { + +IMP_CreateArcIn_2(CHandler(true)) + +static CArcInfo g_ArcInfo = + { "Hxs", "hxs hxi hxr hxq hxw lit", 0, 0xCE, + 16, { 'I', 'T', 'O', 'L', 'I', 'T', 'L', 'S', 1, 0, 0, 0, 0x28, 0, 0, 0 }, + 0, + NArcInfoFlags::kFindSignature, + CreateArc }; + +REGISTER_ARC(Hxs) +} + }} diff --git a/CPP/7zip/Archive/Chm/ChmHandler.h b/CPP/7zip/Archive/Chm/ChmHandler.h index 440c50f1..884f391b 100755..100644 --- a/CPP/7zip/Archive/Chm/ChmHandler.h +++ b/CPP/7zip/Archive/Chm/ChmHandler.h @@ -3,8 +3,10 @@ #ifndef __ARCHIVE_CHM_HANDLER_H #define __ARCHIVE_CHM_HANDLER_H -#include "Common/MyCom.h" +#include "../../../Common/MyCom.h" + #include "../IArchive.h" + #include "ChmIn.h" namespace NArchive { @@ -19,9 +21,13 @@ public: INTERFACE_IInArchive(;) + bool _help2; + CHandler(bool help2): _help2(help2) {} + private: CFilesDatabase m_Database; CMyComPtr<IInStream> m_Stream; + UInt32 m_ErrorFlags; }; }} diff --git a/CPP/7zip/Archive/Chm/ChmHeader.cpp b/CPP/7zip/Archive/Chm/ChmHeader.cpp deleted file mode 100755 index e8dc9f3e..00000000 --- a/CPP/7zip/Archive/Chm/ChmHeader.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Archive/Chm/Header.h - -#include "StdAfx.h" - -#include "ChmHeader.h" - -namespace NArchive{ -namespace NChm{ -namespace NHeader{ - -UInt32 kItsfSignature = 0x46535449 + 1; -UInt32 kItolSignature = 0x4C4F5449 + 1; -static class CSignatureInitializer -{ -public: - CSignatureInitializer() - { - kItsfSignature--; - kItolSignature--; - } -}g_SignatureInitializer; - - -}}} diff --git a/CPP/7zip/Archive/Chm/ChmHeader.h b/CPP/7zip/Archive/Chm/ChmHeader.h deleted file mode 100755 index 9f1bd42b..00000000 --- a/CPP/7zip/Archive/Chm/ChmHeader.h +++ /dev/null @@ -1,28 +0,0 @@ -// Archive/Chm/Header.h - -#ifndef __ARCHIVE_CHM_HEADER_H -#define __ARCHIVE_CHM_HEADER_H - -#include "Common/Types.h" - -namespace NArchive { -namespace NChm { -namespace NHeader{ - -const UInt32 kItspSignature = 0x50535449; -const UInt32 kPmglSignature = 0x4C474D50; -const UInt32 kLzxcSignature = 0x43585A4C; - -const UInt32 kIfcmSignature = 0x4D434649; -const UInt32 kAollSignature = 0x4C4C4F41; -const UInt32 kCaolSignature = 0x4C4F4143; - -extern UInt32 kItsfSignature; - -extern UInt32 kItolSignature; -const UInt32 kItlsSignature = 0x534C5449; -UInt64 inline GetHxsSignature() { return ((UInt64)kItlsSignature << 32) | kItolSignature; } - -}}} - -#endif diff --git a/CPP/7zip/Archive/Chm/ChmIn.cpp b/CPP/7zip/Archive/Chm/ChmIn.cpp index d52b9ba6..9b0bb199 100755..100644 --- a/CPP/7zip/Archive/Chm/ChmIn.cpp +++ b/CPP/7zip/Archive/Chm/ChmIn.cpp @@ -2,8 +2,10 @@ #include "StdAfx.h" -#include "Common/IntToString.h" -#include "Common/UTFConvert.h" +// #include <stdio.h> + +#include "../../../Common/IntToString.h" +#include "../../../Common/UTFConvert.h" #include "../../Common/LimitedStreams.h" @@ -12,6 +14,21 @@ namespace NArchive { namespace NChm { +static const UInt32 kSignature_ITSP = 0x50535449; +static const UInt32 kSignature_PMGL = 0x4C474D50; +static const UInt32 kSignature_LZXC = 0x43585A4C; + +static const UInt32 kSignature_IFCM = 0x4D434649; +static const UInt32 kSignature_AOLL = 0x4C4C4F41; +static const UInt32 kSignature_CAOL = 0x4C4F4143; + +static const UInt32 kSignature_ITSF = 0x46535449; +static const UInt32 kSignature_ITOL = 0x4C4F5449; +static const UInt32 kSignature_ITLS = 0x534C5449; + +struct CEnexpectedEndException {}; +struct CHeaderErrorException {}; + // define CHM_LOW, if you want to see low level items // #define CHM_LOW @@ -31,9 +48,9 @@ static bool AreGuidsEqual(REFGUID g1, REFGUID g2) return true; } -static char GetHex(Byte value) +static char GetHex(unsigned v) { - return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); + return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10))); } static void PrintByte(Byte b, AString &s) @@ -103,10 +120,10 @@ UString CMethodInfo::GetName() const else { s2 = GetGuidString(); - if (ControlData.GetCapacity() > 0) + if (ControlData.Size() > 0) { s2 += ':'; - for (size_t i = 0; i < ControlData.GetCapacity(); i++) + for (size_t i = 0; i < ControlData.Size(); i++) PrintByte(ControlData[i], s2); } } @@ -132,7 +149,7 @@ UString CSectionInfo::GetMethodName() const s += temp; s += L": "; } - for (int i = 0; i < Methods.Size(); i++) + FOR_VECTOR (i, Methods) { if (i != 0) s += L' '; @@ -145,7 +162,7 @@ Byte CInArchive::ReadByte() { Byte b; if (!_inBuffer.ReadByte(b)) - throw 1; + throw CEnexpectedEndException(); return b; } @@ -163,32 +180,32 @@ void CInArchive::ReadBytes(Byte *data, UInt32 size) UInt16 CInArchive::ReadUInt16() { - UInt16 value = 0; + UInt16 val = 0; for (int i = 0; i < 2; i++) - value |= ((UInt16)(ReadByte()) << (8 * i)); - return value; + val |= ((UInt16)(ReadByte()) << (8 * i)); + return val; } UInt32 CInArchive::ReadUInt32() { - UInt32 value = 0; + UInt32 val = 0; for (int i = 0; i < 4; i++) - value |= ((UInt32)(ReadByte()) << (8 * i)); - return value; + val |= ((UInt32)(ReadByte()) << (8 * i)); + return val; } UInt64 CInArchive::ReadUInt64() { - UInt64 value = 0; + UInt64 val = 0; for (int i = 0; i < 8; i++) - value |= ((UInt64)(ReadByte()) << (8 * i)); - return value; + val |= ((UInt64)(ReadByte()) << (8 * i)); + return val; } UInt64 CInArchive::ReadEncInt() { - UInt64 val = 0;; - for (int i = 0; i < 10; i++) + UInt64 val = 0; + for (int i = 0; i < 9; i++) { Byte b = ReadByte(); val |= (b & 0x7F); @@ -196,7 +213,7 @@ UInt64 CInArchive::ReadEncInt() return val; val <<= 7; } - throw 1; + throw CHeaderErrorException(); } void CInArchive::ReadGUID(GUID &g) @@ -207,10 +224,10 @@ void CInArchive::ReadGUID(GUID &g) ReadBytes(g.Data4, 8); } -void CInArchive::ReadString(int size, AString &s) +void CInArchive::ReadString(unsigned size, AString &s) { s.Empty(); - while(size-- != 0) + while (size-- != 0) { char c = (char)ReadByte(); if (c == 0) @@ -222,10 +239,10 @@ void CInArchive::ReadString(int size, AString &s) } } -void CInArchive::ReadUString(int size, UString &s) +void CInArchive::ReadUString(unsigned size, UString &s) { s.Empty(); - while(size-- != 0) + while (size-- != 0) { wchar_t c = ReadUInt16(); if (c == 0) @@ -244,6 +261,7 @@ HRESULT CInArchive::ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size) CMyComPtr<ISequentialInStream> limitedStream(streamSpec); streamSpec->SetStream(inStream); streamSpec->Init(size); + m_InStreamRef = limitedStream; _inBuffer.SetStream(limitedStream); _inBuffer.Init(); return S_OK; @@ -252,10 +270,10 @@ HRESULT CInArchive::ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size) HRESULT CInArchive::ReadDirEntry(CDatabase &database) { CItem item; - UInt64 nameLength = ReadEncInt(); - if (nameLength == 0 || nameLength >= 0x10000000) + UInt64 nameLen = ReadEncInt(); + if (nameLen == 0 || nameLen > (1 << 13)) return S_FALSE; - ReadString((int)nameLength, item.Name); + ReadString((unsigned)nameLen, item.Name); item.Section = ReadEncInt(); item.Offset = ReadEncInt(); item.Size = ReadEncInt(); @@ -268,9 +286,14 @@ HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database) UInt32 headerSize = ReadUInt32(); if (headerSize != 0x60) return S_FALSE; + database.PhySize = headerSize; + UInt32 unknown1 = ReadUInt32(); if (unknown1 != 0 && unknown1 != 1) // it's 0 in one .sll file return S_FALSE; + + IsArc = true; + /* UInt32 timeStamp = */ ReadUInt32(); // Considered as a big-endian DWORD, it appears to contain seconds (MSB) and // fractional seconds (second byte). @@ -280,37 +303,39 @@ HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database) GUID g; ReadGUID(g); // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC} ReadGUID(g); // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC} - const int kNumSections = 2; + const unsigned kNumSections = 2; UInt64 sectionOffsets[kNumSections]; UInt64 sectionSizes[kNumSections]; - int i; + unsigned i; for (i = 0; i < kNumSections; i++) { sectionOffsets[i] = ReadUInt64(); sectionSizes[i] = ReadUInt64(); + UInt64 end = sectionOffsets[i] + sectionSizes[i]; + database.UpdatePhySize(end); } // if (chmVersion == 3) database.ContentOffset = ReadUInt64(); /* else - database.ContentOffset = _startPosition + 0x58 + database.ContentOffset = database.StartPosition + 0x58 */ - /* // Section 0 ReadChunk(inStream, sectionOffsets[0], sectionSizes[0]); - if (sectionSizes[0] != 0x18) + if (sectionSizes[0] < 0x18) + return S_FALSE; + if (ReadUInt32() != 0x01FE) return S_FALSE; - ReadUInt32(); // unknown: 01FE ReadUInt32(); // unknown: 0 UInt64 fileSize = ReadUInt64(); + database.UpdatePhySize(fileSize); ReadUInt32(); // unknown: 0 ReadUInt32(); // unknown: 0 - */ // Section 1: The Directory Listing ReadChunk(inStream, sectionOffsets[1], sectionSizes[1]); - if (ReadUInt32() != NHeader::kItspSignature) + if (ReadUInt32() != kSignature_ITSP) return S_FALSE; if (ReadUInt32() != 1) // version return S_FALSE; @@ -340,13 +365,13 @@ HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database) for (UInt32 ci = 0; ci < numDirChunks; ci++) { UInt64 chunkPos = _inBuffer.GetProcessedSize(); - if (ReadUInt32() == NHeader::kPmglSignature) + if (ReadUInt32() == kSignature_PMGL) { // The quickref area is written backwards from the end of the chunk. // One quickref entry exists for every n entries in the file, where n // is calculated as 1 + (1 << quickref density). So for density = 2, n = 5. - UInt32 quickrefLength = ReadUInt32(); // Length of free space and/or quickref area at end of directory chunk + UInt32 quickrefLength = ReadUInt32(); // Len of free space and/or quickref area at end of directory chunk if (quickrefLength > dirChunkSize || quickrefLength < 2) return S_FALSE; ReadUInt32(); // Always 0 @@ -354,7 +379,7 @@ HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database) // directory in sequence (-1 if this is the first listing chunk) ReadUInt32(); // Chunk number of next listing chunk when reading // directory in sequence (-1 if this is the last listing chunk) - int numItems = 0; + unsigned numItems = 0; for (;;) { UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos; @@ -383,10 +408,13 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) if (ReadUInt32() != 0x28) // Location of header section table return S_FALSE; UInt32 numHeaderSections = ReadUInt32(); - const int kNumHeaderSectionsMax = 5; + const unsigned kNumHeaderSectionsMax = 5; if (numHeaderSections != kNumHeaderSectionsMax) return S_FALSE; - ReadUInt32(); // Length of post-header table + + IsArc = true; + + ReadUInt32(); // Len of post-header table GUID g; ReadGUID(g); // {0A9007C1-4076-11D3-8789-0000F8105754} @@ -398,6 +426,8 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) { sectionOffsets[i] = ReadUInt64(); sectionSizes[i] = ReadUInt64(); + UInt64 end = sectionOffsets[i] + sectionSizes[i]; + database.UpdatePhySize(end); } // Post-Header @@ -436,11 +466,11 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) ReadUInt32(); // $20000 (Same as field following chunk size in directory index) ReadUInt64(); // 0 (unknown) - if (ReadUInt32() != NHeader::kCaolSignature) + if (ReadUInt32() != kSignature_CAOL) return S_FALSE; if (ReadUInt32() != 2) // (Most likely a version number) return S_FALSE; - UInt32 caolLength = ReadUInt32(); // $50 (Length of the CAOL section, which includes the ITSF section) + UInt32 caolLength = ReadUInt32(); // $50 (Len of the CAOL section, which includes the ITSF section) if (caolLength >= 0x2C) { /* UInt32 c7 = */ ReadUInt16(); // Unknown. Remains the same when identical files are built. @@ -458,13 +488,15 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) ReadUInt32(); // 0 (Unknown) if (caolLength == 0x2C) { - database.ContentOffset = 0; + // fprintf(stdout, "\n !!!NewFormat\n"); + // fflush(stdout); + database.ContentOffset = 0; // maybe we must add database.StartPosition here? database.NewFormat = true; } else if (caolLength == 0x50) { ReadUInt32(); // 0 (Unknown) - if (ReadUInt32() != NHeader::kItsfSignature) + if (ReadUInt32() != kSignature_ITSF) return S_FALSE; if (ReadUInt32() != 4) // $4 (Version number -- CHM uses 3) return S_FALSE; @@ -473,7 +505,7 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) UInt32 unknown = ReadUInt32(); if (unknown != 0 && unknown != 1) // = 0 for some HxW files, 1 in other cases; return S_FALSE; - database.ContentOffset = _startPosition + ReadUInt64(); + database.ContentOffset = database.StartPosition + ReadUInt64(); /* UInt32 timeStamp = */ ReadUInt32(); // A timestamp of some sort. // Considered as a big-endian DWORD, it appears to contain @@ -486,21 +518,21 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) return S_FALSE; } - /* // Section 0 - ReadChunk(inStream, _startPosition + sectionOffsets[0], sectionSizes[0]); - if (sectionSizes[0] != 0x18) + ReadChunk(inStream, database.StartPosition + sectionOffsets[0], sectionSizes[0]); + if (sectionSizes[0] < 0x18) + return S_FALSE; + if (ReadUInt32() != 0x01FE) return S_FALSE; - ReadUInt32(); // unknown: 01FE ReadUInt32(); // unknown: 0 UInt64 fileSize = ReadUInt64(); + database.UpdatePhySize(fileSize); ReadUInt32(); // unknown: 0 ReadUInt32(); // unknown: 0 - */ // Section 1: The Directory Listing - ReadChunk(inStream, _startPosition + sectionOffsets[1], sectionSizes[1]); - if (ReadUInt32() != NHeader::kIfcmSignature) + ReadChunk(inStream, database.StartPosition + sectionOffsets[1], sectionSizes[1]); + if (ReadUInt32() != kSignature_IFCM) return S_FALSE; if (ReadUInt32() != 1) // (probably a version number) return S_FALSE; @@ -516,9 +548,9 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) for (UInt32 ci = 0; ci < numDirChunks; ci++) { UInt64 chunkPos = _inBuffer.GetProcessedSize(); - if (ReadUInt32() == NHeader::kAollSignature) + if (ReadUInt32() == kSignature_AOLL) { - UInt32 quickrefLength = ReadUInt32(); // Length of quickref area at end of directory chunk + UInt32 quickrefLength = ReadUInt32(); // Len of quickref area at end of directory chunk if (quickrefLength > dirChunkSize || quickrefLength < 2) return S_FALSE; ReadUInt64(); // Directory chunk number @@ -533,7 +565,7 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) ReadUInt32(); // 1 (unknown -- other values have also been seen here) ReadUInt32(); // 0 (unknown) - int numItems = 0; + unsigned numItems = 0; for (;;) { UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos; @@ -544,11 +576,11 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) break; if (database.NewFormat) { - UInt16 nameLength = ReadUInt16(); - if (nameLength == 0) + UInt16 nameLen = ReadUInt16(); + if (nameLen == 0) return S_FALSE; UString name; - ReadUString((int)nameLength, name); + ReadUString((unsigned)nameLen, name); AString s; ConvertUnicodeToUTF8(name, s); Byte b = ReadByte(); @@ -637,10 +669,10 @@ static int CompareFiles(const int *p1, const int *p2, void *param) void CFilesDatabase::SetIndices() { - for (int i = 0; i < Items.Size(); i++) + FOR_VECTOR (i, Items) { const CItem &item = Items[i]; - if (item.IsUserItem() && item.Name.Length() != 1) + if (item.IsUserItem() && item.Name.Len() != 1) Indices.Add(i); } } @@ -654,7 +686,7 @@ bool CFilesDatabase::Check() { UInt64 maxPos = 0; UInt64 prevSection = 0; - for(int i = 0; i < Indices.Size(); i++) + FOR_VECTOR (i, Indices) { const CItem &item = Items[Indices[i]]; if (item.Section == 0 || item.IsDir()) @@ -684,9 +716,9 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) for (int i = 0; i < numSections; i++) { CSectionInfo section; - UInt16 nameLength = ReadUInt16(); + UInt16 nameLen = ReadUInt16(); UString name; - ReadUString(nameLength, name); + ReadUString(nameLen, name); if (ReadUInt16() != 0) return S_FALSE; if (!ConvertUnicodeToUTF8(name, section.Name)) @@ -695,7 +727,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) } } - int i; + unsigned i; for (i = 1; i < database.Sections.Size(); i++) { CSectionInfo §ion = database.Sections[i]; @@ -736,7 +768,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) { // Control Data RINOK(DecompressStream(inStream, database, sectionPrefix + kControlData)); - for (int mi = 0; mi < section.Methods.Size(); mi++) + FOR_VECTOR (mi, section.Methods) { CMethodInfo &method = section.Methods[mi]; UInt32 numDWORDS = ReadUInt32(); @@ -744,7 +776,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) { if (numDWORDS < 5) return S_FALSE; - if (ReadUInt32() != NHeader::kLzxcSignature) + if (ReadUInt32() != kSignature_LZXC) return S_FALSE; CLzxInfo &li = method.LzxInfo; li.Version = ReadUInt32(); @@ -778,7 +810,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) else { UInt32 numBytes = numDWORDS * 4; - method.ControlData.SetCapacity(numBytes); + method.ControlData.Alloc(numBytes); ReadBytes(method.ControlData, numBytes); } } @@ -791,7 +823,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) } // read ResetTable for LZX - for (int mi = 0; mi < section.Methods.Size(); mi++) + FOR_VECTOR (mi, section.Methods) { CMethodInfo &method = section.Methods[mi]; if (method.IsLzx()) @@ -819,16 +851,16 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) UInt32 numEntries = ReadUInt32(); if (ReadUInt32() != 8) // Size of table entry (bytes) return S_FALSE; - if (ReadUInt32() != 0x28) // Length of table header + if (ReadUInt32() != 0x28) // Len of table header return S_FALSE; rt.UncompressedSize = ReadUInt64(); rt.CompressedSize = ReadUInt64(); rt.BlockSize = ReadUInt64(); // 0x8000 block size for locations below if (rt.BlockSize != 0x8000) return S_FALSE; - rt.ResetOffsets.Reserve(numEntries); + rt.ResetOffsets.ClearAndReserve(numEntries); for (UInt32 i = 0; i < numEntries; i++) - rt.ResetOffsets.Add(ReadUInt64()); + rt.ResetOffsets.AddInReserved(ReadUInt64()); } } } @@ -843,77 +875,91 @@ HRESULT CInArchive::Open2(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database) { + IsArc = false; + HeadersError = false; + UnexpectedEnd = false; + UnsupportedFeature = false; + database.Clear(); + database.Help2Format = _help2; + const UInt32 chmVersion = 3; - RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_startPosition)); + RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &database.StartPosition)); - database.Help2Format = false; - const UInt32 chmVersion = 3; + if (!_inBuffer.Create(1 << 14)) + return E_OUTOFMEMORY; + _inBuffer.SetStream(inStream); + _inBuffer.Init(); + + if (_help2) { - if (!_inBuffer.Create(1 << 14)) - return E_OUTOFMEMORY; - _inBuffer.SetStream(inStream); - _inBuffer.Init(); - UInt64 value = 0; const int kSignatureSize = 8; - UInt64 hxsSignature = NHeader::GetHxsSignature(); - UInt64 chmSignature = ((UInt64)chmVersion << 32)| NHeader::kItsfSignature; + UInt64 signature = ((UInt64)kSignature_ITLS << 32)| kSignature_ITOL; UInt64 limit = 1 << 18; if (searchHeaderSizeLimit) if (limit > *searchHeaderSizeLimit) limit = *searchHeaderSizeLimit; + UInt64 val = 0; for (;;) { Byte b; if (!_inBuffer.ReadByte(b)) return S_FALSE; - value >>= 8; - value |= ((UInt64)b) << ((kSignatureSize - 1) * 8); + val >>= 8; + val |= ((UInt64)b) << ((kSignatureSize - 1) * 8); if (_inBuffer.GetProcessedSize() >= kSignatureSize) { - if (value == chmSignature) - break; - if (value == hxsSignature) - { - database.Help2Format = true; + if (val == signature) break; - } if (_inBuffer.GetProcessedSize() > limit) return S_FALSE; } } - _startPosition += _inBuffer.GetProcessedSize() - kSignatureSize; - } - - if (database.Help2Format) - { + database.StartPosition += _inBuffer.GetProcessedSize() - kSignatureSize; RINOK(OpenHelp2(inStream, database)); if (database.NewFormat) return S_OK; } else { + if (ReadUInt32() != kSignature_ITSF) + return S_FALSE; + if (ReadUInt32() != chmVersion) + return S_FALSE; RINOK(OpenChm(inStream, database)); } + #ifndef CHM_LOW + try { - HRESULT res = OpenHighLevel(inStream, database); - if (res == S_FALSE) + try + { + HRESULT res = OpenHighLevel(inStream, database); + if (res == S_FALSE) + { + UnsupportedFeature = true; + database.HighLevelClear(); + return S_OK; + } + RINOK(res); + database.LowLevel = false; + } + catch(...) { database.HighLevelClear(); - return S_OK; + throw; } - RINOK(res); - database.LowLevel = false; - } - catch(...) - { - return S_OK; } + // catch(const CInBufferException &e) { return e.ErrorCode; } + catch(CEnexpectedEndException &) { UnexpectedEnd = true; } + catch(CHeaderErrorException &) { HeadersError = true; } + catch(...) { throw; } + #endif + return S_OK; } @@ -923,15 +969,22 @@ HRESULT CInArchive::Open(IInStream *inStream, { try { - HRESULT res = Open2(inStream, searchHeaderSizeLimit, database); - _inBuffer.ReleaseStream(); - return res; - } - catch(...) - { - _inBuffer.ReleaseStream(); - throw; + try + { + HRESULT res = Open2(inStream, searchHeaderSizeLimit, database); + m_InStreamRef.Release(); + return res; + } + catch(...) + { + m_InStreamRef.Release(); + throw; + } } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(CEnexpectedEndException &) { UnexpectedEnd = true; } + catch(CHeaderErrorException &) { HeadersError = true; } + return S_FALSE; } }} diff --git a/CPP/7zip/Archive/Chm/ChmIn.h b/CPP/7zip/Archive/Chm/ChmIn.h index 4b1ac7a6..70764ab9 100755..100644 --- a/CPP/7zip/Archive/Chm/ChmIn.h +++ b/CPP/7zip/Archive/Chm/ChmIn.h @@ -3,13 +3,12 @@ #ifndef __ARCHIVE_CHM_IN_H #define __ARCHIVE_CHM_IN_H -#include "Common/Buffer.h" -#include "Common/MyString.h" +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyString.h" #include "../../IStream.h" -#include "../../Common/InBuffer.h" -#include "ChmHeader.h" +#include "../../Common/InBuffer.h" namespace NArchive { namespace NChm { @@ -23,21 +22,21 @@ struct CItem bool IsFormatRelatedItem() const { - if (Name.Length() < 2) + if (Name.Len() < 2) return false; return Name[0] == ':' && Name[1] == ':'; } bool IsUserItem() const { - if (Name.Length() < 2) + if (Name.Len() < 2) return false; return Name[0] == '/'; } bool IsDir() const { - if (Name.Length() == 0) + if (Name.Len() == 0) return false; return (Name.Back() == '/'); } @@ -45,15 +44,19 @@ struct CItem struct CDatabase { + UInt64 StartPosition; UInt64 ContentOffset; CObjectVector<CItem> Items; AString NewFormatString; bool Help2Format; bool NewFormat; + UInt64 PhySize; + + void UpdatePhySize(UInt64 v) { if (PhySize < v) PhySize = v; } int FindItem(const AString &name) const { - for (int i = 0; i < Items.Size(); i++) + FOR_VECTOR (i, Items) if (Items[i].Name == name) return i; return -1; @@ -65,6 +68,8 @@ struct CDatabase NewFormatString.Empty(); Help2Format = false; Items.Clear(); + StartPosition = 0; + PhySize = 0; } }; @@ -74,15 +79,16 @@ struct CResetTable UInt64 CompressedSize; UInt64 BlockSize; CRecordVector<UInt64> ResetOffsets; + bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const { if (blockIndex >= ResetOffsets.Size()) return false; - UInt64 startPos = ResetOffsets[(int)blockIndex]; + UInt64 startPos = ResetOffsets[(unsigned)blockIndex]; if (blockIndex + numBlocks >= ResetOffsets.Size()) size = CompressedSize - startPos; else - size = ResetOffsets[(int)(blockIndex + numBlocks)] - startPos; + size = ResetOffsets[(unsigned)(blockIndex + numBlocks)] - startPos; return true; } bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const @@ -107,7 +113,7 @@ struct CLzxInfo { if (Version == 2 || Version == 3) { - for (int i = 0; i <= 31; i++) + for (unsigned i = 0; i <= 31; i++) if (((UInt32)1 << i) >= WindowSize) return 15 + i; } @@ -123,7 +129,7 @@ struct CLzxInfo UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex); if (blockIndex >= ResetTable.ResetOffsets.Size()) return false; - offset = ResetTable.ResetOffsets[(int)blockIndex]; + offset = ResetTable.ResetOffsets[(unsigned)blockIndex]; return true; } bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const @@ -202,18 +208,21 @@ public: bool Check(); }; +/* class CProgressVirt { public: STDMETHOD(SetTotal)(const UInt64 *numFiles) PURE; STDMETHOD(SetCompleted)(const UInt64 *numFiles) PURE; }; +*/ class CInArchive { - UInt64 _startPosition; + CMyComPtr<ISequentialInStream> m_InStreamRef; ::CInBuffer _inBuffer; UInt64 _chunkSize; + bool _help2; Byte ReadByte(); void ReadBytes(Byte *data, UInt32 size); @@ -222,8 +231,8 @@ class CInArchive UInt32 ReadUInt32(); UInt64 ReadUInt64(); UInt64 ReadEncInt(); - void ReadString(int size, AString &s); - void ReadUString(int size, UString &s); + void ReadString(unsigned size, AString &s); + void ReadUString(unsigned size, UString &s); void ReadGUID(GUID &g); HRESULT ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size); @@ -232,6 +241,13 @@ class CInArchive HRESULT DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name); public: + bool IsArc; + bool HeadersError; + bool UnexpectedEnd; + bool UnsupportedFeature; + + CInArchive(bool help2) { _help2 = help2; } + HRESULT OpenChm(IInStream *inStream, CDatabase &database); HRESULT OpenHelp2(IInStream *inStream, CDatabase &database); HRESULT OpenHighLevel(IInStream *inStream, CFilesDatabase &database); diff --git a/CPP/7zip/Archive/Chm/ChmRegister.cpp b/CPP/7zip/Archive/Chm/ChmRegister.cpp deleted file mode 100755 index e5f38afa..00000000 --- a/CPP/7zip/Archive/Chm/ChmRegister.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// ChmRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "ChmHandler.h" -static IInArchive *CreateArc() { return new NArchive::NChm::CHandler; } - -static CArcInfo g_ArcInfo = - { L"Chm", L"chm chi chq chw hxs hxi hxr hxq hxw lit", 0, 0xE9, { 'I', 'T', 'S', 'F' }, 4, false, CreateArc, 0 }; - -REGISTER_ARC(Chm) diff --git a/CPP/7zip/Archive/Chm/StdAfx.h b/CPP/7zip/Archive/Chm/StdAfx.h index e7fb6986..2854ff3e 100755..100644 --- a/CPP/7zip/Archive/Chm/StdAfx.h +++ b/CPP/7zip/Archive/Chm/StdAfx.h @@ -3,6 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" +#include "../../../Common/Common.h" #endif diff --git a/CPP/7zip/Archive/Com/ComHandler.cpp b/CPP/7zip/Archive/Com/ComHandler.cpp deleted file mode 100755 index 58f76439..00000000 --- a/CPP/7zip/Archive/Com/ComHandler.cpp +++ /dev/null @@ -1,239 +0,0 @@ -// ComHandler.cpp - -#include "StdAfx.h" - -#include "Common/ComTry.h" - -#include "Windows/PropVariant.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamUtils.h" - -#include "../../Compress/CopyCoder.h" - -#include "ComHandler.h" - -namespace NArchive { -namespace NCom { - -STATPROPSTG kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidMTime, VT_FILETIME} -}; - -STATPROPSTG kArcProps[] = -{ - { NULL, kpidClusterSize, VT_UI4}, - { NULL, kpidSectorSize, VT_UI4} -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) - { - case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break; - case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break; - case kpidMainSubfile: if (_db.MainSubfile >= 0) prop = (UInt32)_db.MainSubfile; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CRef &ref = _db.Refs[index]; - const CItem &item = _db.Items[ref.Did]; - - switch(propID) - { - case kpidPath: prop = _db.GetItemPath(index); break; - case kpidIsDir: prop = item.IsDir(); break; - case kpidCTime: prop = item.CTime; break; - case kpidMTime: prop = item.MTime; break; - case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break; - case kpidSize: if (!item.IsDir()) prop = item.Size; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) -{ - COM_TRY_BEGIN - Close(); - try - { - if (_db.Open(inStream) != S_OK) - return S_FALSE; - _stream = inStream; - } - catch(...) { return S_FALSE; } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _db.Clear(); - _stream.Release(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); - if (allFilesMode) - numItems = _db.Refs.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - UInt64 totalSize = 0; - for(i = 0; i < numItems; i++) - { - const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did]; - if (!item.IsDir()) - totalSize += item.Size; - } - RINOK(extractCallback->SetTotal(totalSize)); - - UInt64 totalPackSize; - totalSize = totalPackSize = 0; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr<ICompressProgressInfo> progress = lps; - lps->Init(extractCallback, false); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()); - Int32 index = allFilesMode ? i : indices[i]; - const CItem &item = _db.Items[_db.Refs[index].Did]; - - CMyComPtr<ISequentialOutStream> outStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(index, &outStream, askMode)); - - if (item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - - totalPackSize += _db.GetItemPackSize(item.Size); - totalSize += item.Size; - - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - Int32 res = NExtract::NOperationResult::kDataError; - CMyComPtr<ISequentialInStream> inStream; - HRESULT hres = GetStream(index, &inStream); - if (hres == S_FALSE) - res = NExtract::NOperationResult::kDataError; - else if (hres == E_NOTIMPL) - res = NExtract::NOperationResult::kUnSupportedMethod; - else - { - RINOK(hres); - if (inStream) - { - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); - if (copyCoderSpec->TotalSize == item.Size) - res = NExtract::NOperationResult::kOK; - } - } - outStream.Release(); - RINOK(extractCallback->SetOperationResult(res)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _db.Refs.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - *stream = 0; - const CItem &item = _db.Items[_db.Refs[index].Did]; - CClusterInStream *streamSpec = new CClusterInStream; - CMyComPtr<ISequentialInStream> streamTemp = streamSpec; - streamSpec->Stream = _stream; - streamSpec->StartOffset = 0; - - bool isLargeStream = _db.IsLargeStream(item.Size); - int bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits; - streamSpec->BlockSizeLog = bsLog; - streamSpec->Size = item.Size; - - UInt32 clusterSize = (UInt32)1 << bsLog; - UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog; - if (numClusters64 >= ((UInt32)1 << 31)) - return E_NOTIMPL; - streamSpec->Vector.Reserve((int)numClusters64); - UInt32 sid = item.Sid; - UInt64 size = item.Size; - - if (size != 0) - { - for (;; size -= clusterSize) - { - if (isLargeStream) - { - if (sid >= _db.FatSize) - return S_FALSE; - streamSpec->Vector.Add(sid + 1); - sid = _db.Fat[sid]; - } - else - { - UInt64 val; - if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32) - return S_FALSE; - streamSpec->Vector.Add((UInt32)val); - sid = _db.Mat[sid]; - } - if (size <= clusterSize) - break; - } - } - if (sid != NFatID::kEndOfChain) - return S_FALSE; - RINOK(streamSpec->InitAndSeek()); - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - -}} diff --git a/CPP/7zip/Archive/Com/ComHandler.h b/CPP/7zip/Archive/Com/ComHandler.h deleted file mode 100755 index f2b7de96..00000000 --- a/CPP/7zip/Archive/Com/ComHandler.h +++ /dev/null @@ -1,28 +0,0 @@ -// ComHandler.h - -#ifndef __ARCHIVE_COM_HANDLER_H -#define __ARCHIVE_COM_HANDLER_H - -#include "Common/MyCom.h" -#include "../IArchive.h" -#include "ComIn.h" - -namespace NArchive { -namespace NCom { - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CMyComPtr<IInStream> _stream; - CDatabase _db; -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - -}} - -#endif diff --git a/CPP/7zip/Archive/Com/ComIn.cpp b/CPP/7zip/Archive/Com/ComIn.cpp deleted file mode 100755 index 2203ca53..00000000 --- a/CPP/7zip/Archive/Com/ComIn.cpp +++ /dev/null @@ -1,389 +0,0 @@ -// Archive/ComIn.cpp - -#include "StdAfx.h" - -#include "../../../../C/Alloc.h" -#include "../../../../C/CpuArch.h" - -#include "Common/IntToString.h" -#include "Common/MyCom.h" - -#include "../../Common/StreamUtils.h" - -#include "ComIn.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) - -namespace NArchive{ -namespace NCom{ - -static const UInt32 kSignatureSize = 8; -static const Byte kSignature[kSignatureSize] = { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }; - -void CUInt32Buf::Free() -{ - MyFree(_buf); - _buf = 0; -} - -bool CUInt32Buf::Allocate(UInt32 numItems) -{ - Free(); - if (numItems == 0) - return true; - size_t newSize = (size_t)numItems * sizeof(UInt32); - if (newSize / sizeof(UInt32) != numItems) - return false; - _buf = (UInt32 *)MyAlloc(newSize); - return (_buf != 0); -} - -static HRESULT ReadSector(IInStream *inStream, Byte *buf, int sectorSizeBits, UInt32 sid) -{ - RINOK(inStream->Seek((((UInt64)sid + 1) << sectorSizeBits), STREAM_SEEK_SET, NULL)); - return ReadStream_FALSE(inStream, buf, (UInt32)1 << sectorSizeBits); -} - -static HRESULT ReadIDs(IInStream *inStream, Byte *buf, int sectorSizeBits, UInt32 sid, UInt32 *dest) -{ - RINOK(ReadSector(inStream, buf, sectorSizeBits, sid)); - UInt32 sectorSize = (UInt32)1 << sectorSizeBits; - for (UInt32 t = 0; t < sectorSize; t += 4) - *dest++ = Get32(buf + t); - return S_OK; -} - -static void GetFileTimeFromMem(const Byte *p, FILETIME *ft) -{ - ft->dwLowDateTime = Get32(p); - ft->dwHighDateTime = Get32(p + 4); -} - -void CItem::Parse(const Byte *p, bool mode64bit) -{ - memcpy(Name, p, kNameSizeMax); - // NameSize = Get16(p + 64); - Type = p[66]; - LeftDid = Get32(p + 68); - RightDid = Get32(p + 72); - SonDid = Get32(p + 76); - // Flags = Get32(p + 96); - GetFileTimeFromMem(p + 100, &CTime); - GetFileTimeFromMem(p + 108, &MTime); - Sid = Get32(p + 116); - Size = Get32(p + 120); - if (mode64bit) - Size |= ((UInt64)Get32(p + 124) << 32); -} - -void CDatabase::Clear() -{ - Fat.Free(); - MiniSids.Free(); - Mat.Free(); - Items.Clear(); - Refs.Clear(); -} - -static const UInt32 kNoDid = 0xFFFFFFFF; - -HRESULT CDatabase::AddNode(int parent, UInt32 did) -{ - if (did == kNoDid) - return S_OK; - if (did >= (UInt32)Items.Size()) - return S_FALSE; - const CItem &item = Items[did]; - if (item.IsEmpty()) - return S_FALSE; - CRef ref; - ref.Parent = parent; - ref.Did = did; - int index = Refs.Add(ref); - if (Refs.Size() > Items.Size()) - return S_FALSE; - RINOK(AddNode(parent, item.LeftDid)); - RINOK(AddNode(parent, item.RightDid)); - if (item.IsDir()) - { - RINOK(AddNode(index, item.SonDid)); - } - return S_OK; -} - -static const char kCharOpenBracket = '['; -static const char kCharCloseBracket = ']'; - -static UString CompoundNameToFileName(const UString &s) -{ - UString res; - for (int i = 0; i < s.Length(); i++) - { - wchar_t c = s[i]; - if (c < 0x20) - { - res += kCharOpenBracket; - wchar_t buf[32]; - ConvertUInt32ToString(c, buf); - res += buf; - res += kCharCloseBracket; - } - else - res += c; - } - return res; -} - -static char g_MsiChars[] = -"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._"; - -static const wchar_t *kMsi_ID = L""; // L"{msi}"; - -static const int kMsiNumBits = 6; -static const UInt32 kMsiNumChars = 1 << kMsiNumBits; -static const UInt32 kMsiCharMask = kMsiNumChars - 1; -static const UInt32 kMsiStartUnicodeChar = 0x3800; -static const UInt32 kMsiUnicodeRange = kMsiNumChars * (kMsiNumChars + 1); - -bool CompoundMsiNameToFileName(const UString &name, UString &resultName) -{ - resultName.Empty(); - for (int i = 0; i < name.Length(); i++) - { - wchar_t c = name[i]; - if (c < kMsiStartUnicodeChar || c > kMsiStartUnicodeChar + kMsiUnicodeRange) - return false; - if (i == 0) - resultName += kMsi_ID; - c -= kMsiStartUnicodeChar; - - UInt32 c0 = c & kMsiCharMask; - UInt32 c1 = c >> kMsiNumBits; - - if (c1 <= kMsiNumChars) - { - resultName += (wchar_t)g_MsiChars[c0]; - if (c1 == kMsiNumChars) - break; - resultName += (wchar_t)g_MsiChars[c1]; - } - else - resultName += L'!'; - } - return true; -} - -static UString ConvertName(const Byte *p, bool &isMsi) -{ - isMsi = false; - UString s; - for (int i = 0; i < kNameSizeMax; i += 2) - { - wchar_t c = (p[i] | (wchar_t)p[i + 1] << 8); - if (c == 0) - break; - s += c; - } - UString msiName; - if (CompoundMsiNameToFileName(s, msiName)) - { - isMsi = true; - return msiName; - } - return CompoundNameToFileName(s); -} - -static UString ConvertName(const Byte *p) -{ - bool isMsi; - return ConvertName(p, isMsi); -} - -UString CDatabase::GetItemPath(UInt32 index) const -{ - UString s; - while (index != kNoDid) - { - const CRef &ref = Refs[index]; - const CItem &item = Items[ref.Did]; - if (!s.IsEmpty()) - s = (UString)WCHAR_PATH_SEPARATOR + s; - s = ConvertName(item.Name) + s; - index = ref.Parent; - } - return s; -} - -HRESULT CDatabase::Open(IInStream *inStream) -{ - MainSubfile = -1; - static const UInt32 kHeaderSize = 512; - Byte p[kHeaderSize]; - RINOK(ReadStream_FALSE(inStream, p, kHeaderSize)); - if (memcmp(p, kSignature, kSignatureSize) != 0) - return S_FALSE; - if (Get16(p + 0x1A) > 4) // majorVer - return S_FALSE; - if (Get16(p + 0x1C) != 0xFFFE) - return S_FALSE; - int sectorSizeBits = Get16(p + 0x1E); - bool mode64bit = (sectorSizeBits >= 12); - int miniSectorSizeBits = Get16(p + 0x20); - SectorSizeBits = sectorSizeBits; - MiniSectorSizeBits = miniSectorSizeBits; - - if (sectorSizeBits > 28 || miniSectorSizeBits > 28 || - sectorSizeBits < 7 || miniSectorSizeBits < 2 || miniSectorSizeBits > sectorSizeBits) - return S_FALSE; - UInt32 numSectorsForFAT = Get32(p + 0x2C); - LongStreamMinSize = Get32(p + 0x38); - - UInt32 sectSize = (UInt32)1 << (int)sectorSizeBits; - - CByteBuffer sect; - sect.SetCapacity(sectSize); - - int ssb2 = (int)(sectorSizeBits - 2); - UInt32 numSidsInSec = (UInt32)1 << ssb2; - UInt32 numFatItems = numSectorsForFAT << ssb2; - if ((numFatItems >> ssb2) != numSectorsForFAT) - return S_FALSE; - FatSize = numFatItems; - - { - CUInt32Buf bat; - UInt32 numSectorsForBat = Get32(p + 0x48); - const UInt32 kNumHeaderBatItems = 109; - UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2); - if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat) - return S_FALSE; - if (!bat.Allocate(numBatItems)) - return S_FALSE; - UInt32 i; - for (i = 0; i < kNumHeaderBatItems; i++) - bat[i] = Get32(p + 0x4c + i * 4); - UInt32 sid = Get32(p + 0x44); - for (UInt32 s = 0; s < numSectorsForBat; s++) - { - RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i)); - i += numSidsInSec - 1; - sid = bat[i]; - } - numBatItems = i; - - if (!Fat.Allocate(numFatItems)) - return S_FALSE; - UInt32 j = 0; - - for (i = 0; i < numFatItems; j++, i += numSidsInSec) - { - if (j >= numBatItems) - return S_FALSE; - RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], Fat + i)); - } - } - - UInt32 numMatItems; - { - UInt32 numSectorsForMat = Get32(p + 0x40); - numMatItems = (UInt32)numSectorsForMat << ssb2; - if ((numMatItems >> ssb2) != numSectorsForMat) - return S_FALSE; - if (!Mat.Allocate(numMatItems)) - return S_FALSE; - UInt32 i; - UInt32 sid = Get32(p + 0x3C); - for (i = 0; i < numMatItems; i += numSidsInSec) - { - RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, Mat + i)); - if (sid >= numFatItems) - return S_FALSE; - sid = Fat[sid]; - } - if (sid != NFatID::kEndOfChain) - return S_FALSE; - } - - { - UInt32 sid = Get32(p + 0x30); - for (;;) - { - if (sid >= numFatItems) - return S_FALSE; - RINOK(ReadSector(inStream, sect, sectorSizeBits, sid)); - for (UInt32 i = 0; i < sectSize; i += 128) - { - CItem item; - item.Parse(sect + i, mode64bit); - Items.Add(item); - } - sid = Fat[sid]; - if (sid == NFatID::kEndOfChain) - break; - } - } - - CItem root = Items[0]; - - { - UInt32 numSectorsInMiniStream; - { - UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits; - if (numSatSects64 > NFatID::kMaxValue) - return S_FALSE; - numSectorsInMiniStream = (UInt32)numSatSects64; - } - NumSectorsInMiniStream = numSectorsInMiniStream; - if (!MiniSids.Allocate(numSectorsInMiniStream)) - return S_FALSE; - { - UInt64 matSize64 = (root.Size + ((UInt64)1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits; - if (matSize64 > NFatID::kMaxValue) - return S_FALSE; - MatSize = (UInt32)matSize64; - if (numMatItems < MatSize) - return S_FALSE; - } - - UInt32 sid = root.Sid; - for (UInt32 i = 0; ; i++) - { - if (sid == NFatID::kEndOfChain) - { - if (i != numSectorsInMiniStream) - return S_FALSE; - break; - } - if (i >= numSectorsInMiniStream) - return S_FALSE; - MiniSids[i] = sid; - if (sid >= numFatItems) - return S_FALSE; - sid = Fat[sid]; - } - } - - RINOK(AddNode(-1, root.SonDid)); - - unsigned numCabs = 0; - for (int i = 0; i < Refs.Size(); i++) - { - const CItem &item = Items[Refs[i].Did]; - if (item.IsDir() || numCabs > 1) - continue; - bool isMsiName; - UString msiName = ConvertName(item.Name, isMsiName); - if (isMsiName && msiName.Right(4).CompareNoCase(L".cab") == 0) - { - numCabs++; - MainSubfile = i; - } - } - if (numCabs > 1) - MainSubfile = -1; - - return S_OK; -} - -}} diff --git a/CPP/7zip/Archive/Com/ComIn.h b/CPP/7zip/Archive/Com/ComIn.h deleted file mode 100755 index 429d3796..00000000 --- a/CPP/7zip/Archive/Com/ComIn.h +++ /dev/null @@ -1,119 +0,0 @@ -// Archive/ComIn.h - -#ifndef __ARCHIVE_COM_IN_H -#define __ARCHIVE_COM_IN_H - -#include "Common/MyString.h" -#include "Common/Buffer.h" - -namespace NArchive { -namespace NCom { - -struct CUInt32Buf -{ - UInt32 *_buf; -public: - CUInt32Buf(): _buf(0) {} - ~CUInt32Buf() { Free(); } - void Free(); - bool Allocate(UInt32 numItems); - operator UInt32 *() const { return _buf; }; -}; - -namespace NFatID -{ - const UInt32 kFree = 0xFFFFFFFF; - const UInt32 kEndOfChain = 0xFFFFFFFE; - const UInt32 kFatSector = 0xFFFFFFFD; - const UInt32 kMatSector = 0xFFFFFFFC; - const UInt32 kMaxValue = 0xFFFFFFFA; -} - -namespace NItemType -{ - const Byte kEmpty = 0; - const Byte kStorage = 1; - const Byte kStream = 2; - const Byte kLockBytes = 3; - const Byte kProperty = 4; - const Byte kRootStorage = 5; -} - -const UInt32 kNameSizeMax = 64; - -struct CItem -{ - Byte Name[kNameSizeMax]; - // UInt16 NameSize; - // UInt32 Flags; - FILETIME CTime; - FILETIME MTime; - UInt64 Size; - UInt32 LeftDid; - UInt32 RightDid; - UInt32 SonDid; - UInt32 Sid; - Byte Type; - - bool IsEmpty() const { return Type == NItemType::kEmpty; } - bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; } - - void Parse(const Byte *p, bool mode64bit); -}; - -struct CRef -{ - int Parent; - UInt32 Did; -}; - -class CDatabase -{ - UInt32 NumSectorsInMiniStream; - CUInt32Buf MiniSids; - - HRESULT AddNode(int parent, UInt32 did); -public: - - CUInt32Buf Fat; - UInt32 FatSize; - - CUInt32Buf Mat; - UInt32 MatSize; - - CObjectVector<CItem> Items; - CRecordVector<CRef> Refs; - - UInt32 LongStreamMinSize; - int SectorSizeBits; - int MiniSectorSizeBits; - - Int32 MainSubfile; - - void Clear(); - bool IsLargeStream(UInt64 size) const { return size >= LongStreamMinSize; } - UString GetItemPath(UInt32 index) const; - - UInt64 GetItemPackSize(UInt64 size) const - { - UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1; - return (size + mask) & ~mask; - } - - bool GetMiniCluster(UInt32 sid, UInt64 &res) const - { - int subBits = SectorSizeBits - MiniSectorSizeBits; - UInt32 fid = sid >> subBits; - if (fid >= NumSectorsInMiniStream) - return false; - res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1)); - return true; - } - - HRESULT Open(IInStream *inStream); -}; - - -}} - -#endif diff --git a/CPP/7zip/Archive/Com/ComRegister.cpp b/CPP/7zip/Archive/Com/ComRegister.cpp deleted file mode 100755 index 6712b890..00000000 --- a/CPP/7zip/Archive/Com/ComRegister.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// ComRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "ComHandler.h" -static IInArchive *CreateArc() { return new NArchive::NCom::CHandler; } - -static CArcInfo g_ArcInfo = - { L"Compound", L"msi msp doc xls ppt", 0, 0xE5, { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }, 8, false, CreateArc, 0 }; - -REGISTER_ARC(Com) diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp new file mode 100644 index 00000000..fc686b94 --- /dev/null +++ b/CPP/7zip/Archive/ComHandler.cpp @@ -0,0 +1,875 @@ +// ComHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" +#include "../../../C/CpuArch.h" + +#include "../../Common/IntToString.h" +#include "../../Common/ComTry.h" +#include "../../Common/MyCom.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/MyString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + +namespace NArchive { +namespace NCom { + +#define SIGNATURE { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 } +static const UInt32 kSignatureSize = 8; +static const Byte kSignature[kSignatureSize] = SIGNATURE; + +enum EType +{ + k_Type_Common, + k_Type_Msi, + k_Type_Msp, + k_Type_Doc, + k_Type_Ppt, + k_Type_Xls, +}; + +static const char *kExtensions[] = +{ + "compound" + , "msi" + , "msp" + , "doc" + , "ppt" + , "xls" +}; + +namespace NFatID +{ + static const UInt32 kFree = 0xFFFFFFFF; + static const UInt32 kEndOfChain = 0xFFFFFFFE; + static const UInt32 kFatSector = 0xFFFFFFFD; + static const UInt32 kMatSector = 0xFFFFFFFC; + static const UInt32 kMaxValue = 0xFFFFFFFA; +} + +namespace NItemType +{ + static const Byte kEmpty = 0; + static const Byte kStorage = 1; + static const Byte kStream = 2; + static const Byte kLockBytes = 3; + static const Byte kProperty = 4; + static const Byte kRootStorage = 5; +} + +static const UInt32 kNameSizeMax = 64; + +struct CItem +{ + Byte Name[kNameSizeMax]; + // UInt16 NameSize; + // UInt32 Flags; + FILETIME CTime; + FILETIME MTime; + UInt64 Size; + UInt32 LeftDid; + UInt32 RightDid; + UInt32 SonDid; + UInt32 Sid; + Byte Type; + + bool IsEmpty() const { return Type == NItemType::kEmpty; } + bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; } + + void Parse(const Byte *p, bool mode64bit); +}; + +struct CRef +{ + int Parent; + UInt32 Did; +}; + +class CDatabase +{ + UInt32 NumSectorsInMiniStream; + CObjArray<UInt32> MiniSids; + + HRESULT AddNode(int parent, UInt32 did); +public: + + CObjArray<UInt32> Fat; + UInt32 FatSize; + + CObjArray<UInt32> Mat; + UInt32 MatSize; + + CObjectVector<CItem> Items; + CRecordVector<CRef> Refs; + + UInt32 LongStreamMinSize; + unsigned SectorSizeBits; + unsigned MiniSectorSizeBits; + + Int32 MainSubfile; + + UInt64 PhySize; + EType Type; + + bool IsNotArcType() const + { + return + Type != k_Type_Msi && + Type != k_Type_Msp; + } + + void UpdatePhySize(UInt64 val) + { + if (PhySize < val) + PhySize = val; + } + HRESULT ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid); + HRESULT ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest); + + HRESULT Update_PhySize_WithItem(unsigned index); + + void Clear(); + bool IsLargeStream(UInt64 size) const { return size >= LongStreamMinSize; } + UString GetItemPath(UInt32 index) const; + + UInt64 GetItemPackSize(UInt64 size) const + { + UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1; + return (size + mask) & ~mask; + } + + bool GetMiniCluster(UInt32 sid, UInt64 &res) const + { + unsigned subBits = SectorSizeBits - MiniSectorSizeBits; + UInt32 fid = sid >> subBits; + if (fid >= NumSectorsInMiniStream) + return false; + res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1)); + return true; + } + + HRESULT Open(IInStream *inStream); +}; + + +HRESULT CDatabase::ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid) +{ + UpdatePhySize(((UInt64)sid + 2) << sectorSizeBits); + RINOK(inStream->Seek((((UInt64)sid + 1) << sectorSizeBits), STREAM_SEEK_SET, NULL)); + return ReadStream_FALSE(inStream, buf, (UInt32)1 << sectorSizeBits); +} + +HRESULT CDatabase::ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest) +{ + RINOK(ReadSector(inStream, buf, sectorSizeBits, sid)); + UInt32 sectorSize = (UInt32)1 << sectorSizeBits; + for (UInt32 t = 0; t < sectorSize; t += 4) + *dest++ = Get32(buf + t); + return S_OK; +} + +static void GetFileTimeFromMem(const Byte *p, FILETIME *ft) +{ + ft->dwLowDateTime = Get32(p); + ft->dwHighDateTime = Get32(p + 4); +} + +void CItem::Parse(const Byte *p, bool mode64bit) +{ + memcpy(Name, p, kNameSizeMax); + // NameSize = Get16(p + 64); + Type = p[66]; + LeftDid = Get32(p + 68); + RightDid = Get32(p + 72); + SonDid = Get32(p + 76); + // Flags = Get32(p + 96); + GetFileTimeFromMem(p + 100, &CTime); + GetFileTimeFromMem(p + 108, &MTime); + Sid = Get32(p + 116); + Size = Get32(p + 120); + if (mode64bit) + Size |= ((UInt64)Get32(p + 124) << 32); +} + +void CDatabase::Clear() +{ + PhySize = 0; + + Fat.Free(); + MiniSids.Free(); + Mat.Free(); + Items.Clear(); + Refs.Clear(); +} + +static const UInt32 kNoDid = 0xFFFFFFFF; + +HRESULT CDatabase::AddNode(int parent, UInt32 did) +{ + if (did == kNoDid) + return S_OK; + if (did >= (UInt32)Items.Size()) + return S_FALSE; + const CItem &item = Items[did]; + if (item.IsEmpty()) + return S_FALSE; + CRef ref; + ref.Parent = parent; + ref.Did = did; + int index = Refs.Add(ref); + if (Refs.Size() > Items.Size()) + return S_FALSE; + RINOK(AddNode(parent, item.LeftDid)); + RINOK(AddNode(parent, item.RightDid)); + if (item.IsDir()) + { + RINOK(AddNode(index, item.SonDid)); + } + return S_OK; +} + +static const char kCharOpenBracket = '['; +static const char kCharCloseBracket = ']'; + +static UString CompoundNameToFileName(const UString &s) +{ + UString res; + for (unsigned i = 0; i < s.Len(); i++) + { + wchar_t c = s[i]; + if (c < 0x20) + { + res += kCharOpenBracket; + wchar_t buf[32]; + ConvertUInt32ToString(c, buf); + res += buf; + res += kCharCloseBracket; + } + else + res += c; + } + return res; +} + +static char g_MsiChars[] = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._"; + +static const wchar_t *kMsi_ID = L""; // L"{msi}"; + +static const unsigned kMsiNumBits = 6; +static const UInt32 kMsiNumChars = 1 << kMsiNumBits; +static const UInt32 kMsiCharMask = kMsiNumChars - 1; +static const UInt32 kMsiStartUnicodeChar = 0x3800; +static const UInt32 kMsiUnicodeRange = kMsiNumChars * (kMsiNumChars + 1); + +static bool IsMsiName(const Byte *p) +{ + UInt32 c = Get16(p); + return + c >= kMsiStartUnicodeChar && + c <= kMsiStartUnicodeChar + kMsiUnicodeRange; +} + +static bool AreEqualNames(const Byte *rawName, const char *asciiName) +{ + for (unsigned i = 0; i < kNameSizeMax / 2; i++) + { + wchar_t c = Get16(rawName + i * 2); + wchar_t c2 = (Byte)asciiName[i]; + if (c != c2) + return false; + if (c == 0) + return true; + } + return false; +} + +static bool CompoundMsiNameToFileName(const UString &name, UString &resultName) +{ + resultName.Empty(); + for (unsigned i = 0; i < name.Len(); i++) + { + wchar_t c = name[i]; + if (c < kMsiStartUnicodeChar || c > kMsiStartUnicodeChar + kMsiUnicodeRange) + return false; + if (i == 0) + resultName += kMsi_ID; + c -= kMsiStartUnicodeChar; + + UInt32 c0 = c & kMsiCharMask; + UInt32 c1 = c >> kMsiNumBits; + + if (c1 <= kMsiNumChars) + { + resultName += (wchar_t)g_MsiChars[c0]; + if (c1 == kMsiNumChars) + break; + resultName += (wchar_t)g_MsiChars[c1]; + } + else + resultName += L'!'; + } + return true; +} + +static UString ConvertName(const Byte *p, bool &isMsi) +{ + isMsi = false; + UString s; + for (unsigned i = 0; i < kNameSizeMax; i += 2) + { + wchar_t c = Get16(p + i); + if (c == 0) + break; + s += c; + } + UString msiName; + if (CompoundMsiNameToFileName(s, msiName)) + { + isMsi = true; + return msiName; + } + return CompoundNameToFileName(s); +} + +static UString ConvertName(const Byte *p) +{ + bool isMsi; + return ConvertName(p, isMsi); +} + +UString CDatabase::GetItemPath(UInt32 index) const +{ + UString s; + while (index != kNoDid) + { + const CRef &ref = Refs[index]; + const CItem &item = Items[ref.Did]; + if (!s.IsEmpty()) + s.InsertAtFront(WCHAR_PATH_SEPARATOR); + s.Insert(0, ConvertName(item.Name)); + index = ref.Parent; + } + return s; +} + +HRESULT CDatabase::Update_PhySize_WithItem(unsigned index) +{ + const CItem &item = Items[index]; + bool isLargeStream = (index == 0 || IsLargeStream(item.Size)); + if (!isLargeStream) + return S_OK; + unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits; + // streamSpec->Size = item.Size; + + UInt32 clusterSize = (UInt32)1 << bsLog; + UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog; + if (numClusters64 >= ((UInt32)1 << 31)) + return S_FALSE; + UInt32 sid = item.Sid; + UInt64 size = item.Size; + + if (size != 0) + { + for (;; size -= clusterSize) + { + // if (isLargeStream) + { + if (sid >= FatSize) + return S_FALSE; + UpdatePhySize(((UInt64)sid + 2) << bsLog); + sid = Fat[sid]; + } + if (size <= clusterSize) + break; + } + } + if (sid != NFatID::kEndOfChain) + return S_FALSE; + return S_OK; +} + +// There is name "[!]MsiPatchSequence" in msp files +static const unsigned kMspSequence_Size = 18; +static const Byte kMspSequence[kMspSequence_Size] = + { 0x40, 0x48, 0x96, 0x45, 0x6C, 0x3E, 0xE4, 0x45, + 0xE6, 0x42, 0x16, 0x42, 0x37, 0x41, 0x27, 0x41, + 0x37, 0x41 }; + +HRESULT CDatabase::Open(IInStream *inStream) +{ + MainSubfile = -1; + Type = k_Type_Common; + const UInt32 kHeaderSize = 512; + Byte p[kHeaderSize]; + PhySize = kHeaderSize; + RINOK(ReadStream_FALSE(inStream, p, kHeaderSize)); + if (memcmp(p, kSignature, kSignatureSize) != 0) + return S_FALSE; + if (Get16(p + 0x1A) > 4) // majorVer + return S_FALSE; + if (Get16(p + 0x1C) != 0xFFFE) // Little-endian + return S_FALSE; + unsigned sectorSizeBits = Get16(p + 0x1E); + bool mode64bit = (sectorSizeBits >= 12); + unsigned miniSectorSizeBits = Get16(p + 0x20); + SectorSizeBits = sectorSizeBits; + MiniSectorSizeBits = miniSectorSizeBits; + + if (sectorSizeBits > 28 || + sectorSizeBits < 7 || + miniSectorSizeBits > 28 || + miniSectorSizeBits < 2 || + miniSectorSizeBits > sectorSizeBits) + return S_FALSE; + UInt32 numSectorsForFAT = Get32(p + 0x2C); // SAT + LongStreamMinSize = Get32(p + 0x38); + + UInt32 sectSize = (UInt32)1 << sectorSizeBits; + + CByteBuffer sect(sectSize); + + unsigned ssb2 = sectorSizeBits - 2; + UInt32 numSidsInSec = (UInt32)1 << ssb2; + UInt32 numFatItems = numSectorsForFAT << ssb2; + if ((numFatItems >> ssb2) != numSectorsForFAT) + return S_FALSE; + FatSize = numFatItems; + + { + UInt32 numSectorsForBat = Get32(p + 0x48); // master sector allocation table + const UInt32 kNumHeaderBatItems = 109; + UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2); + if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat) + return S_FALSE; + CObjArray<UInt32> bat(numBatItems); + UInt32 i; + for (i = 0; i < kNumHeaderBatItems; i++) + bat[i] = Get32(p + 0x4c + i * 4); + UInt32 sid = Get32(p + 0x44); + for (UInt32 s = 0; s < numSectorsForBat; s++) + { + RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i)); + i += numSidsInSec - 1; + sid = bat[i]; + } + numBatItems = i; + + Fat.Alloc(numFatItems); + UInt32 j = 0; + + for (i = 0; i < numFatItems; j++, i += numSidsInSec) + { + if (j >= numBatItems) + return S_FALSE; + RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], Fat + i)); + } + FatSize = numFatItems = i; + } + + UInt32 numMatItems; + { + UInt32 numSectorsForMat = Get32(p + 0x40); + numMatItems = (UInt32)numSectorsForMat << ssb2; + if ((numMatItems >> ssb2) != numSectorsForMat) + return S_FALSE; + Mat.Alloc(numMatItems); + UInt32 i; + UInt32 sid = Get32(p + 0x3C); // short-sector table SID + for (i = 0; i < numMatItems; i += numSidsInSec) + { + RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, Mat + i)); + if (sid >= numFatItems) + return S_FALSE; + sid = Fat[sid]; + } + if (sid != NFatID::kEndOfChain) + return S_FALSE; + } + + { + CByteBuffer used(numFatItems); + for (UInt32 i = 0; i < numFatItems; i++) + used[i] = 0; + UInt32 sid = Get32(p + 0x30); // directory stream SID + for (;;) + { + if (sid >= numFatItems) + return S_FALSE; + if (used[sid]) + return S_FALSE; + used[sid] = 1; + RINOK(ReadSector(inStream, sect, sectorSizeBits, sid)); + for (UInt32 i = 0; i < sectSize; i += 128) + { + CItem item; + item.Parse(sect + i, mode64bit); + Items.Add(item); + } + sid = Fat[sid]; + if (sid == NFatID::kEndOfChain) + break; + } + } + + const CItem &root = Items[0]; + + { + UInt32 numSectorsInMiniStream; + { + UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits; + if (numSatSects64 > NFatID::kMaxValue) + return S_FALSE; + numSectorsInMiniStream = (UInt32)numSatSects64; + } + NumSectorsInMiniStream = numSectorsInMiniStream; + MiniSids.Alloc(numSectorsInMiniStream); + { + UInt64 matSize64 = (root.Size + ((UInt64)1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits; + if (matSize64 > NFatID::kMaxValue) + return S_FALSE; + MatSize = (UInt32)matSize64; + if (numMatItems < MatSize) + return S_FALSE; + } + + UInt32 sid = root.Sid; + for (UInt32 i = 0; ; i++) + { + if (sid == NFatID::kEndOfChain) + { + if (i != numSectorsInMiniStream) + return S_FALSE; + break; + } + if (i >= numSectorsInMiniStream) + return S_FALSE; + MiniSids[i] = sid; + if (sid >= numFatItems) + return S_FALSE; + sid = Fat[sid]; + } + } + + RINOK(AddNode(-1, root.SonDid)); + + unsigned numCabs = 0; + FOR_VECTOR (i, Refs) + { + const CItem &item = Items[Refs[i].Did]; + if (item.IsDir() || numCabs > 1) + continue; + bool isMsiName; + UString msiName = ConvertName(item.Name, isMsiName); + if (isMsiName && msiName.Len() >= 4 && + MyStringCompareNoCase(msiName.RightPtr(4), L".cab") == 0) + { + numCabs++; + MainSubfile = i; + } + } + if (numCabs > 1) + MainSubfile = -1; + + { + FOR_VECTOR(t, Items) + { + Update_PhySize_WithItem(t); + } + } + { + FOR_VECTOR(t, Items) + { + const CItem &item = Items[t]; + + if (IsMsiName(item.Name)) + { + Type = k_Type_Msi; + if (memcmp(item.Name, kMspSequence, kMspSequence_Size) == 0) + { + Type = k_Type_Msp; + break; + } + continue; + } + if (AreEqualNames(item.Name, "WordDocument")) + { + Type = k_Type_Doc; + break; + } + if (AreEqualNames(item.Name, "PowerPoint Document")) + { + Type = k_Type_Ppt; + break; + } + if (AreEqualNames(item.Name, "Workbook")) + { + Type = k_Type_Xls; + break; + } + } + } + + return S_OK; +} + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CMyComPtr<IInStream> _stream; + CDatabase _db; +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidCTime, + kpidMTime +}; + +static const Byte kArcProps[] = +{ + kpidExtension, + kpidClusterSize, + kpidSectorSize +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidExtension: prop = kExtensions[_db.Type]; break; + case kpidPhySize: prop = _db.PhySize; break; + case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break; + case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break; + case kpidMainSubfile: if (_db.MainSubfile >= 0) prop = (UInt32)_db.MainSubfile; break; + case kpidIsNotArcType: if (_db.IsNotArcType()) prop = true; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CRef &ref = _db.Refs[index]; + const CItem &item = _db.Items[ref.Did]; + + switch (propID) + { + case kpidPath: prop = _db.GetItemPath(index); break; + case kpidIsDir: prop = item.IsDir(); break; + case kpidCTime: prop = item.CTime; break; + case kpidMTime: prop = item.MTime; break; + case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break; + case kpidSize: if (!item.IsDir()) prop = item.Size; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + try + { + if (_db.Open(inStream) != S_OK) + return S_FALSE; + _stream = inStream; + } + catch(...) { return S_FALSE; } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _db.Clear(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _db.Refs.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + UInt64 totalSize = 0; + for(i = 0; i < numItems; i++) + { + const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did]; + if (!item.IsDir()) + totalSize += item.Size; + } + RINOK(extractCallback->SetTotal(totalSize)); + + UInt64 totalPackSize; + totalSize = totalPackSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + Int32 index = allFilesMode ? i : indices[i]; + const CItem &item = _db.Items[_db.Refs[index].Did]; + + CMyComPtr<ISequentialOutStream> outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + + if (item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + + totalPackSize += _db.GetItemPackSize(item.Size); + totalSize += item.Size; + + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + Int32 res = NExtract::NOperationResult::kDataError; + CMyComPtr<ISequentialInStream> inStream; + HRESULT hres = GetStream(index, &inStream); + if (hres == S_FALSE) + res = NExtract::NOperationResult::kDataError; + else if (hres == E_NOTIMPL) + res = NExtract::NOperationResult::kUnsupportedMethod; + else + { + RINOK(hres); + if (inStream) + { + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize == item.Size) + res = NExtract::NOperationResult::kOK; + } + } + outStream.Release(); + RINOK(extractCallback->SetOperationResult(res)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _db.Refs.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = 0; + UInt32 itemIndex = _db.Refs[index].Did; + const CItem &item = _db.Items[itemIndex]; + CClusterInStream *streamSpec = new CClusterInStream; + CMyComPtr<ISequentialInStream> streamTemp = streamSpec; + streamSpec->Stream = _stream; + streamSpec->StartOffset = 0; + + bool isLargeStream = (itemIndex == 0 || _db.IsLargeStream(item.Size)); + int bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits; + streamSpec->BlockSizeLog = bsLog; + streamSpec->Size = item.Size; + + UInt32 clusterSize = (UInt32)1 << bsLog; + UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog; + if (numClusters64 >= ((UInt32)1 << 31)) + return E_NOTIMPL; + streamSpec->Vector.ClearAndReserve((unsigned)numClusters64); + UInt32 sid = item.Sid; + UInt64 size = item.Size; + + if (size != 0) + { + for (;; size -= clusterSize) + { + if (isLargeStream) + { + if (sid >= _db.FatSize) + return S_FALSE; + streamSpec->Vector.AddInReserved(sid + 1); + sid = _db.Fat[sid]; + } + else + { + UInt64 val = 0; + if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32) + return S_FALSE; + streamSpec->Vector.AddInReserved((UInt32)val); + sid = _db.Mat[sid]; + } + if (size <= clusterSize) + break; + } + } + if (sid != NFatID::kEndOfChain) + return S_FALSE; + RINOK(streamSpec->InitAndSeek()); + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + +IMP_CreateArcIn + +static CArcInfo g_ArcInfo = + { "Compound", "msi msp doc xls ppt", 0, 0xE5, + kSignatureSize, SIGNATURE, + 0, + 0, + CreateArc }; + +REGISTER_ARC(Com) + +}} diff --git a/CPP/7zip/Archive/Common/CoderMixer.cpp b/CPP/7zip/Archive/Common/CoderMixer.cpp index a19f0457..a19f0457 100755..100644 --- a/CPP/7zip/Archive/Common/CoderMixer.cpp +++ b/CPP/7zip/Archive/Common/CoderMixer.cpp diff --git a/CPP/7zip/Archive/Common/CoderMixer.h b/CPP/7zip/Archive/Common/CoderMixer.h index 6379dd80..6379dd80 100755..100644 --- a/CPP/7zip/Archive/Common/CoderMixer.h +++ b/CPP/7zip/Archive/Common/CoderMixer.h diff --git a/CPP/7zip/Archive/Common/CoderMixer2.cpp b/CPP/7zip/Archive/Common/CoderMixer2.cpp index 0b06a489..13019d1f 100755..100644 --- a/CPP/7zip/Archive/Common/CoderMixer2.cpp +++ b/CPP/7zip/Archive/Common/CoderMixer2.cpp @@ -11,16 +11,23 @@ CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo): { srcBindInfo.GetNumStreams(NumSrcInStreams, _numSrcOutStreams); - UInt32 j; + UInt32 j; + _srcInToDestOutMap.ClearAndSetSize(NumSrcInStreams); + DestOutToSrcInMap.ClearAndSetSize(NumSrcInStreams); + for (j = 0; j < NumSrcInStreams; j++) { - _srcInToDestOutMap.Add(0); - DestOutToSrcInMap.Add(0); + _srcInToDestOutMap[j] = 0; + DestOutToSrcInMap[j] = 0; } + + _srcOutToDestInMap.ClearAndSetSize(_numSrcOutStreams); + _destInToSrcOutMap.ClearAndSetSize(_numSrcOutStreams); + for (j = 0; j < _numSrcOutStreams; j++) { - _srcOutToDestInMap.Add(0); - _destInToSrcOutMap.Add(0); + _srcOutToDestInMap[j] = 0; + _destInToSrcOutMap[j] = 0; } UInt32 destInOffset = 0; @@ -53,66 +60,57 @@ CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo): void CBindReverseConverter::CreateReverseBindInfo(CBindInfo &destBindInfo) { - destBindInfo.Coders.Clear(); - destBindInfo.BindPairs.Clear(); - destBindInfo.InStreams.Clear(); - destBindInfo.OutStreams.Clear(); + destBindInfo.Coders.ClearAndReserve(_srcBindInfo.Coders.Size()); + destBindInfo.BindPairs.ClearAndReserve(_srcBindInfo.BindPairs.Size()); + destBindInfo.InStreams.ClearAndReserve(_srcBindInfo.OutStreams.Size()); + destBindInfo.OutStreams.ClearAndReserve(_srcBindInfo.InStreams.Size()); - int i; - for (i = _srcBindInfo.Coders.Size() - 1; i >= 0; i--) + unsigned i; + for (i = _srcBindInfo.Coders.Size(); i != 0;) { + i--; const CCoderStreamsInfo &srcCoderInfo = _srcBindInfo.Coders[i]; CCoderStreamsInfo destCoderInfo; destCoderInfo.NumInStreams = srcCoderInfo.NumOutStreams; destCoderInfo.NumOutStreams = srcCoderInfo.NumInStreams; - destBindInfo.Coders.Add(destCoderInfo); + destBindInfo.Coders.AddInReserved(destCoderInfo); } - for (i = _srcBindInfo.BindPairs.Size() - 1; i >= 0; i--) + for (i = _srcBindInfo.BindPairs.Size(); i != 0;) { + i--; const CBindPair &srcBindPair = _srcBindInfo.BindPairs[i]; CBindPair destBindPair; destBindPair.InIndex = _srcOutToDestInMap[srcBindPair.OutIndex]; destBindPair.OutIndex = _srcInToDestOutMap[srcBindPair.InIndex]; - destBindInfo.BindPairs.Add(destBindPair); + destBindInfo.BindPairs.AddInReserved(destBindPair); } for (i = 0; i < _srcBindInfo.InStreams.Size(); i++) - destBindInfo.OutStreams.Add(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]); + destBindInfo.OutStreams.AddInReserved(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]); for (i = 0; i < _srcBindInfo.OutStreams.Size(); i++) - destBindInfo.InStreams.Add(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]); -} - -CCoderInfo2::CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams): - NumInStreams(numInStreams), - NumOutStreams(numOutStreams) -{ - InSizes.Reserve(NumInStreams); - InSizePointers.Reserve(NumInStreams); - OutSizes.Reserve(NumOutStreams); - OutSizePointers.Reserve(NumOutStreams); + destBindInfo.InStreams.AddInReserved(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]); } -static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes, +void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes, CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems) { - sizes.Clear(); - sizePointers.Clear(); + sizes.ClearAndSetSize(numItems); + sizePointers.ClearAndSetSize(numItems); for(UInt32 i = 0; i < numItems; i++) { - if (srcSizes == 0 || srcSizes[i] == NULL) + if (!srcSizes || !srcSizes[i]) { - sizes.Add(0); - sizePointers.Add(NULL); + sizes[i] = 0; + sizePointers[i] = NULL; } else { - sizes.Add(*srcSizes[i]); - sizePointers.Add(&sizes.Back()); + sizes[i] = *(srcSizes[i]); + sizePointers[i] = &sizes[i]; } } } -void CCoderInfo2::SetCoderInfo(const UInt64 **inSizes, - const UInt64 **outSizes) +void CCoderInfo2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes) { SetSizes(inSizes, InSizes, InSizePointers, NumInStreams); SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams); diff --git a/CPP/7zip/Archive/Common/CoderMixer2.h b/CPP/7zip/Archive/Common/CoderMixer2.h index a03722d6..50e7077a 100755..100644 --- a/CPP/7zip/Archive/Common/CoderMixer2.h +++ b/CPP/7zip/Archive/Common/CoderMixer2.h @@ -3,9 +3,9 @@ #ifndef __CODER_MIXER2_H #define __CODER_MIXER2_H -#include "../../../Common/MyVector.h" -#include "../../../Common/Types.h" #include "../../../Common/MyCom.h" +#include "../../../Common/MyVector.h" + #include "../../ICoder.h" namespace NCoderMixer { @@ -52,7 +52,7 @@ struct CBindInfo { numInStreams = 0; numOutStreams = 0; - for (int i = 0; i < Coders.Size(); i++) + FOR_VECTOR (i, Coders) { const CCoderStreamsInfo &coderStreamsInfo = Coders[i]; numInStreams += coderStreamsInfo.NumInStreams; @@ -62,14 +62,14 @@ struct CBindInfo int FindBinderForInStream(UInt32 inStream) const { - for (int i = 0; i < BindPairs.Size(); i++) + FOR_VECTOR (i, BindPairs) if (BindPairs[i].InIndex == inStream) return i; return -1; } int FindBinderForOutStream(UInt32 outStream) const { - for (int i = 0; i < BindPairs.Size(); i++) + FOR_VECTOR (i, BindPairs) if (BindPairs[i].OutIndex == outStream) return i; return -1; @@ -139,6 +139,9 @@ public: void CreateReverseBindInfo(NCoderMixer::CBindInfo &destBindInfo); }; +void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes, + CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems); + struct CCoderInfo2 { CMyComPtr<ICompressCoder> Coder; @@ -151,7 +154,9 @@ struct CCoderInfo2 CRecordVector<const UInt64 *> InSizePointers; CRecordVector<const UInt64 *> OutSizePointers; - CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams); + CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams): + NumInStreams(numInStreams), + NumOutStreams(numOutStreams) {} void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes); HRESULT QueryInterface(REFGUID iid, void** pp) const @@ -170,5 +175,5 @@ public: }; } -#endif +#endif diff --git a/CPP/7zip/Archive/Common/CoderMixer2MT.cpp b/CPP/7zip/Archive/Common/CoderMixer2MT.cpp index 87686e85..5288fbc1 100755..100644 --- a/CPP/7zip/Archive/Common/CoderMixer2MT.cpp +++ b/CPP/7zip/Archive/Common/CoderMixer2MT.cpp @@ -9,30 +9,28 @@ namespace NCoderMixer { CCoder2::CCoder2(UInt32 numInStreams, UInt32 numOutStreams): CCoderInfo2(numInStreams, numOutStreams) { - InStreams.Reserve(NumInStreams); - InStreamPointers.Reserve(NumInStreams); - OutStreams.Reserve(NumOutStreams); - OutStreamPointers.Reserve(NumOutStreams); + InStreams.ClearAndReserve(NumInStreams); + OutStreams.ClearAndReserve(NumOutStreams); } void CCoder2::Execute() { Code(NULL); } void CCoder2::Code(ICompressProgressInfo *progress) { - InStreamPointers.Clear(); - OutStreamPointers.Clear(); + InStreamPointers.ClearAndReserve(NumInStreams); + OutStreamPointers.ClearAndReserve(NumOutStreams); UInt32 i; for (i = 0; i < NumInStreams; i++) { - if (InSizePointers[i] != NULL) + if (InSizePointers[i]) InSizePointers[i] = &InSizes[i]; - InStreamPointers.Add((ISequentialInStream *)InStreams[i]); + InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]); } for (i = 0; i < NumOutStreams; i++) { - if (OutSizePointers[i] != NULL) + if (OutSizePointers[i]) OutSizePointers[i] = &OutSizes[i]; - OutStreamPointers.Add((ISequentialOutStream *)OutStreams[i]); + OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]); } if (Coder) Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0], @@ -41,7 +39,7 @@ void CCoder2::Code(ICompressProgressInfo *progress) Result = Coder2->Code(&InStreamPointers.Front(), &InSizePointers.Front(), NumInStreams, &OutStreamPointers.Front(), &OutSizePointers.Front(), NumOutStreams, progress); { - int i; + unsigned i; for (i = 0; i < InStreams.Size(); i++) InStreams[i].Release(); for (i = 0; i < OutStreams.Size(); i++) @@ -49,32 +47,13 @@ void CCoder2::Code(ICompressProgressInfo *progress) } } -static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes, - CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems) -{ - sizes.Clear(); - sizePointers.Clear(); - for (UInt32 i = 0; i < numItems; i++) - { - if (srcSizes == 0 || srcSizes[i] == NULL) - { - sizes.Add(0); - sizePointers.Add(NULL); - } - else - { - sizes.Add(*srcSizes[i]); - sizePointers.Add(&sizes.Back()); - } - } -} - - +/* void CCoder2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes) { SetSizes(inSizes, InSizes, InSizePointers, NumInStreams); SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams); } +*/ ////////////////////////////////////// // CCoderMixer2MT @@ -83,10 +62,9 @@ HRESULT CCoderMixer2MT::SetBindInfo(const CBindInfo &bindInfo) { _bindInfo = bindInfo; _streamBinders.Clear(); - for (int i = 0; i < _bindInfo.BindPairs.Size(); i++) + FOR_VECTOR (i, _bindInfo.BindPairs) { - _streamBinders.Add(CStreamBinder()); - RINOK(_streamBinders.Back().CreateEvents()); + RINOK(_streamBinders.AddNew().CreateEvents()); } return S_OK; } @@ -113,7 +91,7 @@ void CCoderMixer2MT::AddCoder2(ICompressCoder2 *coder) void CCoderMixer2MT::ReInit() { - for (int i = 0; i < _streamBinders.Size(); i++) + FOR_VECTOR (i, _streamBinders) _streamBinders[i].ReInit(); } @@ -124,7 +102,7 @@ HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStre if (_coders.Size() != _bindInfo.Coders.Size()) throw 0; */ - int i; + unsigned i; for (i = 0; i < _coders.Size(); i++) { CCoder2 &coderInfo = _coders[i]; @@ -179,7 +157,7 @@ HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStre HRESULT CCoderMixer2MT::ReturnIfError(HRESULT code) { - for (int i = 0; i < _coders.Size(); i++) + FOR_VECTOR (i, _coders) if (_coders[i].Result == code) return code; return S_OK; @@ -199,7 +177,7 @@ STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams, Init(inStreams, outStreams); - int i; + unsigned i; for (i = 0; i < _coders.Size(); i++) if (i != _progressCoderIndex) { diff --git a/CPP/7zip/Archive/Common/CoderMixer2MT.h b/CPP/7zip/Archive/Common/CoderMixer2MT.h index 81bb3f0b..ba475cec 100755..100644 --- a/CPP/7zip/Archive/Common/CoderMixer2MT.h +++ b/CPP/7zip/Archive/Common/CoderMixer2MT.h @@ -12,15 +12,17 @@ namespace NCoderMixer { struct CCoder2: public CCoderInfo2, public CVirtThread { + CRecordVector<ISequentialInStream*> InStreamPointers; + CRecordVector<ISequentialOutStream*> OutStreamPointers; + +public: HRESULT Result; CObjectVector< CMyComPtr<ISequentialInStream> > InStreams; CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams; - CRecordVector<ISequentialInStream*> InStreamPointers; - CRecordVector<ISequentialOutStream*> OutStreamPointers; CCoder2(UInt32 numInStreams, UInt32 numOutStreams); ~CCoder2() { CVirtThread::WaitThreadFinish(); } - void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes); + // void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes); virtual void Execute(); void Code(ICompressProgressInfo *progress); }; @@ -48,7 +50,7 @@ class CCoderMixer2MT: { CBindInfo _bindInfo; CObjectVector<CStreamBinder> _streamBinders; - int _progressCoderIndex; + unsigned _progressCoderIndex; void AddCoderCommon(); HRESULT Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams); @@ -68,7 +70,7 @@ public: HRESULT SetBindInfo(const CBindInfo &bindInfo); void AddCoder(ICompressCoder *coder); void AddCoder2(ICompressCoder2 *coder); - void SetProgressCoderIndex(int coderIndex) { _progressCoderIndex = coderIndex; } + void SetProgressCoderIndex(unsigned coderIndex) { _progressCoderIndex = coderIndex; } void ReInit(); void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) diff --git a/CPP/7zip/Archive/Common/CoderMixer2ST.cpp b/CPP/7zip/Archive/Common/CoderMixer2ST.cpp index a21ca0c0..a94ba115 100755..100644 --- a/CPP/7zip/Archive/Common/CoderMixer2ST.cpp +++ b/CPP/7zip/Archive/Common/CoderMixer2ST.cpp @@ -47,7 +47,7 @@ HRESULT CCoderMixer2ST::GetInStream( { seqInStream = inStreams[i]; *inStreamRes = seqInStream.Detach(); - return S_OK; + return S_OK; } int binderIndex = _bindInfo.FindBinderForInStream(streamIndex); if (binderIndex < 0) @@ -96,7 +96,7 @@ HRESULT CCoderMixer2ST::GetOutStream( { seqOutStream = outStreams[i]; *outStreamRes = seqOutStream.Detach(); - return S_OK; + return S_OK; } int binderIndex = _bindInfo.FindBinderForOutStream(streamIndex); if (binderIndex < 0) diff --git a/CPP/7zip/Archive/Common/CoderMixer2ST.h b/CPP/7zip/Archive/Common/CoderMixer2ST.h index d35655ba..d35655ba 100755..100644 --- a/CPP/7zip/Archive/Common/CoderMixer2ST.h +++ b/CPP/7zip/Archive/Common/CoderMixer2ST.h diff --git a/CPP/7zip/Archive/Common/CoderMixerMT.cpp b/CPP/7zip/Archive/Common/CoderMixerMT.cpp index 96ea76a3..96ea76a3 100755..100644 --- a/CPP/7zip/Archive/Common/CoderMixerMT.cpp +++ b/CPP/7zip/Archive/Common/CoderMixerMT.cpp diff --git a/CPP/7zip/Archive/Common/CoderMixerMT.h b/CPP/7zip/Archive/Common/CoderMixerMT.h index 9491a965..9491a965 100755..100644 --- a/CPP/7zip/Archive/Common/CoderMixerMT.h +++ b/CPP/7zip/Archive/Common/CoderMixerMT.h diff --git a/CPP/7zip/Archive/Common/CrossThreadProgress.cpp b/CPP/7zip/Archive/Common/CrossThreadProgress.cpp index a974b54c..a974b54c 100755..100644 --- a/CPP/7zip/Archive/Common/CrossThreadProgress.cpp +++ b/CPP/7zip/Archive/Common/CrossThreadProgress.cpp diff --git a/CPP/7zip/Archive/Common/CrossThreadProgress.h b/CPP/7zip/Archive/Common/CrossThreadProgress.h index 7e0b1053..7e0b1053 100755..100644 --- a/CPP/7zip/Archive/Common/CrossThreadProgress.h +++ b/CPP/7zip/Archive/Common/CrossThreadProgress.h diff --git a/CPP/7zip/Archive/Common/DummyOutStream.cpp b/CPP/7zip/Archive/Common/DummyOutStream.cpp index 54bcfec1..7c4f5487 100755..100644 --- a/CPP/7zip/Archive/Common/DummyOutStream.cpp +++ b/CPP/7zip/Archive/Common/DummyOutStream.cpp @@ -4,19 +4,14 @@ #include "DummyOutStream.h" -STDMETHODIMP CDummyOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +STDMETHODIMP CDummyOutStream::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); + UInt32 realProcessedSize = size; + HRESULT res = S_OK; + if (_stream) + res = _stream->Write(data, size, &realProcessedSize); _size += realProcessedSize; - if(processedSize != NULL) + if (processedSize) *processedSize = realProcessedSize; - return result; + return res; } diff --git a/CPP/7zip/Archive/Common/DummyOutStream.h b/CPP/7zip/Archive/Common/DummyOutStream.h index 13d5b62c..b5a51fc0 100755..100644 --- a/CPP/7zip/Archive/Common/DummyOutStream.h +++ b/CPP/7zip/Archive/Common/DummyOutStream.h @@ -1,10 +1,11 @@ // DummyOutStream.h -#ifndef __DUMMYOUTSTREAM_H -#define __DUMMYOUTSTREAM_H +#ifndef __DUMMY_OUT_STREAM_H +#define __DUMMY_OUT_STREAM_H + +#include "../../../Common/MyCom.h" #include "../../IStream.h" -#include "Common/MyCom.h" class CDummyOutStream: public ISequentialOutStream, diff --git a/CPP/7zip/Archive/Common/FindSignature.cpp b/CPP/7zip/Archive/Common/FindSignature.cpp index 15aa6cea..e9a0f032 100755..100644 --- a/CPP/7zip/Archive/Common/FindSignature.cpp +++ b/CPP/7zip/Archive/Common/FindSignature.cpp @@ -2,27 +2,25 @@ #include "StdAfx.h" -#include "Common/Buffer.h" - -#include "FindSignature.h" +#include "../../../Common/MyBuffer.h" #include "../../Common/StreamUtils.h" +#include "FindSignature.h" + HRESULT FindSignatureInStream(ISequentialInStream *stream, const Byte *signature, unsigned signatureSize, const UInt64 *limit, UInt64 &resPos) { resPos = 0; - CByteBuffer byteBuffer2; - byteBuffer2.SetCapacity(signatureSize); + CByteBuffer byteBuffer2(signatureSize); RINOK(ReadStream_FALSE(stream, byteBuffer2, signatureSize)); if (memcmp(byteBuffer2, signature, signatureSize) == 0) return S_OK; const UInt32 kBufferSize = (1 << 16); - CByteBuffer byteBuffer; - byteBuffer.SetCapacity(kBufferSize); + CByteBuffer byteBuffer(kBufferSize); Byte *buffer = byteBuffer; UInt32 numPrevBytes = signatureSize - 1; memcpy(buffer, (const Byte *)byteBuffer2 + 1, numPrevBytes); diff --git a/CPP/7zip/Archive/Common/FindSignature.h b/CPP/7zip/Archive/Common/FindSignature.h index e15af573..e15af573 100755..100644 --- a/CPP/7zip/Archive/Common/FindSignature.h +++ b/CPP/7zip/Archive/Common/FindSignature.h diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp index 7e6f4602..18ad5580 100755..100644 --- a/CPP/7zip/Archive/Common/HandlerOut.cpp +++ b/CPP/7zip/Archive/Common/HandlerOut.cpp @@ -27,7 +27,7 @@ void CMultiMethodProps::SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo ) { UInt32 level = _level; - if (level != (UInt32)(UInt32)-1) + if (level != (UInt32)(Int32)-1) SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level); #ifndef _7ZIP_ST SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); @@ -40,7 +40,7 @@ void CMultiMethodProps::Init() _numProcessors = _numThreads = NSystem::GetNumberOfProcessors(); #endif - _level = (UInt32)(UInt32)-1; + _level = (UInt32)(Int32)-1; _autoFilter = true; _crcSize = 4; _filterMethod.Clear(); @@ -50,18 +50,18 @@ void CMultiMethodProps::Init() HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) { UString name = nameSpec; - name.MakeUpper(); + name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; - if (name[0] == 'X') + if (name[0] == 'x') { name.Delete(0); _level = 9; return ParsePropToUInt32(name, value, _level); } - if (name == L"CRC") + if (name == L"crc") { name.Delete(0, 3); _crcSize = 4; @@ -70,17 +70,17 @@ HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIAN UInt32 number; int index = ParseStringToUInt32(name, number); - UString realName = name.Mid(index); + UString realName = name.Ptr(index); if (index == 0) { - if (name.Left(2).CompareNoCase(L"MT") == 0) + if (name.IsPrefixedBy(L"mt")) { #ifndef _7ZIP_ST - RINOK(ParseMtProp(name.Mid(2), value, _numProcessors, _numThreads)); + RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads)); #endif return S_OK; } - if (name.CompareNoCase(L"F") == 0) + if (name.IsEqualTo("f")) { HRESULT res = PROPVARIANT_to_bool(value, _autoFilter); if (res == S_OK) @@ -105,35 +105,35 @@ void CSingleMethodProps::Init() _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors(); AddNumThreadsProp(_numThreads); #endif - _level = (UInt32)(UInt32)-1; + _level = (UInt32)(Int32)-1; } -HRESULT CSingleMethodProps::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) +HRESULT CSingleMethodProps::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { Init(); - for (int i = 0; i < numProps; i++) + for (UInt32 i = 0; i < numProps; i++) { UString name = names[i]; - name.MakeUpper(); + name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &value = values[i]; - if (name[0] == L'X') + if (name[0] == L'x') { UInt32 a = 9; - RINOK(ParsePropToUInt32(name.Mid(1), value, a)); + RINOK(ParsePropToUInt32(name.Ptr(1), value, a)); _level = a; AddLevelProp(a); } - else if (name.Left(2).CompareNoCase(L"MT") == 0) + else if (name.IsPrefixedBy(L"mt")) { #ifndef _7ZIP_ST - RINOK(ParseMtProp(name.Mid(2), value, _numProcessors, _numThreads)); + RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads)); AddNumThreadsProp(_numThreads); #endif } else - return ParseParamsFromPROPVARIANT(name, value); + return ParseMethodFromPROPVARIANT(names[i], value); } return S_OK; } diff --git a/CPP/7zip/Archive/Common/HandlerOut.h b/CPP/7zip/Archive/Common/HandlerOut.h index d3c9a237..40a4a698 100755..100644 --- a/CPP/7zip/Archive/Common/HandlerOut.h +++ b/CPP/7zip/Archive/Common/HandlerOut.h @@ -27,16 +27,16 @@ public: #endif ); - int GetNumEmptyMethods() const + unsigned GetNumEmptyMethods() const { - int i; + unsigned i; for (i = 0; i < _methods.Size(); i++) if (!_methods[i].IsEmpty()) break; return i; } - int GetLevel() const { return _level == (UInt32)(UInt32)-1 ? 5 : (int)_level; } + int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } void Init(); @@ -44,20 +44,20 @@ public: HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); }; -class CSingleMethodProps: public CMethodProps +class CSingleMethodProps: public COneMethodInfo { UInt32 _level; - void Init(); public: #ifndef _7ZIP_ST UInt32 _numThreads; UInt32 _numProcessors; #endif + void Init(); CSingleMethodProps() { Init(); } - int GetLevel() const { return _level == (UInt32)(UInt32)-1 ? 5 : (int)_level; } - HRESULT SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps); + int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } + HRESULT SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); }; } diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp index 569a56f3..3f4dd3b8 100755..100644 --- a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp +++ b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp @@ -6,29 +6,33 @@ STDMETHODIMP CSequentialInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize) { - UInt32 realProcessedSize; - HRESULT result = _stream->Read(data, size, &realProcessedSize); - _size += realProcessedSize; - if (size > 0 && realProcessedSize == 0) + UInt32 realProcessed = 0; + HRESULT result = S_OK; + if (_stream) + _stream->Read(data, size, &realProcessed); + _size += realProcessed; + if (size > 0 && realProcessed == 0) _wasFinished = true; - _crc = CrcUpdate(_crc, data, realProcessedSize); - if(processedSize != NULL) - *processedSize = realProcessedSize; + _crc = CrcUpdate(_crc, data, realProcessed); + if (processedSize) + *processedSize = realProcessed; return result; } STDMETHODIMP CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize) { - UInt32 realProcessedSize; - HRESULT result = _stream->Read(data, size, &realProcessedSize); + UInt32 realProcessed = 0; + HRESULT result = S_OK; + if (_stream) + result = _stream->Read(data, size, &realProcessed); + _size += realProcessed; /* - if (size > 0 && realProcessedSize == 0) + if (size > 0 && realProcessed == 0) _wasFinished = true; */ - _size += realProcessedSize; - _crc = CrcUpdate(_crc, data, realProcessedSize); - if(processedSize != NULL) - *processedSize = realProcessedSize; + _crc = CrcUpdate(_crc, data, realProcessed); + if (processedSize) + *processedSize = realProcessed; return result; } diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.h b/CPP/7zip/Archive/Common/InStreamWithCRC.h index 31b761e4..31b761e4 100755..100644 --- a/CPP/7zip/Archive/Common/InStreamWithCRC.h +++ b/CPP/7zip/Archive/Common/InStreamWithCRC.h diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/CPP/7zip/Archive/Common/ItemNameUtils.cpp index cc476fad..7cd3037b 100755..100644 --- a/CPP/7zip/Archive/Common/ItemNameUtils.cpp +++ b/CPP/7zip/Archive/Common/ItemNameUtils.cpp @@ -2,8 +2,6 @@ #include "StdAfx.h" -#include "../../../../C/Types.h" - #include "ItemNameUtils.h" namespace NArchive { @@ -12,6 +10,21 @@ namespace NItemName { static const wchar_t kOSDirDelimiter = WCHAR_PATH_SEPARATOR; static const wchar_t kDirDelimiter = L'/'; +void ReplaceToOsPathSeparator(wchar_t *s) +{ + #ifdef _WIN32 + for (;;) + { + wchar_t c = *s; + if (c == 0) + break; + if (c == kDirDelimiter) + *s = kOSDirDelimiter; + s++; + } + #endif +} + UString MakeLegalName(const UString &name) { UString zipName = name; @@ -36,15 +49,29 @@ UString GetOSName2(const UString &name) return newName; } -bool HasTailSlash(const AString &name, UINT codePage) +void ConvertToOSName2(UString &name) +{ + if (!name.IsEmpty()) + { + name.Replace(kDirDelimiter, kOSDirDelimiter); + if (name.Back() == kOSDirDelimiter) + name.DeleteBack(); + } +} + +bool HasTailSlash(const AString &name, UINT + #if defined(_WIN32) && !defined(UNDER_CE) + codePage + #endif + ) { if (name.IsEmpty()) return false; LPCSTR prev = #if defined(_WIN32) && !defined(UNDER_CE) - CharPrevExA((WORD)codePage, name, &name[name.Length()], 0); + CharPrevExA((WORD)codePage, name, &name[name.Len()], 0); #else - (LPCSTR)(name) + (name.Length() - 1); + (LPCSTR)(name) + (name.Len() - 1); #endif return (*prev == '/'); } diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.h b/CPP/7zip/Archive/Common/ItemNameUtils.h index 5eafacb1..d0dc76a4 100755..100644 --- a/CPP/7zip/Archive/Common/ItemNameUtils.h +++ b/CPP/7zip/Archive/Common/ItemNameUtils.h @@ -1,16 +1,19 @@ // Archive/Common/ItemNameUtils.h -#ifndef __ARCHIVE_ITEMNAMEUTILS_H -#define __ARCHIVE_ITEMNAMEUTILS_H +#ifndef __ARCHIVE_ITEM_NAME_UTILS_H +#define __ARCHIVE_ITEM_NAME_UTILS_H #include "../../../Common/MyString.h" namespace NArchive { namespace NItemName { + void ReplaceToOsPathSeparator(wchar_t *s); + UString MakeLegalName(const UString &name); UString GetOSName(const UString &name); UString GetOSName2(const UString &name); + void ConvertToOSName2(UString &name); bool HasTailSlash(const AString &name, UINT codePage); #ifdef _WIN32 diff --git a/CPP/7zip/Archive/Common/MultiStream.cpp b/CPP/7zip/Archive/Common/MultiStream.cpp index 04d11caf..5bf0bef9 100755..100644 --- a/CPP/7zip/Archive/Common/MultiStream.cpp +++ b/CPP/7zip/Archive/Common/MultiStream.cpp @@ -11,10 +11,10 @@ STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize) if (size == 0) return S_OK; if (_pos >= _totalLength) - return (_pos == _totalLength) ? S_OK : E_FAIL; + return S_OK; { - int left = 0, mid = _streamIndex, right = Streams.Size(); + unsigned left = 0, mid = _streamIndex, right = Streams.Size(); for (;;) { CSubStreamInfo &m = Streams[mid]; @@ -51,15 +51,18 @@ STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize) STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { - switch(seekOrigin) + switch (seekOrigin) { - case STREAM_SEEK_SET: _pos = offset; break; - case STREAM_SEEK_CUR: _pos = _pos + offset; break; - case STREAM_SEEK_END: _pos = _totalLength + offset; break; + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _pos; break; + case STREAM_SEEK_END: offset += _totalLength; break; default: return STG_E_INVALIDFUNCTION; } - if (newPosition != 0) - *newPosition = _pos; + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _pos = offset; + if (newPosition) + *newPosition = offset; return S_OK; } @@ -69,7 +72,7 @@ class COutVolumeStream: public ISequentialOutStream, public CMyUnknownImp { - int _volIndex; + unsigned _volIndex; UInt64 _volSize; UInt64 _curPos; CMyComPtr<ISequentialOutStream> _volumeStream; @@ -169,22 +172,20 @@ STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *proce STDMETHODIMP COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { - if(seekOrigin >= 3) - return STG_E_INVALIDFUNCTION; - switch(seekOrigin) + switch (seekOrigin) { - case STREAM_SEEK_SET: - _absPos = offset; - break; - case STREAM_SEEK_CUR: - _absPos += offset; - break; - case STREAM_SEEK_END: - _absPos = _length + offset; - break; + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _absPos; break; + case STREAM_SEEK_END: offset += _length; break; + default: return STG_E_INVALIDFUNCTION; } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _absPos = offset; _offsetPos = _absPos; _streamIndex = 0; + if (newPosition) + *newPosition = offset; return S_OK; } */ diff --git a/CPP/7zip/Archive/Common/MultiStream.h b/CPP/7zip/Archive/Common/MultiStream.h index 3fceb7cc..2a1a4a43 100755..100644 --- a/CPP/7zip/Archive/Common/MultiStream.h +++ b/CPP/7zip/Archive/Common/MultiStream.h @@ -14,7 +14,7 @@ class CMultiStream: { UInt64 _pos; UInt64 _totalLength; - int _streamIndex; + unsigned _streamIndex; public: struct CSubStreamInfo { @@ -28,7 +28,7 @@ public: HRESULT Init() { UInt64 total = 0; - for (int i = 0; i < Streams.Size(); i++) + FOR_VECTOR (i, Streams) { CSubStreamInfo &s = Streams[i]; s.GlobalOffset = total; @@ -52,7 +52,7 @@ class COutMultiStream: public IOutStream, public CMyUnknownImp { - int _streamIndex; // required stream + unsigned _streamIndex; // required stream UInt64 _offsetPos; // offset from start of _streamIndex index UInt64 _absPos; UInt64 _length; diff --git a/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp b/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp index f955c225..f955c225 100755..100644 --- a/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp +++ b/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp diff --git a/CPP/7zip/Archive/Common/OutStreamWithCRC.h b/CPP/7zip/Archive/Common/OutStreamWithCRC.h index 115b442a..09b899bb 100755..100644 --- a/CPP/7zip/Archive/Common/OutStreamWithCRC.h +++ b/CPP/7zip/Archive/Common/OutStreamWithCRC.h @@ -28,6 +28,7 @@ public: _calculate = calculate; _crc = CRC_INIT_VAL; } + void EnableCalc(bool calculate) { _calculate = calculate; } void InitCRC() { _crc = CRC_INIT_VAL; } UInt64 GetSize() const { return _size; } UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp index 0526c1b1..0526c1b1 100755..100644 --- a/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp +++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.h b/CPP/7zip/Archive/Common/OutStreamWithSha1.h index 3bbfbbe1..3bbfbbe1 100755..100644 --- a/CPP/7zip/Archive/Common/OutStreamWithSha1.h +++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.h diff --git a/CPP/7zip/Archive/Common/ParseProperties.cpp b/CPP/7zip/Archive/Common/ParseProperties.cpp index 63e4f3ef..63e4f3ef 100755..100644 --- a/CPP/7zip/Archive/Common/ParseProperties.cpp +++ b/CPP/7zip/Archive/Common/ParseProperties.cpp diff --git a/CPP/7zip/Archive/Common/ParseProperties.h b/CPP/7zip/Archive/Common/ParseProperties.h index 1038a8c0..1038a8c0 100755..100644 --- a/CPP/7zip/Archive/Common/ParseProperties.h +++ b/CPP/7zip/Archive/Common/ParseProperties.h diff --git a/CPP/7zip/Archive/Common/StdAfx.h b/CPP/7zip/Archive/Common/StdAfx.h index 2e4be10b..2854ff3e 100755..100644 --- a/CPP/7zip/Archive/Common/StdAfx.h +++ b/CPP/7zip/Archive/Common/StdAfx.h @@ -3,7 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" -#include "../../../Common/NewHandler.h" +#include "../../../Common/Common.h" #endif diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp index 0f32ef66..9c1271c4 100755..100644 --- a/CPP/7zip/Archive/CpioHandler.cpp +++ b/CPP/7zip/Archive/CpioHandler.cpp @@ -2,12 +2,15 @@ #include "StdAfx.h" -#include "Common/ComTry.h" -#include "Common/StringConvert.h" -#include "Common/StringToInt.h" +#include "../../../C/CpuArch.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../Common/ComTry.h" +#include "../../Common/StringConvert.h" +#include "../../Common/StringToInt.h" +#include "../../Common/UTFConvert.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -18,24 +21,30 @@ #include "Common/ItemNameUtils.h" +using namespace NWindows; + namespace NArchive { namespace NCpio { -namespace NFileHeader -{ - namespace NMagic - { - const char *kMagic1 = "070701"; - const char *kMagic2 = "070702"; - const char *kMagic3 = "070707"; - const char *kEndName = "TRAILER!!!"; +static const Byte kMagicBin0 = 0xC7; +static const Byte kMagicBin1 = 0x71; - const Byte kMagicForRecord2[2] = { 0xC7, 0x71 }; - } +// #define MAGIC_ASCII { '0', '7', '0', '7', '0' } + +static const Byte kMagicHex = '1'; // New ASCII Format +static const Byte kMagicHexCrc = '2'; // New CRC Format +static const Byte kMagicOct = '7'; // Portable ASCII Format + +static const char *kName_TRAILER = "TRAILER!!!"; + +static const unsigned k_BinRecord_Size = 2 + 8 * 2 + 2 * 4; +static const unsigned k_OctRecord_Size = 6 + 8 * 6 + 2 * 11; +static const unsigned k_HexRecord_Size = 6 + 13 * 8; + +static const unsigned k_RecordSize_Max = k_HexRecord_Size; - const UInt32 kRecord2Size = 26; /* - struct CRecord2 + struct CBinRecord { unsigned short c_magic; short c_dev; @@ -49,13 +58,10 @@ namespace NFileHeader unsigned short c_namesize; unsigned short c_filesizes[2]; }; - */ - - const UInt32 kRecordSize = 110; - /* - struct CRecord + + struct CHexRecord { - char Magic[6]; // "070701" for "new" portable format, "070702" for CRC format + char Magic[6]; char inode[8]; char Mode[8]; char UID[8]; @@ -69,15 +75,26 @@ namespace NFileHeader char RDevMinor[8]; //only valid for chr and blk special files char NameSize[8]; // count includes terminating NUL in pathname char ChkSum[8]; // 0 for "new" portable format; for CRC format the sum of all the bytes in the file - bool CheckMagic() const - { return memcmp(Magic, NMagic::kMagic1, 6) == 0 || - memcmp(Magic, NMagic::kMagic2, 6) == 0; }; }; - */ +*/ - const UInt32 kOctRecordSize = 76; - -} +enum EType +{ + k_Type_BinLe, + k_Type_BinBe, + k_Type_Oct, + k_Type_Hex, + k_Type_HexCrc +}; + +static const char *k_Types[] = +{ + "Binary LE" + , "Binary BE" + , "Portable ASCII" + , "New ASCII" + , "New CRC" +}; struct CItem { @@ -86,12 +103,9 @@ struct CItem UInt32 Mode; UInt32 UID; UInt32 GID; - UInt32 Size; + UInt64 Size; UInt32 MTime; - // char LinkFlag; - // AString LinkName; ????? - char Magic[8]; UInt32 NumLinks; UInt32 DevMajor; UInt32 DevMinor; @@ -100,394 +114,479 @@ struct CItem UInt32 ChkSum; UInt32 Align; + EType Type; + + UInt32 HeaderSize; + UInt64 HeaderPos; + bool IsBin() const { return Type == k_Type_BinLe || Type == k_Type_BinBe; } + bool IsCrcFormat() const { return Type == k_Type_HexCrc; }; bool IsDir() const { return (Mode & 0170000) == 0040000; } + bool IsTrailer() const { return strcmp(Name, kName_TRAILER) == 0; } + UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }; }; -class CItemEx: public CItem +enum EErrorType { -public: - UInt64 HeaderPosition; - UInt32 HeaderSize; - UInt64 GetDataPosition() const { return HeaderPosition + HeaderSize; }; + k_ErrorType_OK, + k_ErrorType_Corrupted, + k_ErrorType_UnexpectedEnd, }; -const UInt32 kMaxBlockSize = NFileHeader::kRecordSize; - -class CInArchive +struct CInArchive { - CMyComPtr<IInStream> m_Stream; - UInt64 m_Position; - - UInt16 _blockSize; - Byte _block[kMaxBlockSize]; - UInt32 _blockPos; - Byte ReadByte(); - UInt16 ReadUInt16(); - UInt32 ReadUInt32(); + ISequentialInStream *Stream; + UInt64 Processed; - bool ReadNumber(UInt32 &resultValue); - bool ReadOctNumber(int size, UInt32 &resultValue); - - HRESULT ReadBytes(void *data, UInt32 size, UInt32 &processedSize); -public: - HRESULT Open(IInStream *inStream); - HRESULT GetNextItem(bool &filled, CItemEx &itemInfo); - HRESULT Skip(UInt64 numBytes); - HRESULT SkipDataRecords(UInt64 dataSize, UInt32 align); + HRESULT Read(void *data, size_t *size); + HRESULT GetNextItem(CItem &item, EErrorType &errorType); }; -HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 &processedSize) +HRESULT CInArchive::Read(void *data, size_t *size) { - size_t realProcessedSize = size; - RINOK(ReadStream(m_Stream, data, &realProcessedSize)); - processedSize = (UInt32)realProcessedSize; - m_Position += processedSize; - return S_OK; + HRESULT res = ReadStream(Stream, data, size); + Processed += *size; + return res; } -Byte CInArchive::ReadByte() +static bool ReadHex(const Byte *p, UInt32 &resVal) { - if (_blockPos >= _blockSize) - throw "Incorrect cpio archive"; - return _block[_blockPos++]; + char sz[16]; + memcpy(sz, p, 8); + sz[8] = 0; + const char *end; + resVal = ConvertHexStringToUInt32(sz, &end); + return (unsigned)(end - sz) == 8; } -UInt16 CInArchive::ReadUInt16() +static bool ReadOct6(const Byte *p, UInt32 &resVal) { - UInt16 value = 0; - for (int i = 0; i < 2; i++) - { - Byte b = ReadByte(); - value |= (UInt16(b) << (8 * i)); - } - return value; + char sz[16]; + memcpy(sz, p, 6); + sz[6] = 0; + const char *end; + resVal = ConvertOctStringToUInt32(sz, &end); + return (unsigned)(end - sz) == 6; } -UInt32 CInArchive::ReadUInt32() +static bool ReadOct11(const Byte *p, UInt64 &resVal) { - UInt32 value = 0; - for (int i = 0; i < 4; i++) - { - Byte b = ReadByte(); - value |= (UInt32(b) << (8 * i)); - } - return value; + char sz[16]; + memcpy(sz, p, 11); + sz[11] = 0; + const char *end; + resVal = ConvertOctStringToUInt64(sz, &end); + return (unsigned)(end - sz) == 11; } -HRESULT CInArchive::Open(IInStream *inStream) -{ - RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position)); - m_Stream = inStream; - return S_OK; -} -bool CInArchive::ReadNumber(UInt32 &resultValue) -{ - resultValue = 0; - for (int i = 0; i < 8; i++) - { - char c = char(ReadByte()); - int d; - if (c >= '0' && c <= '9') - d = c - '0'; - else if (c >= 'A' && c <= 'F') - d = 10 + c - 'A'; - else if (c >= 'a' && c <= 'f') - d = 10 + c - 'a'; - else - return false; - resultValue *= 0x10; - resultValue += d; - } - return true; -} +#define READ_HEX(y) { if (!ReadHex(p2, y)) return S_OK; p2 += 8; } +#define READ_OCT_6(y) { if (!ReadOct6(p2, y)) return S_OK; p2 += 6; } +#define READ_OCT_11(y) { if (!ReadOct11(p2, y)) return S_OK; p2 += 11; } -static bool OctalToNumber(const char *s, UInt64 &res) +static UInt32 GetAlignedSize(UInt32 size, UInt32 align) { - const char *end; - res = ConvertOctStringToUInt64(s, &end); - return (*end == ' ' || *end == 0); + while ((size & (align - 1)) != 0) + size++; + return size; } -static bool OctalToNumber32(const char *s, UInt32 &res) -{ - UInt64 res64; - if (!OctalToNumber(s, res64)) - return false; - res = (UInt32)res64; - return (res64 <= 0xFFFFFFFF); -} +static UInt16 Get16(const Byte *p, bool be) { if (be) return GetBe16(p); return GetUi16(p); } +static UInt32 Get32(const Byte *p, bool be) { return ((UInt32)Get16(p, be) << 16) + Get16(p + 2, be); } -bool CInArchive::ReadOctNumber(int size, UInt32 &resultValue) -{ - char sz[32 + 4]; - int i; - for (i = 0; i < size && i < 32; i++) - sz[i] = (char)ReadByte(); - sz[i] = 0; - return OctalToNumber32(sz, resultValue); -} +#define G16(offs, v) v = Get16(p + (offs), be) +#define G32(offs, v) v = Get32(p + (offs), be) -#define GetFromHex(y) { if (!ReadNumber(y)) return S_FALSE; } -#define GetFromOct6(y) { if (!ReadOctNumber(6, y)) return S_FALSE; } -#define GetFromOct11(y) { if (!ReadOctNumber(11, y)) return S_FALSE; } +static const unsigned kNameSizeMax = 1 << 12; -static unsigned short ConvertValue(unsigned short value, bool convert) +API_FUNC_static_IsArc IsArc_Cpio(const Byte *p, size_t size) { - if (!convert) - return value; - return (unsigned short)((((unsigned short)(value & 0xFF)) << 8) | (value >> 8)); -} + if (size < k_BinRecord_Size) + return k_IsArc_Res_NEED_MORE; -static UInt32 GetAlignedSize(UInt32 size, UInt32 align) -{ - while ((size & (align - 1)) != 0) - size++; - return size; + UInt32 nameSize; + UInt32 numLinks; + if (p[0] == '0') + { + if (p[1] != '7' || + p[2] != '0' || + p[3] != '7' || + p[4] != '0') + return k_IsArc_Res_NO; + if (p[5] == '7') + { + if (size < k_OctRecord_Size) + return k_IsArc_Res_NEED_MORE; + for (int i = 6; i < k_OctRecord_Size; i++) + { + char c = p[i]; + if (c < '0' || c > '7') + return k_IsArc_Res_NO; + } + ReadOct6(p + 6 * 6, numLinks); + ReadOct6(p + 8 * 6 + 11, nameSize); + } + else if (p[5] == '1' || p[5] == '2') + { + if (size < k_HexRecord_Size) + return k_IsArc_Res_NEED_MORE; + for (int i = 6; i < k_HexRecord_Size; i++) + { + char c = p[i]; + if ((c < '0' || c > '9') && + (c < 'A' || c > 'F') && + (c < 'a' || c > 'f')) + return k_IsArc_Res_NO; + } + ReadHex(p + 6 + 4 * 8, numLinks); + ReadHex(p + 6 + 11 * 8, nameSize); + } + else + return k_IsArc_Res_NO; + } + else + { + UInt32 rDevMinor; + if (p[0] == kMagicBin0 && p[1] == kMagicBin1) + { + numLinks = GetUi16(p + 12); + rDevMinor = GetUi16(p + 14); + nameSize = GetUi16(p + 20); + } + else if (p[0] == kMagicBin1 && p[1] == kMagicBin0) + { + numLinks = GetBe16(p + 12); + rDevMinor = GetBe16(p + 14); + nameSize = GetBe16(p + 20); + } + else + return k_IsArc_Res_NO; + + if (rDevMinor != 0) + return k_IsArc_Res_NO; + if (nameSize > (1 << 8)) + return k_IsArc_Res_NO; + } + if (numLinks == 0 || numLinks >= (1 << 10)) + return k_IsArc_Res_NO; + if (nameSize == 0 || nameSize > kNameSizeMax) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; } +#define READ_STREAM(_dest_, _size_) \ + { size_t processed = (_size_); RINOK(Read(_dest_, &processed)); \ +if (processed != (_size_)) { errorType = k_ErrorType_UnexpectedEnd; return S_OK; } } -HRESULT CInArchive::GetNextItem(bool &filled, CItemEx &item) +HRESULT CInArchive::GetNextItem(CItem &item, EErrorType &errorType) { - filled = false; + errorType = k_ErrorType_Corrupted; - UInt32 processedSize; - item.HeaderPosition = m_Position; + Byte p[k_RecordSize_Max]; - _blockSize = kMaxBlockSize; - RINOK(ReadBytes(_block, 2, processedSize)); - if (processedSize != 2) - return S_FALSE; - _blockPos = 0; + READ_STREAM(p, k_BinRecord_Size) UInt32 nameSize; - bool oldBE = - _block[0] == NFileHeader::NMagic::kMagicForRecord2[1] && - _block[1] == NFileHeader::NMagic::kMagicForRecord2[0]; - - bool binMode = (_block[0] == NFileHeader::NMagic::kMagicForRecord2[0] && - _block[1] == NFileHeader::NMagic::kMagicForRecord2[1]) || - oldBE; - - if (binMode) + if (p[0] != '0') { - RINOK(ReadBytes(_block + 2, NFileHeader::kRecord2Size - 2, processedSize)); - if (processedSize != NFileHeader::kRecord2Size - 2) - return S_FALSE; + bool be; + if (p[0] == kMagicBin0 && p[1] == kMagicBin1) { be = false; item.Type = k_Type_BinLe; } + else if (p[0] == kMagicBin1 && p[1] == kMagicBin0) { be = true; item.Type = k_Type_BinBe; } + else return S_FALSE; + item.Align = 2; - _blockPos = 2; item.DevMajor = 0; - item.DevMinor = ConvertValue(ReadUInt16(), oldBE); - item.inode = ConvertValue(ReadUInt16(), oldBE); - item.Mode = ConvertValue(ReadUInt16(), oldBE); - item.UID = ConvertValue(ReadUInt16(), oldBE); - item.GID = ConvertValue(ReadUInt16(), oldBE); - item.NumLinks = ConvertValue(ReadUInt16(), oldBE); item.RDevMajor =0; - item.RDevMinor = ConvertValue(ReadUInt16(), oldBE); - UInt16 timeHigh = ConvertValue(ReadUInt16(), oldBE); - UInt16 timeLow = ConvertValue(ReadUInt16(), oldBE); - item.MTime = (UInt32(timeHigh) << 16) + timeLow; - nameSize = ConvertValue(ReadUInt16(), oldBE); - UInt16 sizeHigh = ConvertValue(ReadUInt16(), oldBE); - UInt16 sizeLow = ConvertValue(ReadUInt16(), oldBE); - item.Size = (UInt32(sizeHigh) << 16) + sizeLow; - item.ChkSum = 0; - item.HeaderSize = GetAlignedSize( - nameSize + NFileHeader::kRecord2Size, item.Align); - nameSize = item.HeaderSize - NFileHeader::kRecord2Size; + + G16(2, item.DevMinor); + G16(4, item.inode); + G16(6, item.Mode); + G16(8, item.UID); + G16(10, item.GID); + G16(12, item.NumLinks); + G16(14, item.RDevMinor); + G32(16, item.MTime); + G16(20, nameSize); + G32(22, item.Size); + + /* + if (item.RDevMinor != 0) + return S_FALSE; + */ + + item.HeaderSize = GetAlignedSize(nameSize + k_BinRecord_Size, item.Align); + nameSize = item.HeaderSize - k_BinRecord_Size; } else { - RINOK(ReadBytes(_block + 2, 4, processedSize)); - if (processedSize != 4) + if (p[1] != '7' || + p[2] != '0' || + p[3] != '7' || + p[4] != '0') return S_FALSE; - - bool magicOK = - memcmp(_block, NFileHeader::NMagic::kMagic1, 6) == 0 || - memcmp(_block, NFileHeader::NMagic::kMagic2, 6) == 0; - _blockPos = 6; - if (magicOK) + if (p[5] == kMagicOct) { - RINOK(ReadBytes(_block + 6, NFileHeader::kRecordSize - 6, processedSize)); - if (processedSize != NFileHeader::kRecordSize - 6) - return S_FALSE; - item.Align = 4; + item.Type = k_Type_Oct; + READ_STREAM(p + k_BinRecord_Size, k_OctRecord_Size - k_BinRecord_Size) + item.Align = 1; + item.DevMajor = 0; + item.RDevMajor = 0; - GetFromHex(item.inode); - GetFromHex(item.Mode); - GetFromHex(item.UID); - GetFromHex(item.GID); - GetFromHex(item.NumLinks); - UInt32 mTime; - GetFromHex(mTime); - item.MTime = mTime; - GetFromHex(item.Size); - GetFromHex(item.DevMajor); - GetFromHex(item.DevMinor); - GetFromHex(item.RDevMajor); - GetFromHex(item.RDevMinor); - GetFromHex(nameSize); - GetFromHex(item.ChkSum); - item.HeaderSize = GetAlignedSize( - nameSize + NFileHeader::kRecordSize, item.Align); - nameSize = item.HeaderSize - NFileHeader::kRecordSize; + const Byte *p2 = p + 6; + READ_OCT_6(item.DevMinor); + READ_OCT_6(item.inode); + READ_OCT_6(item.Mode); + READ_OCT_6(item.UID); + READ_OCT_6(item.GID); + READ_OCT_6(item.NumLinks); + READ_OCT_6(item.RDevMinor); + { + UInt64 mTime64; + READ_OCT_11(mTime64); + item.MTime = 0; + if (mTime64 < (UInt32)(Int32)-1) + item.MTime = (UInt32)mTime64; + } + READ_OCT_6(nameSize); + READ_OCT_11(item.Size); // ????? + item.HeaderSize = GetAlignedSize(nameSize + k_OctRecord_Size, item.Align); + nameSize = item.HeaderSize - k_OctRecord_Size; } else { - if (!memcmp(_block, NFileHeader::NMagic::kMagic3, 6) == 0) - return S_FALSE; - RINOK(ReadBytes(_block + 6, NFileHeader::kOctRecordSize - 6, processedSize)); - if (processedSize != NFileHeader::kOctRecordSize - 6) + if (p[5] == kMagicHex) + item.Type = k_Type_Hex; + else if (p[5] == kMagicHexCrc) + item.Type = k_Type_HexCrc; + else return S_FALSE; - item.Align = 1; - item.DevMajor = 0; - GetFromOct6(item.DevMinor); - GetFromOct6(item.inode); - GetFromOct6(item.Mode); - GetFromOct6(item.UID); - GetFromOct6(item.GID); - GetFromOct6(item.NumLinks); - item.RDevMajor = 0; - GetFromOct6(item.RDevMinor); - UInt32 mTime; - GetFromOct11(mTime); - item.MTime = mTime; - GetFromOct6(nameSize); - GetFromOct11(item.Size); // ????? - item.HeaderSize = GetAlignedSize( - nameSize + NFileHeader::kOctRecordSize, item.Align); - nameSize = item.HeaderSize - NFileHeader::kOctRecordSize; + + READ_STREAM(p + k_BinRecord_Size, k_HexRecord_Size - k_BinRecord_Size) + + item.Align = 4; + + const Byte *p2 = p + 6; + READ_HEX(item.inode); + READ_HEX(item.Mode); + READ_HEX(item.UID); + READ_HEX(item.GID); + READ_HEX(item.NumLinks); + READ_HEX(item.MTime); + { + UInt32 size32; + READ_HEX(size32); + item.Size = size32; + } + READ_HEX(item.DevMajor); + READ_HEX(item.DevMinor); + READ_HEX(item.RDevMajor); + READ_HEX(item.RDevMinor); + READ_HEX(nameSize); + READ_HEX(item.ChkSum); + if (nameSize >= kNameSizeMax) + return S_OK; + item.HeaderSize = GetAlignedSize(nameSize + k_HexRecord_Size, item.Align); + nameSize = item.HeaderSize - k_HexRecord_Size; } } - if (nameSize == 0 || nameSize >= (1 << 27)) - return E_FAIL; - RINOK(ReadBytes(item.Name.GetBuffer(nameSize), nameSize, processedSize)); - if (processedSize != nameSize) - return E_FAIL; + if (nameSize > kNameSizeMax) + return S_FALSE; + if (nameSize == 0 || nameSize >= kNameSizeMax) + return S_OK; + char *s = item.Name.GetBuffer(nameSize); + size_t processedSize = nameSize; + RINOK(Read(s, &processedSize)); + s[nameSize] = 0; item.Name.ReleaseBuffer(); - if (strcmp(item.Name, NFileHeader::NMagic::kEndName) == 0) + if (processedSize != nameSize) + { + errorType = k_ErrorType_UnexpectedEnd; return S_OK; - filled = true; - return S_OK; -} - -HRESULT CInArchive::Skip(UInt64 numBytes) -{ - UInt64 newPostion; - RINOK(m_Stream->Seek(numBytes, STREAM_SEEK_CUR, &newPostion)); - m_Position += numBytes; - if (m_Position != newPostion) - return E_FAIL; + } + errorType = k_ErrorType_OK; return S_OK; } -HRESULT CInArchive::SkipDataRecords(UInt64 dataSize, UInt32 align) -{ - while ((dataSize & (align - 1)) != 0) - dataSize++; - return Skip(dataSize); -} - - class CHandler: public IInArchive, public IInArchiveGetStream, public CMyUnknownImp { - CObjectVector<CItemEx> _items; + CObjectVector<CItem> _items; CMyComPtr<IInStream> _stream; + UInt64 _phySize; + EType _Type; + EErrorType _error; + bool _isArc; public: MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; -/* -enum +static const Byte kArcProps[] = { - kpidinode = kpidUserDefined, - kpidiChkSum + kpidSubType }; -*/ -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidPosixAttrib, VT_UI4}, - // { L"inode", kpidinode, VT_UI4} - // { L"CheckSum", kpidiChkSum, VT_UI4} + kpidPath, + kpidIsDir, + kpidSize, + kpidMTime, + kpidPosixAttrib, + kpidLinks }; IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO +IMP_IInArchive_ArcProps -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - // try + NCOM::CPropVariant prop; + switch (propID) { - CInArchive archive; + case kpidSubType: prop = k_Types[_Type]; break; + case kpidPhySize: prop = _phySize; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) + v |= kpv_ErrorFlags_IsNotArc; + switch (_error) + { + case k_ErrorType_UnexpectedEnd: v |= kpv_ErrorFlags_UnexpectedEnd; break; + case k_ErrorType_Corrupted: v |= kpv_ErrorFlags_HeadersError; break; + } + prop = v; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + { + Close(); + UInt64 endPos = 0; - bool needSetTotal = true; - if (callback != NULL) + RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + if (callback) { - RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); - RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(callback->SetTotal(NULL, &endPos)); } - RINOK(archive.Open(stream)); - _items.Clear(); + CInArchive arc; + + arc.Stream = stream; + arc.Processed = 0; for (;;) { - CItemEx item; - bool filled; - HRESULT result = archive.GetNextItem(filled, item); + CItem item; + item.HeaderPos = arc.Processed; + HRESULT result = arc.GetNextItem(item, _error); if (result == S_FALSE) return S_FALSE; if (result != S_OK) return S_FALSE; - if (!filled) + if (_error != k_ErrorType_OK) + { + if (_error == k_ErrorType_Corrupted) + arc.Processed = item.HeaderPos; break; + } + if (_items.IsEmpty()) + _Type = item.Type; + else if (_items.Back().Type != item.Type) + { + _error = k_ErrorType_Corrupted; + arc.Processed = item.HeaderPos; + break; + } + if (item.IsTrailer()) + break; + _items.Add(item); - archive.SkipDataRecords(item.Size, item.Align); - if (callback != NULL) + { - if (needSetTotal) + // archive.SkipDataRecords(item.Size, item.Align); + UInt64 dataSize = item.Size; + UInt32 align = item.Align; + while ((dataSize & (align - 1)) != 0) + dataSize++; + + // _error = k_ErrorType_UnexpectedEnd; break; + + arc.Processed += dataSize; + if (arc.Processed > endPos) { - RINOK(callback->SetTotal(NULL, &endPos)); - needSetTotal = false; + _error = k_ErrorType_UnexpectedEnd; + break; } - if (_items.Size() % 100 == 0) + + UInt64 newPostion; + RINOK(stream->Seek(dataSize, STREAM_SEEK_CUR, &newPostion)); + if (arc.Processed != newPostion) + return E_FAIL; + } + + if (callback && (_items.Size() & 0xFF) == 0) + { + UInt64 numFiles = _items.Size(); + RINOK(callback->SetCompleted(&numFiles, &item.HeaderPos)); + } + } + _phySize = arc.Processed; + if (_error != k_ErrorType_OK) + { + if (_items.Size() == 0) + return S_FALSE; + if (_items.Size() == 1 && _items[0].IsBin()) + { + // probably it's false detected archive. So we return error + return S_FALSE; + } + } + else + { + // Read tailing zeros. + // Most of cpio files use 512-bytes aligned zeros + UInt64 pos = arc.Processed; + const UInt32 kTailSize_MAX = 1 << 9; + Byte buf[kTailSize_MAX]; + + UInt32 rem = (kTailSize_MAX - (UInt32)pos) & (kTailSize_MAX - 1); + if (rem != 0) + { + rem++; // we need to see that it's end of file + size_t processed = rem; + RINOK(ReadStream(stream, buf, &processed)); + if (processed < rem) { - UInt64 numFiles = _items.Size(); - UInt64 numBytes = item.HeaderPosition; - RINOK(callback->SetCompleted(&numFiles, &numBytes)); + unsigned i; + for (i = 0; i < processed && buf[i] == 0; i++); + if (i == processed) + _phySize += processed; } } } - if (_items.Size() == 0) - return S_FALSE; - + + _isArc = true; _stream = stream; } - /* - catch(...) - { - return S_FALSE; - } - */ return S_OK; COM_TRY_END } @@ -496,6 +595,10 @@ STDMETHODIMP CHandler::Close() { _items.Clear(); _stream.Release(); + _phySize = 0; + _Type = k_Type_BinLe; + _isArc = false; + _error = k_ErrorType_OK; return S_OK; } @@ -508,12 +611,24 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItemEx &item = _items[index]; + NCOM::CPropVariant prop; + const CItem &item = _items[index]; - switch(propID) + switch (propID) { - case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break; + case kpidPath: + { + UString res; + bool needConvert = true; + #ifdef _WIN32 + if (ConvertUTF8ToUnicode(item.Name, res)) + needConvert = false; + #endif + if (needConvert) + res = MultiByteToUnicodeString(item.Name, CP_OEMCP); + prop = NItemName::GetOSName(res); + break; + } case kpidIsDir: prop = item.IsDir(); break; case kpidSize: case kpidPackSize: @@ -524,12 +639,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (item.MTime != 0) { FILETIME utc; - NWindows::NTime::UnixTimeToFileTime(item.MTime, utc); + NTime::UnixTimeToFileTime(item.MTime, utc); prop = utc; } break; } case kpidPosixAttrib: prop = item.Mode; break; + case kpidLinks: prop = item.NumLinks; break; /* case kpidinode: prop = item.inode; break; case kpidiChkSum: prop = item.ChkSum; break; @@ -540,11 +656,53 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_END } +class COutStreamWithSum: + public ISequentialOutStream, + public CMyUnknownImp +{ + CMyComPtr<ISequentialOutStream> _stream; + UInt64 _size; + UInt32 _crc; + bool _calculate; +public: + MY_UNKNOWN_IMP + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init(bool calculate = true) + { + _size = 0; + _calculate = calculate; + _crc = 0; + } + void EnableCalc(bool calculate) { _calculate = calculate; } + void InitCRC() { _crc = 0; } + UInt64 GetSize() const { return _size; } + UInt32 GetCRC() const { return _crc; } +}; + +STDMETHODIMP COutStreamWithSum::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + if (_calculate) + { + UInt32 crc = 0; + for (UInt32 i = 0; i < size; i++) + crc += (UInt32)(((const Byte *)data)[i]); + _crc += crc; + } + if (processedSize) + *processedSize = size; + return result; +} + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (numItems == 0) @@ -568,6 +726,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ISequentialInStream> inStream(streamSpec); streamSpec->SetStream(_stream); + COutStreamWithSum *outStreamSumSpec = new COutStreamWithSum; + CMyComPtr<ISequentialOutStream> outStreamSum(outStreamSumSpec); + for (i = 0; i < numItems; i++) { lps->InSize = lps->OutSize = currentTotalSize; @@ -577,7 +738,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; Int32 index = allFilesMode ? i : indices[i]; - const CItemEx &item = _items[index]; + const CItem &item = _items[index]; RINOK(extractCallback->GetStream(index, &outStream, askMode)); currentTotalSize += item.Size; if (item.IsDir()) @@ -588,19 +749,23 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } if (!testMode && !outStream) continue; + outStreamSumSpec->Init(item.IsCrcFormat()); + outStreamSumSpec->SetStream(outStream); + outStream.Release(); + RINOK(extractCallback->PrepareOperation(askMode)); - if (testMode) - { - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } RINOK(_stream->Seek(item.GetDataPosition(), STREAM_SEEK_SET, NULL)); streamSpec->Init(item.Size); - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); - outStream.Release(); - RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError)); + RINOK(copyCoder->Code(inStream, outStreamSum, NULL, NULL, progress)); + outStreamSumSpec->ReleaseStream(); + Int32 res = NExtract::NOperationResult::kDataError; + if (copyCoderSpec->TotalSize == item.Size) + { + res = NExtract::NOperationResult::kOK; + if (item.IsCrcFormat() && item.ChkSum != outStreamSumSpec->GetCRC()) + res = NExtract::NOperationResult::kCRCError; + } + RINOK(extractCallback->SetOperationResult(res)); } return S_OK; COM_TRY_END @@ -609,15 +774,24 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) { COM_TRY_BEGIN - const CItemEx &item = _items[index]; + const CItem &item = _items[index]; return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream); COM_TRY_END } -static IInArchive *CreateArc() { return new NArchive::NCpio::CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"Cpio", L"cpio", 0, 0xED, { 0 }, 0, false, CreateArc, 0 }; + { "Cpio", "cpio", 0, 0xED, + 3 + 5 + 2 + 2, + { + 5, '0', '7', '0', '7', '0', + 2, kMagicBin0, kMagicBin1, + 2, kMagicBin1, kMagicBin0, + }, + 0, + NArcInfoFlags::kMultiSignature, + CreateArc, NULL, IsArc_Cpio }; REGISTER_ARC(Cpio) diff --git a/CPP/7zip/Archive/CramfsHandler.cpp b/CPP/7zip/Archive/CramfsHandler.cpp index a55e3743..3764f1af 100755..100644 --- a/CPP/7zip/Archive/CramfsHandler.cpp +++ b/CPP/7zip/Archive/CramfsHandler.cpp @@ -3,13 +3,14 @@ #include "StdAfx.h" #include "../../../C/7zCrc.h" -#include "../../../C/CpuArch.h" #include "../../../C/Alloc.h" +#include "../../../C/CpuArch.h" +#include "../../../C/LzmaDec.h" -#include "Common/ComTry.h" -#include "Common/StringConvert.h" +#include "../../Common/ComTry.h" +#include "../../Common/StringConvert.h" -#include "Windows/PropVariantUtils.h" +#include "../../Windows/PropVariantUtils.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -38,6 +39,30 @@ static const UInt32 kNodeSize = 12; static const UInt32 kFlag_FsVer2 = (1 << 0); +static const unsigned k_Flags_BlockSize_Shift = 11; +static const unsigned k_Flags_BlockSize_Mask = 7; +static const unsigned k_Flags_Method_Shift = 14; +static const unsigned k_Flags_Method_Mask = 3; + +/* + There is possible collision in flags: + - Original CramFS writes 0 in method field. But it uses ZLIB. + - Modified CramFS writes 0 in method field for "NONE" compression? + How to solve that collision? +*/ + +#define k_Flags_Method_NONE 0 +#define k_Flags_Method_ZLIB 1 +#define k_Flags_Method_LZMA 2 + +static const char *k_Methods[] = +{ + "Copy" + , "ZLIB" + , "LZMA" + , "Unknown" +}; + static const CUInt32PCharPair k_Flags[] = { { 0, "Ver2" }, @@ -48,7 +73,6 @@ static const CUInt32PCharPair k_Flags[] = }; static const unsigned kBlockSizeLog = 12; -static const UInt32 kBlockSize = 1 << kBlockSizeLog; /* struct CNode @@ -141,6 +165,8 @@ struct CHeader } bool IsVer2() const { return (Flags & kFlag_FsVer2) != 0; } + unsigned GetBlockSizeShift() const { return (unsigned)(Flags >> k_Flags_BlockSize_Shift) & k_Flags_BlockSize_Mask; } + unsigned GetMethod() const { return (unsigned)(Flags >> k_Flags_Method_Shift) & k_Flags_Method_Mask; } }; class CHandler: @@ -153,14 +179,21 @@ class CHandler: Byte *_data; UInt32 _size; UInt32 _headersSize; - AString _errorMessage; + + UInt32 _errorFlags; + bool _isArc; + CHeader _h; + UInt32 _phySize; + + unsigned _method; + unsigned _blockSizeLog; // Current file NCompress::NZlib::CDecoder *_zlibDecoderSpec; CMyComPtr<ICompressCoder> _zlibDecoder; - + CBufInStream *_inStreamSpec; CMyComPtr<ISequentialInStream> _inStream; @@ -175,6 +208,18 @@ class CHandler: AString GetPath(int index) const; bool GetPackSize(int index, UInt32 &res) const; void Free(); + + UInt32 GetNumBlocks(UInt32 size) const + { + return (size + ((UInt32)1 << _blockSizeLog) - 1) >> _blockSizeLog; + } + + void UpdatePhySize(UInt32 s) + { + if (_phySize < s) + _phySize = s; + } + public: CHandler(): _data(0) {} ~CHandler() { Free(); } @@ -184,25 +229,26 @@ public: HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); }; -static const STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI4}, - { NULL, kpidPackSize, VT_UI4}, - { NULL, kpidPosixAttrib, VT_UI4} - // { NULL, kpidOffset, VT_UI4} + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidPosixAttrib + // kpidOffset }; -static const STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidName, VT_BSTR}, - { NULL, kpidBigEndian, VT_BOOL}, - { NULL, kpidCharacts, VT_BSTR}, - { NULL, kpidPhySize, VT_UI4}, - { NULL, kpidHeadersSize, VT_UI4}, - { NULL, kpidNumSubFiles, VT_UI4}, - { NULL, kpidNumBlocks, VT_UI4} + kpidVolumeName, + kpidBigEndian, + kpidCharacts, + kpidClusterSize, + kpidMethod, + kpidHeadersSize, + kpidNumSubFiles, + kpidNumBlocks }; IMP_IInArchive_Props @@ -221,10 +267,11 @@ HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level) UInt32 end = offset + size; if (offset < kHeaderSize || end > _size || level > kNumDirLevelsMax) return S_FALSE; + UpdatePhySize(end); if (end > _headersSize) _headersSize = end; - int startIndex = _items.Size(); + unsigned startIndex = _items.Size(); while (size != 0) { @@ -241,8 +288,8 @@ HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level) size -= nodeLen; } - int endIndex = _items.Size(); - for (int i = startIndex; i < endIndex; i++) + unsigned endIndex = _items.Size(); + for (unsigned i = startIndex; i < endIndex; i++) { RINOK(OpenDir(i, _items[i].Offset, level + 1)); } @@ -255,17 +302,26 @@ HRESULT CHandler::Open2(IInStream *inStream) RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)); if (!_h.Parse(buf)) return S_FALSE; + _method = k_Flags_Method_ZLIB; + _blockSizeLog = kBlockSizeLog; + _phySize = kHeaderSize; if (_h.IsVer2()) { + _method = _h.GetMethod(); + // FIT IT. Now we don't know correct way to work with collision in method field. + if (_method == k_Flags_Method_NONE) + _method = k_Flags_Method_ZLIB; + _blockSizeLog = kBlockSizeLog + _h.GetBlockSizeShift(); if (_h.Size < kHeaderSize || _h.Size > kArcSizeMax || _h.NumFiles > kNumFilesMax) return S_FALSE; + _phySize = _h.Size; } else { UInt64 size; RINOK(inStream->Seek(0, STREAM_SEEK_END, &size)); if (size > kArcSizeMax) - return S_FALSE; + size = kArcSizeMax; _h.Size = (UInt32)size; RINOK(inStream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL)); } @@ -278,18 +334,59 @@ HRESULT CHandler::Open2(IInStream *inStream) if (processed < kNodeSize) return S_FALSE; _size = kHeaderSize + (UInt32)processed; - if (_size != _h.Size) - _errorMessage = "Unexpected end of archive"; - else + if (_h.IsVer2()) { - SetUi32(_data + 0x20, 0); - if (_h.IsVer2()) + if (_size != _h.Size) + _errorFlags = kpv_ErrorFlags_UnexpectedEnd; + else + { + SetUi32(_data + 0x20, 0); if (CrcCalc(_data, _h.Size) != _h.Crc) - _errorMessage = "CRC error"; + { + _errorFlags = kpv_ErrorFlags_HeadersError; + // _errorMessage = "CRC error"; + } + } + if (_h.NumFiles >= 1) + _items.ClearAndReserve(_h.NumFiles - 1); } - if (_h.IsVer2()) - _items.Reserve(_h.NumFiles - 1); - return OpenDir(-1, kHeaderSize, 0); + + RINOK(OpenDir(-1, kHeaderSize, 0)); + + if (!_h.IsVer2()) + { + FOR_VECTOR(i, _items) + { + const CItem &item = _items[i]; + const Byte *p = _data + item.Offset; + bool be = _h.be; + if (IsDir(p, be)) + continue; + UInt32 offset = GetOffset(p, be); + if (offset < kHeaderSize) + continue; + UInt32 numBlocks = GetNumBlocks(GetSize(p, be)); + if (numBlocks == 0) + continue; + UInt32 start = offset + numBlocks * 4; + if (start > _size) + continue; + UInt32 end = Get32(_data + start - 4); + if (end >= start) + UpdatePhySize(end); + } + + // Read tailing zeros. Most cramfs archives use 4096-bytes aligned zeros + const UInt32 kTailSize_MAX = 1 << 12; + UInt32 endPos = (_phySize + kTailSize_MAX - 1) & ~(kTailSize_MAX - 1); + if (endPos > _size) + endPos = _size; + UInt32 pos; + for (pos = _phySize; pos < endPos && _data[pos] == 0; pos++); + if (pos == endPos) + _phySize = endPos; + } + return S_OK; } AString CHandler::GetPath(int index) const @@ -334,13 +431,16 @@ AString CHandler::GetPath(int index) const bool CHandler::GetPackSize(int index, UInt32 &res) const { + res = 0; const CItem &item = _items[index]; const Byte *p = _data + item.Offset; bool be = _h.be; UInt32 offset = GetOffset(p, be); if (offset < kHeaderSize) return false; - UInt32 numBlocks = (GetSize(p, be) + kBlockSize - 1) >> kBlockSizeLog; + UInt32 numBlocks = GetNumBlocks(GetSize(p, be)); + if (numBlocks == 0) + return true; UInt32 start = offset + numBlocks * 4; if (start > _size) return false; @@ -357,6 +457,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb { Close(); RINOK(Open2(stream)); + _isArc = true; _stream = stream; } return S_OK; @@ -371,10 +472,12 @@ void CHandler::Free() STDMETHODIMP CHandler::Close() { + _isArc = false; + _phySize = 0; + _errorFlags = 0; _headersSize = 0; _items.Clear(); _stream.Release(); - _errorMessage.Empty(); Free(); return S_OK; } @@ -389,9 +492,9 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NWindows::NCOM::CPropVariant prop; - switch(propID) + switch (propID) { - case kpidName: + case kpidVolumeName: { char dest[kHeaderNameSize + 4]; memcpy(dest, _h.Name, kHeaderNameSize); @@ -401,11 +504,20 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } case kpidBigEndian: prop = _h.be; break; case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break; + case kpidMethod: prop = k_Methods[_method]; break; + case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break; case kpidNumBlocks: if (_h.IsVer2()) prop = _h.NumBlocks; break; case kpidNumSubFiles: if (_h.IsVer2()) prop = _h.NumFiles; break; - case kpidPhySize: if (_h.IsVer2()) prop = _h.Size; break; + case kpidPhySize: prop = _phySize; break; case kpidHeadersSize: prop = _headersSize; break; - case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + case kpidErrorFlags: + { + UInt32 v = _errorFlags; + if (!_isArc) + v |= kpv_ErrorFlags_IsNotArc; + prop = v; + break; + } } prop.Detach(value); return S_OK; @@ -453,13 +565,60 @@ HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSi return Handler->ReadBlock(blockIndex, dest, blockSize); } +static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } +static void SzFree(void *p, void *address) { p = p; MyFree(address); } +static ISzAlloc g_Alloc = { SzAlloc, SzFree }; + HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) { - if (!_zlibDecoder) + if (_method == k_Flags_Method_ZLIB) { - _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); - _zlibDecoder = _zlibDecoderSpec; + if (!_zlibDecoder) + { + _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); + _zlibDecoder = _zlibDecoderSpec; + } } + else + { + if (_method != k_Flags_Method_LZMA) + { + // probably we must support no-compression archives here. + return E_NOTIMPL; + } + } + + bool be = _h.be; + const Byte *p = _data + (_curBlocksOffset + (UInt32)blockIndex * 4); + UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p - 4)); + UInt32 end = Get32(p); + if (end < start || end > _size) + return S_FALSE; + UInt32 inSize = end - start; + + if (_method == k_Flags_Method_LZMA) + { + const unsigned kLzmaHeaderSize = LZMA_PROPS_SIZE + 4; + if (inSize < kLzmaHeaderSize) + return S_FALSE; + const Byte *p = _data + start; + UInt32 destSize32 = GetUi32(p + LZMA_PROPS_SIZE); + if (destSize32 > blockSize) + return S_FALSE; + SizeT destLen = destSize32; + SizeT srcLen = inSize - kLzmaHeaderSize; + ELzmaStatus status; + SRes res = LzmaDecode(dest, &destLen, p + kLzmaHeaderSize, &srcLen, + p, LZMA_PROPS_SIZE, LZMA_FINISH_END, &status, &g_Alloc); + if (res != SZ_OK + || (status != LZMA_STATUS_FINISHED_WITH_MARK && + status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + || destLen != destSize32 + || srcLen != inSize - kLzmaHeaderSize) + return S_FALSE; + return S_OK; + } + if (!_inStream) { _inStreamSpec = new CBufInStream(); @@ -470,17 +629,10 @@ HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) _outStreamSpec = new CBufPtrSeqOutStream(); _outStream = _outStreamSpec; } - bool be = _h.be; - const Byte *p = _data + (_curBlocksOffset + (UInt32)blockIndex * 4); - UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p - 4)); - UInt32 end = Get32(p); - if (end < start || end > _size) - return S_FALSE; - UInt32 inSize = end - start; _inStreamSpec->Init(_data + start, inSize); _outStreamSpec->Init(dest, blockSize); RINOK(_zlibDecoder->Code(_inStream, _outStream, NULL, NULL, NULL)); - return (_zlibDecoderSpec->GetInputProcessedSize() == inSize && + return (inSize == _zlibDecoderSpec->GetInputProcessedSize() && _outStreamSpec->GetPos() == blockSize) ? S_OK : S_FALSE; } @@ -488,7 +640,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (numItems == 0) @@ -562,19 +714,22 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (hres == E_OUTOFMEMORY) return E_OUTOFMEMORY; if (hres == S_FALSE || !inStream) - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; else { RINOK(hres); if (inStream) { HRESULT hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress); - if (hres != S_OK && hres != S_FALSE) + if (hres == S_OK) { - RINOK(hres); + if (copyCoderSpec->TotalSize == curSize) + res = NExtract::NOperationResult::kOK; } - if (copyCoderSpec->TotalSize == curSize && hres == S_OK) - res = NExtract::NOperationResult::kOK; + else if (hres == E_NOTIMPL) + res = NExtract::NOperationResult::kUnsupportedMethod; + else if (hres != S_FALSE) + return hres; } } } @@ -596,7 +751,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) return E_FAIL; UInt32 size = GetSize(p, be); - UInt32 numBlocks = (size + kBlockSize - 1) >> kBlockSizeLog; + UInt32 numBlocks = GetNumBlocks(size); UInt32 offset = GetOffset(p, be); if (offset < kHeaderSize) { @@ -625,7 +780,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) _curNumBlocks = numBlocks; _curBlocksOffset = offset; streamSpec->Handler = this; - if (!streamSpec->Alloc(kBlockSizeLog, 21 - kBlockSizeLog)) + if (!streamSpec->Alloc(_blockSizeLog, 21 - _blockSizeLog)) return E_OUTOFMEMORY; streamSpec->Init(size); *stream = streamTemp.Detach(); @@ -634,10 +789,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -static IInArchive *CreateArc() { return new NArchive::NCramfs::CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"CramFS", L"cramfs", 0, 0xD3, SIGNATURE, kSignatureSize, false, CreateArc, 0 }; + { "CramFS", "cramfs", 0, 0xD3, + kSignatureSize, SIGNATURE, + 16, + 0, + CreateArc }; REGISTER_ARC(Cramfs) diff --git a/CPP/7zip/Archive/DebHandler.cpp b/CPP/7zip/Archive/DebHandler.cpp deleted file mode 100755 index 82d2cde8..00000000 --- a/CPP/7zip/Archive/DebHandler.cpp +++ /dev/null @@ -1,413 +0,0 @@ -// DebHandler.cpp - -#include "StdAfx.h" - -#include "Common/ComTry.h" -#include "Common/StringConvert.h" -#include "Common/StringToInt.h" - -#include "Windows/PropVariant.h" -#include "Windows/Time.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#include "Common/ItemNameUtils.h" - -using namespace NWindows; -using namespace NTime; - -namespace NArchive { -namespace NDeb { - -namespace NHeader -{ - const int kSignatureLen = 8; - - const char *kSignature = "!<arch>\n"; - - const int kNameSize = 16; - const int kTimeSize = 12; - const int kModeSize = 8; - const int kSizeSize = 10; - - /* - struct CHeader - { - char Name[kNameSize]; - char MTime[kTimeSize]; - char Number0[6]; - char Number1[6]; - char Mode[kModeSize]; - char Size[kSizeSize]; - char Quote; - char NewLine; - }; - */ - const int kHeaderSize = kNameSize + kTimeSize + 6 + 6 + kModeSize + kSizeSize + 1 + 1; -} - -struct CItem -{ - AString Name; - UInt64 Size; - UInt32 MTime; - UInt32 Mode; - - UInt64 HeaderPos; - UInt64 GetDataPos() const { return HeaderPos + NHeader::kHeaderSize; }; - // UInt64 GetFullSize() const { return NFileHeader::kRecordSize + Size; }; -}; - -class CInArchive -{ - CMyComPtr<IInStream> m_Stream; - - HRESULT GetNextItemReal(bool &filled, CItem &itemInfo); -public: - UInt64 m_Position; - HRESULT Open(IInStream *inStream); - HRESULT GetNextItem(bool &filled, CItem &itemInfo); - HRESULT SkipData(UInt64 dataSize); -}; - -HRESULT CInArchive::Open(IInStream *inStream) -{ - RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_Position)); - char signature[NHeader::kSignatureLen]; - RINOK(ReadStream_FALSE(inStream, signature, NHeader::kSignatureLen)); - m_Position += NHeader::kSignatureLen; - if (memcmp(signature, NHeader::kSignature, NHeader::kSignatureLen) != 0) - return S_FALSE; - m_Stream = inStream; - return S_OK; -} - -static void MyStrNCpy(char *dest, const char *src, int size) -{ - for (int i = 0; i < size; i++) - { - char c = src[i]; - dest[i] = c; - if (c == 0) - break; - } -} - -static bool OctalToNumber(const char *s, int size, UInt64 &res) -{ - char sz[32]; - MyStrNCpy(sz, s, size); - sz[size] = 0; - const char *end; - int i; - for (i = 0; sz[i] == ' '; i++); - res = ConvertOctStringToUInt64(sz + i, &end); - return (*end == ' ' || *end == 0); -} - -static bool OctalToNumber32(const char *s, int size, UInt32 &res) -{ - UInt64 res64; - if (!OctalToNumber(s, size, res64)) - return false; - res = (UInt32)res64; - return (res64 <= 0xFFFFFFFF); -} - -static bool DecimalToNumber(const char *s, int size, UInt64 &res) -{ - char sz[32]; - MyStrNCpy(sz, s, size); - sz[size] = 0; - const char *end; - int i; - for (i = 0; sz[i] == ' '; i++); - res = ConvertStringToUInt64(sz + i, &end); - return (*end == ' ' || *end == 0); -} - -static bool DecimalToNumber32(const char *s, int size, UInt32 &res) -{ - UInt64 res64; - if (!DecimalToNumber(s, size, res64)) - return false; - res = (UInt32)res64; - return (res64 <= 0xFFFFFFFF); -} - -#define RIF(x) { if (!(x)) return S_FALSE; } - - -HRESULT CInArchive::GetNextItemReal(bool &filled, CItem &item) -{ - filled = false; - - char header[NHeader::kHeaderSize]; - const char *cur = header; - - size_t processedSize = sizeof(header); - item.HeaderPos = m_Position; - RINOK(ReadStream(m_Stream, header, &processedSize)); - if (processedSize != sizeof(header)) - return S_OK; - m_Position += processedSize; - - char tempString[NHeader::kNameSize + 1]; - MyStrNCpy(tempString, cur, NHeader::kNameSize); - cur += NHeader::kNameSize; - tempString[NHeader::kNameSize] = '\0'; - item.Name = tempString; - item.Name.Trim(); - - for (int i = 0; i < item.Name.Length(); i++) - if (((Byte)item.Name[i]) < 0x20) - return S_FALSE; - - RIF(DecimalToNumber32(cur, NHeader::kTimeSize, item.MTime)); - cur += NHeader::kTimeSize; - - cur += 6 + 6; - - RIF(OctalToNumber32(cur, NHeader::kModeSize, item.Mode)); - cur += NHeader::kModeSize; - - RIF(DecimalToNumber(cur, NHeader::kSizeSize, item.Size)); - cur += NHeader::kSizeSize; - - filled = true; - return S_OK; -} - -HRESULT CInArchive::GetNextItem(bool &filled, CItem &item) -{ - for (;;) - { - RINOK(GetNextItemReal(filled, item)); - if (!filled) - return S_OK; - if (item.Name.Compare("debian-binary") != 0) - return S_OK; - if (item.Size != 4) - return S_OK; - SkipData(item.Size); - } -} - -HRESULT CInArchive::SkipData(UInt64 dataSize) -{ - return m_Stream->Seek((dataSize + 1) & (~((UInt64)0x1)), STREAM_SEEK_CUR, &m_Position); -} - -class CHandler: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - CObjectVector<CItem> _items; - CMyComPtr<IInStream> _stream; - Int32 _mainSubfile; - UInt64 _phySize; -public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) - INTERFACE_IInArchive(;) - STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); -}; - -static STATPROPSTG kArcProps[] = -{ - { NULL, kpidPhySize, VT_UI8} -}; - -static STATPROPSTG kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME} -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback *openArchiveCallback) -{ - COM_TRY_BEGIN - { - _mainSubfile = -1; - CInArchive archive; - if (archive.Open(stream) != S_OK) - return S_FALSE; - _items.Clear(); - - if (openArchiveCallback != NULL) - { - RINOK(openArchiveCallback->SetTotal(NULL, NULL)); - UInt64 numFiles = _items.Size(); - RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL)); - } - - for (;;) - { - CItem item; - bool filled; - HRESULT result = archive.GetNextItem(filled, item); - if (result == S_FALSE) - return S_FALSE; - if (result != S_OK) - return S_FALSE; - if (!filled) - break; - if (item.Name.Left(5) == "data.") - _mainSubfile = _items.Size(); - _items.Add(item); - archive.SkipData(item.Size); - if (openArchiveCallback != NULL) - { - UInt64 numFiles = _items.Size(); - RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL)); - } - } - _stream = stream; - _phySize = archive.m_Position; - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _stream.Release(); - _items.Clear(); - return S_OK; -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _items.Size(); - return S_OK; -} - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - NCOM::CPropVariant prop; - switch(propID) - { - case kpidPhySize: prop = _phySize; break; - case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; - } - prop.Detach(value); - return S_OK; -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = _items[index]; - - switch(propID) - { - case kpidPath: prop = (const wchar_t *)NItemName::GetOSName2(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break; - case kpidSize: - case kpidPackSize: - prop = item.Size; - break; - case kpidMTime: - { - if (item.MTime != 0) - { - FILETIME fileTime; - NTime::UnixTimeToFileTime(item.MTime, fileTime); - prop = fileTime; - } - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - totalSize += _items[allFilesMode ? i : indices[i]].Size; - extractCallback->SetTotal(totalSize); - - UInt64 currentTotalSize = 0; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr<ICompressProgressInfo> progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr<ISequentialInStream> inStream(streamSpec); - streamSpec->SetStream(_stream); - - for (i = 0; i < numItems; i++) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()); - CMyComPtr<ISequentialOutStream> realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - currentTotalSize += item.Size; - - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - if (testMode) - { - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - RINOK(_stream->Seek(item.GetDataPos(), STREAM_SEEK_SET, NULL)); - streamSpec->Init(item.Size); - RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - const CItem &item = _items[index]; - return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream); - COM_TRY_END -} - -static IInArchive *CreateArc() { return new NArchive::NDeb::CHandler; } - -static CArcInfo g_ArcInfo = - { L"Deb", L"deb", 0, 0xEC, { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' }, 8, false, CreateArc, 0 }; - -REGISTER_ARC(Deb) - -}} diff --git a/CPP/7zip/Archive/DeflateProps.cpp b/CPP/7zip/Archive/DeflateProps.cpp index ca3dc6f5..ca3dc6f5 100755..100644 --- a/CPP/7zip/Archive/DeflateProps.cpp +++ b/CPP/7zip/Archive/DeflateProps.cpp diff --git a/CPP/7zip/Archive/DeflateProps.h b/CPP/7zip/Archive/DeflateProps.h index 9fd2c2e9..9fd2c2e9 100755..100644 --- a/CPP/7zip/Archive/DeflateProps.h +++ b/CPP/7zip/Archive/DeflateProps.h diff --git a/CPP/7zip/Archive/DllExports.cpp b/CPP/7zip/Archive/DllExports.cpp index 6c72dea7..fa40d024 100755..100644 --- a/CPP/7zip/Archive/DllExports.cpp +++ b/CPP/7zip/Archive/DllExports.cpp @@ -3,8 +3,8 @@ #include "StdAfx.h" #include "../../Common/MyInitGuid.h" + #include "../../Common/ComTry.h" -#include "../../Common/Types.h" #include "../../Windows/NtCheck.h" #include "../../Windows/PropVariant.h" diff --git a/CPP/7zip/Archive/DllExports2.cpp b/CPP/7zip/Archive/DllExports2.cpp index ad14ff06..beb758a2 100755..100644 --- a/CPP/7zip/Archive/DllExports2.cpp +++ b/CPP/7zip/Archive/DllExports2.cpp @@ -1,4 +1,4 @@ -// DLLExports.cpp +// DLLExports2.cpp #include "StdAfx.h" @@ -45,23 +45,23 @@ DEFINE_GUID(CLSID_CArchiveHandler, static const UInt16 kDecodeId = 0x2790; DEFINE_GUID(CLSID_CCodec, -0x23170F69, 0x40C1, kDecodeId, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); +0x23170F69, 0x40C1, kDecodeId, 0, 0, 0, 0, 0, 0, 0, 0); STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject); +STDAPI CreateHasher(const GUID *clsid, IHasher **hasher); STDAPI CreateArchiver(const GUID *classID, const GUID *iid, void **outObject); STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject) { // COM_TRY_BEGIN *outObject = 0; - if (*iid == IID_ICompressCoder || *iid == IID_ICompressCoder2 || *iid == IID_ICompressFilter) - { + if (*iid == IID_ICompressCoder || + *iid == IID_ICompressCoder2 || + *iid == IID_ICompressFilter) return CreateCoder(clsid, iid, outObject); - } - else - { - return CreateArchiver(clsid, iid, outObject); - } + if (*iid == IID_IHasher) + return CreateHasher(clsid, (IHasher **)outObject); + return CreateArchiver(clsid, iid, outObject); // COM_TRY_END } @@ -72,3 +72,11 @@ STDAPI SetLargePageMode() #endif return S_OK; } + +extern bool g_CaseSensitive; + +STDAPI SetCaseSensitive(Int32 caseSensitive) +{ + g_CaseSensitive = (caseSensitive != 0); + return S_OK; +} diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp index 5040d518..7166f2ce 100755..100644 --- a/CPP/7zip/Archive/DmgHandler.cpp +++ b/CPP/7zip/Archive/DmgHandler.cpp @@ -4,85 +4,115 @@ #include "../../../C/CpuArch.h" -#include "Common/Buffer.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/MyXml.h" -#include "Common/UTFConvert.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyXml.h" +#include "../../Common/UTFConvert.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" #include "../Common/StreamUtils.h" #include "../Compress/BZip2Decoder.h" #include "../Compress/CopyCoder.h" #include "../Compress/ZlibDecoder.h" +#include "Common/OutStreamWithCRC.h" + // #define DMG_SHOW_RAW // #include <stdio.h> #define PRF(x) // x +#define Get16(p) GetBe16(p) #define Get32(p) GetBe32(p) #define Get64(p) GetBe64(p) -static int Base64ToByte(char c) +static const Byte k_Base64Table[256] = { - if (c >= 'A' && c <= 'Z') return c - 'A'; - if (c >= 'a' && c <= 'z') return c - 'a' + 26; - if (c >= '0' && c <= '9') return c - '0' + 52; - if (c == '+') return 62; - if (c == '/') return 63; - if (c == '=') return 0; - return -1; -} + 64,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,62,77,64,77,63,52,53,54,55,56,57,58,59,60,61,77,77,77,77,77,77, + 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,77,77,77,77,77, + 77,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77 +}; -static int Base64ToBin(Byte *dest, const char *src, int srcLen) +static Byte *Base64ToBin(Byte *dest, const char *src) { - int srcPos = 0; - int destPos = 0; - while (srcPos < srcLen) + UInt32 val = 1; + UInt32 c = k_Base64Table[(Byte)(*src++)]; + for (;;) { - Byte buf[4]; - int filled = 0; - while (srcPos < srcLen) + /* + UInt32 c = (Byte)(*src++); + if (c >= 'A') { - int n = Base64ToByte(src[srcPos++]); - if (n >= 0) - { - buf[filled++] = (Byte)n; - if (filled == 4) - break; - } + if (c <= 'Z') c -= 'A'; + else if (c >= 'a' && c <= 'z') c -= 'a' - 26; + else continue; + } + else if (c >= '0') + { + if (c <= '9') c += 52 - '0'; + else if (c == '=') break; + else continue; + } + else if (c == '+') c = 62; + else if (c == '/') c = 63; + else if (c == 0) break; + else continue; + */ + + // UInt32 c = k_Base64Table[(Byte)(*src++)]; + if (c < 64) + { + val = (val << 6) | c; + c = k_Base64Table[(Byte)(*src++)]; + if ((val & ((UInt32)1 << 24)) == 0) + continue; + dest[0] = (Byte)(val >> 16); + dest[1] = (Byte)(val >> 8); + dest[2] = (Byte)(val); + dest += 3; + val = 1; + continue; } - if (filled >= 2) { if (dest) dest[destPos] = (buf[0] << 2) | (buf[1] >> 4); destPos++; } - if (filled >= 3) { if (dest) dest[destPos] = (buf[1] << 4) | (buf[2] >> 2); destPos++; } - if (filled >= 4) { if (dest) dest[destPos] = (buf[2] << 6) | (buf[3] ); destPos++; } + if (c == 64) + break; + c = k_Base64Table[(Byte)(*src++)]; + } + if (val >= ((UInt32)1 << 12)) + { + if (val >= ((UInt32)1 << 18)) + *dest++ = (Byte)(val >> 16); + *dest++ = (Byte)(val); } - return destPos; + return dest; } -static UString GetSizeString(UInt64 value) -{ - wchar_t s[32]; - wchar_t c; - if (value < (UInt64)20000) c = 0; - else if (value < ((UInt64)20000 << 10)) { value >>= 10; c = L'K'; } - else if (value < ((UInt64)20000 << 20)) { value >>= 20; c = L'M'; } - else { value >>= 30; c = L'G'; } - ConvertUInt64ToString(value, s); - int p = MyStringLen(s); - s[p++] = c; - s[p++] = L'\0'; - return s; -} namespace NArchive { namespace NDmg { +enum +{ + METHOD_ZERO_0 = 0, + METHOD_COPY = 1, + METHOD_ZERO_2 = 2, // without file CRC calculation + METHOD_ADC = 0x80000004, + METHOD_ZLIB = 0x80000005, + METHOD_BZIP2 = 0x80000006, + METHOD_COMMENT = 0x7FFFFFFE, // is used to comment "+beg" and "+end" in extra field. + METHOD_END = 0xFFFFFFFF +}; + struct CBlock { UInt32 Type; @@ -92,176 +122,244 @@ struct CBlock UInt64 PackSize; UInt64 GetNextPackOffset() const { return PackPos + PackSize; } + UInt64 GetNextUnpPos() const { return UnpPos + UnpSize; } + + bool IsZeroMethod() const { return Type == METHOD_ZERO_0 || Type == METHOD_ZERO_2; } + bool ThereAreDataInBlock() const { return Type != METHOD_COMMENT && Type != METHOD_END; } +}; + +static const UInt32 kCheckSumType_CRC = 2; + +static const size_t kChecksumSize_Max = 0x80; + +struct CChecksum +{ + UInt32 Type; + UInt32 NumBits; + Byte Data[kChecksumSize_Max]; + + bool IsCrc32() const { return Type == kCheckSumType_CRC && NumBits == 32; } + UInt32 GetCrc32() const { return Get32(Data); } + void Parse(const Byte *p); +}; + +void CChecksum::Parse(const Byte *p) +{ + Type = Get32(p); + NumBits = Get32(p + 4); + memcpy(Data, p + 8, kChecksumSize_Max); }; struct CFile { - CByteBuffer Raw; + UInt64 Size; + UInt64 PackSize; UInt64 StartPos; + AString Name; CRecordVector<CBlock> Blocks; - UInt64 GetUnpackSize() const - { - UInt64 size = 0; - for (int i = 0; i < Blocks.Size(); i++) - size += Blocks[i].UnpSize; - return size; - }; - UInt64 GetPackSize() const - { - UInt64 size = 0; - for (int i = 0; i < Blocks.Size(); i++) - size += Blocks[i].PackSize; - return size; - }; + CChecksum Checksum; + bool FullFileChecksum; + + HRESULT Parse(const Byte *p, UInt32 size); +}; +#ifdef DMG_SHOW_RAW +struct CExtraFile +{ + CByteBuffer Data; AString Name; }; +#endif class CHandler: public IInArchive, + public IInArchiveGetStream, public CMyUnknownImp { CMyComPtr<IInStream> _inStream; - - AString _xml; CObjectVector<CFile> _files; - CRecordVector<int> _fileIndices; + bool _masterCrcError; + + UInt64 _startPos; + UInt64 _phySize; + + #ifdef DMG_SHOW_RAW + CObjectVector<CExtraFile> _extras; + #endif HRESULT Open2(IInStream *stream); HRESULT Extract(IInStream *stream); public: - MY_UNKNOWN_IMP1(IInArchive) + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; const UInt32 kXmlSizeMax = ((UInt32)1 << 31) - (1 << 14); -enum -{ - METHOD_ZERO_0 = 0, - METHOD_COPY = 1, - METHOD_ZERO_2 = 2, - METHOD_ADC = 0x80000004, - METHOD_ZLIB = 0x80000005, - METHOD_BZIP2 = 0x80000006, - METHOD_DUMMY = 0x7FFFFFFE, - METHOD_END = 0xFFFFFFFF -}; - -struct CMethodStat -{ - UInt32 NumBlocks; - UInt64 PackSize; - UInt64 UnpSize; - CMethodStat(): NumBlocks(0), PackSize(0), UnpSize(0) {} -}; - struct CMethods { - CRecordVector<CMethodStat> Stats; CRecordVector<UInt32> Types; + CRecordVector<UInt32> ChecksumTypes; + void Update(const CFile &file); - UString GetString() const; + void GetString(AString &s) const; }; void CMethods::Update(const CFile &file) { - for (int i = 0; i < file.Blocks.Size(); i++) - { - const CBlock &b = file.Blocks[i]; - int index = Types.FindInSorted(b.Type); - if (index < 0) - { - index = Types.AddToUniqueSorted(b.Type); - Stats.Insert(index, CMethodStat()); - } - CMethodStat &m = Stats[index]; - m.PackSize += b.PackSize; - m.UnpSize += b.UnpSize; - m.NumBlocks++; - } + ChecksumTypes.AddToUniqueSorted(file.Checksum.Type); + FOR_VECTOR (i, file.Blocks) + Types.AddToUniqueSorted(file.Blocks[i].Type); } -UString CMethods::GetString() const +void CMethods::GetString(AString &res) const { - UString res; - for (int i = 0; i < Types.Size(); i++) + res.Empty(); + unsigned i; + for (i = 0; i < Types.Size(); i++) { - if (i != 0) - res += L' '; - wchar_t buf[32]; - const wchar_t *s; - const CMethodStat &m = Stats[i]; - bool showPack = true; UInt32 type = Types[i]; - switch(type) + if (type == METHOD_COMMENT || type == METHOD_END) + continue; + char buf[16]; + const char *s; + switch (type) { - case METHOD_ZERO_0: s = L"zero0"; showPack = (m.PackSize != 0); break; - case METHOD_ZERO_2: s = L"zero2"; showPack = (m.PackSize != 0); break; - case METHOD_COPY: s = L"copy"; showPack = (m.UnpSize != m.PackSize); break; - case METHOD_ADC: s = L"adc"; break; - case METHOD_ZLIB: s = L"zlib"; break; - case METHOD_BZIP2: s = L"bzip2"; break; - default: ConvertUInt64ToString(type, buf); s = buf; + case METHOD_ZERO_0: s = "Zero0"; break; + case METHOD_ZERO_2: s = "Zero2"; break; + case METHOD_COPY: s = "Copy"; break; + case METHOD_ADC: s = "ADC"; break; + case METHOD_ZLIB: s = "ZLIB"; break; + case METHOD_BZIP2: s = "BZip2"; break; + default: ConvertUInt32ToString(type, buf); s = buf; } + if (!res.IsEmpty()) + res += ' '; res += s; - if (m.NumBlocks != 1) - { - res += L'['; - ConvertUInt64ToString(m.NumBlocks, buf); - res += buf; - res += L']'; - } - res += L'-'; - res += GetSizeString(m.UnpSize); - if (showPack) + } + for (i = 0; i < ChecksumTypes.Size(); i++) + { + UInt32 type = ChecksumTypes[i]; + char buf[32]; + const char *s; + switch (type) { - res += L'-'; - res += GetSizeString(m.PackSize); + case kCheckSumType_CRC: s = "CRC"; break; + default: + ConvertUInt32ToString(type, MyStpCpy(buf, "Check")); + s = buf; } + if (!res.IsEmpty()) + res += ' '; + res += s; } - return res; } -STATPROPSTG kProps[] = +struct CAppleName +{ + bool IsFs; + const char *Ext; + const char *AppleName; +}; + +static const CAppleName k_Names[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidComment, VT_BSTR}, - { NULL, kpidMethod, VT_BSTR} + { true, "hfs", "Apple_HFS" }, + { true, "hfsx", "Apple_HFSX" }, + { true, "ufs", "Apple_UFS" }, + { false, "free", "Apple_Free" }, + { false, "ddm", "DDM" }, + { false, NULL, "Apple_partition_map" }, + { false, NULL, " GPT " }, + { false, NULL, "MBR" }, + { false, NULL, "Driver" }, + { false, NULL, "Patches" } +}; + +static const unsigned kNumAppleNames = ARRAY_SIZE(k_Names); + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidCRC, + kpidComment, + kpidMethod }; IMP_IInArchive_Props -STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidNumBlocks, VT_UI4} + kpidMethod, + kpidNumBlocks }; STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NWindows::NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidMethod: { CMethods m; - for (int i = 0; i < _files.Size(); i++) + FOR_VECTOR (i, _files) m.Update(_files[i]); - prop = m.GetString(); + AString s; + m.GetString(s); + if (!s.IsEmpty()) + prop = s; break; } case kpidNumBlocks: { UInt64 numBlocks = 0; - for (int i = 0; i < _files.Size(); i++) + FOR_VECTOR (i, _files) numBlocks += _files[i].Blocks.Size(); prop = numBlocks; break; } + case kpidMainSubfile: + { + int mainIndex = -1; + int numFS = 0; + int numUnknown = 0; + FOR_VECTOR (i, _files) + { + const AString &name = _files[i].Name; + unsigned n; + for (n = 0; n < kNumAppleNames; n++) + { + const CAppleName &appleName = k_Names[n]; + if (name.Find(appleName.AppleName) >= 0) + { + if (appleName.IsFs) + { + numFS++; + mainIndex = i; + } + break; + } + } + if (n == kNumAppleNames) + { + mainIndex = i; + numUnknown++; + } + } + if (numFS + numUnknown == 1) + prop = (UInt32)mainIndex; + break; + } + case kpidWarning: + if (_masterCrcError) + prop = "Master CRC error"; + break; + case kpidOffset: prop = _startPos; break; + case kpidPhySize: prop = _phySize; break; } prop.Detach(value); return S_OK; @@ -270,9 +368,83 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) IMP_IInArchive_ArcProps +HRESULT CFile::Parse(const Byte *p, UInt32 size) +{ + const UInt32 kHeadSize = 0xCC; + if (size < kHeadSize) + return S_FALSE; + if (Get32(p) != 0x6D697368) // "mish" signature + return S_FALSE; + if (Get32(p + 4) != 1) // version + return S_FALSE; + // UInt64 firstSectorNumber = Get64(p + 8); + UInt64 numSectors = Get64(p + 0x10); + + StartPos = Get64(p + 0x18); + + // UInt32 decompressedBufRequested = Get32(p + 0x20); // ??? + // UInt32 blocksDescriptor = Get32(p + 0x24); // number starting from -1? + // char Reserved1[24]; + + Checksum.Parse(p + 0x40); + PRF(printf("\n\nChecksum Type = %2d", Checksum.Type)); + + UInt32 numBlocks = Get32(p + 0xC8); + if (numBlocks > ((UInt32)1 << 28)) + return S_FALSE; + + const UInt32 kRecordSize = 40; + if (numBlocks * kRecordSize + kHeadSize != size) + return S_FALSE; + + PackSize = 0; + Size = 0; + Blocks.ClearAndReserve(numBlocks); + FullFileChecksum = true; + + p += kHeadSize; + UInt32 i; + for (i = 0; i < numBlocks; i++, p += kRecordSize) + { + CBlock b; + b.Type = Get32(p); + b.UnpPos = Get64(p + 0x08) << 9; + b.UnpSize = Get64(p + 0x10) << 9; + b.PackPos = Get64(p + 0x18); + b.PackSize = Get64(p + 0x20); + + // b.PackPos can be 0 for some types. So we don't check it + if (!Blocks.IsEmpty()) + if (b.UnpPos != Blocks.Back().GetNextUnpPos()) + return S_FALSE; + + PRF(printf("\nType=%8x m[1]=%8x uPos=%8x uSize=%7x pPos=%8x pSize=%7x", + b.Type, Get32(p + 4), (UInt32)b.UnpPos, (UInt32)b.UnpSize, (UInt32)b.PackPos, (UInt32)b.PackSize)); + + if (b.Type == METHOD_COMMENT) + continue; + if (b.Type == METHOD_END) + break; + PackSize += b.PackSize; + if (b.UnpSize != 0) + { + if (b.Type == METHOD_ZERO_2) + FullFileChecksum = false; + Blocks.AddInReserved(b); + } + } + if (i != numBlocks - 1) + return S_FALSE; + if (!Blocks.IsEmpty()) + Size = Blocks.Back().GetNextUnpPos(); + if (Size != (numSectors << 9)) + return S_FALSE; + return S_OK; +} + static int FindKeyPair(const CXmlItem &item, const AString &key, const AString &nextTag) { - for (int i = 0; i + 1 < item.SubItems.Size(); i++) + for (unsigned i = 0; i + 1 < item.SubItems.Size(); i++) { const CXmlItem &si = item.SubItems[i]; if (si.IsTagged("key") && si.GetSubString() == key && item.SubItems[i + 1].IsTagged(nextTag)) @@ -281,134 +453,308 @@ static int FindKeyPair(const CXmlItem &item, const AString &key, const AString & return -1; } -static AString GetStringFromKeyPair(const CXmlItem &item, const AString &key, const AString &nextTag) +static const AString *GetStringFromKeyPair(const CXmlItem &item, const AString &key, const AString &nextTag) { int index = FindKeyPair(item, key, nextTag); if (index >= 0) - return item.SubItems[index].GetSubString(); - return AString(); + return item.SubItems[index].GetSubStringPtr(); + return NULL; +} + +static const unsigned HEADER_SIZE = 0x200; + +static bool IsKoly(const Byte *p) +{ + if (Get32(p) != 0x6B6F6C79) // "koly" signature + return false; + if (Get32(p + 4) != 4) // version + return false; + if (Get32(p + 8) != HEADER_SIZE) + return false; + return true; } HRESULT CHandler::Open2(IInStream *stream) { - const int HEADER_SIZE = 0x1E0; + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPos)); - UInt64 headerPos; - RINOK(stream->Seek(-HEADER_SIZE, STREAM_SEEK_END, &headerPos)); Byte buf[HEADER_SIZE]; RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE)); - UInt64 address1 = Get64(buf + 0); - UInt64 address2 = Get64(buf + 0xB8); - UInt64 size64 = Get64(buf + 0xC0); - if (address1 != address2 || size64 >= kXmlSizeMax || size64 == 0 || - address1 >= headerPos || address1 + size64 > headerPos) - return S_FALSE; - RINOK(stream->Seek(address1, STREAM_SEEK_SET, NULL)); - size_t size = (size_t)size64; - char *ss = _xml.GetBuffer((int)size + 1); - RINOK(ReadStream_FALSE(stream, ss, size)); - ss[size] = 0; - _xml.ReleaseBuffer(); + UInt64 headerPos; + if (IsKoly(buf)) + headerPos = _startPos; + else + { + RINOK(stream->Seek(0, STREAM_SEEK_END, &headerPos)); + if (headerPos < HEADER_SIZE) + return S_FALSE; + headerPos -= HEADER_SIZE; + RINOK(stream->Seek(headerPos, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE)); + if (!IsKoly(buf)) + return S_FALSE; + } - CXml xml; - if (!xml.Parse(_xml)) - return S_FALSE; - if (xml.Root.Name != "plist") + // 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); + // 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); + + UInt64 totalLen = dataForkLen + rsrcLen + xmlLen; + if (totalLen > headerPos) return S_FALSE; - - int dictIndex = xml.Root.FindSubTag("dict"); - if (dictIndex < 0) - return S_FALSE; - - const CXmlItem &dictItem = xml.Root.SubItems[dictIndex]; - int rfDictIndex = FindKeyPair(dictItem, "resource-fork", "dict"); - if (rfDictIndex < 0) - return S_FALSE; - - const CXmlItem &rfDictItem = dictItem.SubItems[rfDictIndex]; - int arrIndex = FindKeyPair(rfDictItem, "blkx", "array"); - if (arrIndex < 0) + _startPos = headerPos - totalLen; + _phySize = totalLen + HEADER_SIZE; + headerPos = totalLen; + + if (headerPos < dataForkOffset || + headerPos < dataForkOffset + dataForkLen || + headerPos < rsrcOffset || + headerPos < rsrcOffset + rsrcLen || + headerPos < xmlOffset || + headerPos < xmlOffset + xmlLen) return S_FALSE; - const CXmlItem &arrItem = rfDictItem.SubItems[arrIndex]; + // Byte reserved[0x78] + + CChecksum masterChecksum; + masterChecksum.Parse(buf + 0x160); - int i; - for (i = 0; i < arrItem.SubItems.Size(); i++) + // UInt32 imageVariant = Get32(buf + 0x1E8); + // UInt64 numSectors = Get64(buf + 0x1EC); + // Byte reserved[0x12] + + const UInt32 RSRC_HEAD_SIZE = 0x100; + + // 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)); + // useRsrc = false; + + if (useRsrc) { - const CXmlItem &item = arrItem.SubItems[i]; - if (!item.IsTagged("dict")) - continue; + #ifdef DMG_SHOW_RAW + CExtraFile &extra = _extras.AddNew(); + extra.Name = "rsrc.bin"; + CByteBuffer &rsrcBuf = extra.Data; + #else + 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)); + + 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) + return S_FALSE; + if (footerSize < 16) + return S_FALSE; + if (memcmp(p, p + footerOffset, 16) != 0) + return S_FALSE; - CFile file; - file.StartPos = 0; + p += footerOffset; - int destLen; + if ((UInt32)Get16(p + 0x18) != 0x1C) + return S_FALSE; + UInt32 namesOffset = Get16(p + 0x1A); + if (namesOffset > footerSize) + return S_FALSE; + + UInt32 numItems = (UInt32)Get16(p + 0x1C) + 1; + if (numItems * 8 + 0x1E > namesOffset) + return S_FALSE; + + for (UInt32 i = 0; i < numItems; i++) { - AString dataString; - AString name = GetStringFromKeyPair(item, "Name", "string"); - if (name.IsEmpty()) - name = GetStringFromKeyPair(item, "CFName", "string"); - file.Name = name; - dataString = GetStringFromKeyPair(item, "Data", "data"); - - destLen = Base64ToBin(NULL, dataString, dataString.Length()); - file.Raw.SetCapacity(destLen); - Base64ToBin(file.Raw, dataString, dataString.Length()); - } + const Byte *p2 = p + 0x1E + i * 8; + + UInt32 typeId = Get32(p2); + if (typeId != 0x626C6B78) // blkx + continue; + + UInt32 numFiles = (UInt32)Get16(p2 + 4) + 1; + UInt32 offs = Get16(p2 + 6); + if (0x1C + offs + 12 * numFiles > namesOffset) + return S_FALSE; - if (destLen > 0xCC && Get32(file.Raw) == 0x6D697368) + for (UInt32 k = 0; k < numFiles; k++) + { + const Byte *p3 = p + 0x1C + offs + k * 12; + // UInt32 id = Get16(p3); + 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); + blockOffset &= (((UInt32)1 << 24) - 1); + // UInt32 unknown2 = Get32(p3 + 8); // ??? + 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; + } + CByteBuffer &rawBuf = extra.Data; + rawBuf.SetCapacity(blockSize); + memcpy(rawBuf, pBlock + 4, blockSize); + } + #endif + + CFile &file = _files.AddNew(); + if (namePos != 0xFFFF) + { + UInt32 namesBlockSize = footerSize - namesOffset; + if (namePos >= namesBlockSize) + return S_FALSE; + const Byte *namePtr = p + namesOffset + namePos; + UInt32 nameLen = *namePtr; + if (namesBlockSize - namePos <= nameLen) + return S_FALSE; + for (UInt32 r = 1; r <= nameLen; r++) + { + char c = namePtr[r]; + if (c < 0x20 || c >= 0x80) + break; + file.Name += c; + } + } + RINOK(file.Parse(pBlock + 4, blockSize)); + } + } + } + else + { + if (xmlLen >= kXmlSizeMax || xmlLen == 0) + return S_FALSE; + RINOK(stream->Seek(_startPos + dataForkLen, STREAM_SEEK_SET, NULL)); + size_t size = (size_t)xmlLen; + + CXml xml; { - PRF(printf("\n\n index = %d", _files.Size())); - const int kRecordSize = 40; - for (int offset = 0xCC; offset + kRecordSize <= destLen; offset += kRecordSize) + AString xmlStr; + char *ss = xmlStr.GetBuffer((int)size + 1); + RINOK(ReadStream_FALSE(stream, ss, size)); + ss[size] = 0; { - const Byte *p = (const Byte *)file.Raw + offset; - CBlock b; - b.Type = Get32(p); - if (b.Type == METHOD_END) - break; - if (b.Type == METHOD_DUMMY) - continue; - - b.UnpPos = Get64(p + 0x08) << 9; - b.UnpSize = Get64(p + 0x10) << 9; - b.PackPos = Get64(p + 0x18); - b.PackSize = Get64(p + 0x20); - - file.Blocks.Add(b); - - PRF(printf("\nType=%8x m[1]=%8x uPos=%8x uSize=%7x pPos=%8x pSize=%7x", - b.Type, Get32(p + 4), (UInt32)b.UnpPos, (UInt32)b.UnpSize, (UInt32)b.PackPos, (UInt32)b.PackSize)); + const char *p = ss; + for (;;) + { + if (*p == 0) break; p++; + if (*p == 0) break; p++; + if (*p == 0) break; p++; + if (*p == 0) break; p++; + } + xmlStr.ReleaseBuffer((int)(p - ss)); } + if (!xml.Parse(xmlStr)) + return S_FALSE; + + #ifdef DMG_SHOW_RAW + CExtraFile &extra = _extras.AddNew(); + extra.Name = "a.xml"; + extra.Data.SetCapacity(size); + memcpy(extra.Data, ss, size); + #endif } - int itemIndex = _files.Add(file); - if (file.Blocks.Size() > 0) + if (xml.Root.Name != "plist") + return S_FALSE; + + int dictIndex = xml.Root.FindSubTag("dict"); + if (dictIndex < 0) + return S_FALSE; + + const CXmlItem &dictItem = xml.Root.SubItems[dictIndex]; + int rfDictIndex = FindKeyPair(dictItem, "resource-fork", "dict"); + if (rfDictIndex < 0) + return S_FALSE; + + const CXmlItem &rfDictItem = dictItem.SubItems[rfDictIndex]; + int arrIndex = FindKeyPair(rfDictItem, "blkx", "array"); + if (arrIndex < 0) + return S_FALSE; + + const CXmlItem &arrItem = rfDictItem.SubItems[arrIndex]; + + FOR_VECTOR (i, arrItem.SubItems) { - // if (file.Name.Find("HFS") >= 0) - _fileIndices.Add(itemIndex); + const CXmlItem &item = arrItem.SubItems[i]; + if (!item.IsTagged("dict")) + continue; + + CByteBuffer rawBuf; + int destLen = 0; + { + const AString *dataString = GetStringFromKeyPair(item, "Data", "data"); + if (!dataString) + return S_FALSE; + destLen = dataString->Len() / 4 * 3 + 4; + rawBuf.Alloc(destLen); + destLen = (int)(Base64ToBin(rawBuf, *dataString) - rawBuf); + #ifdef DMG_SHOW_RAW + CExtraFile &extra = _extras.AddNew(); + { + char extraName[16]; + ConvertUInt32ToString(_files.Size(), extraName); + extra.Name = extraName; + } + extra.Data.SetCapacity(destLen); + memcpy(extra.Data, rawBuf, destLen); + #endif + } + CFile &file = _files.AddNew(); + { + const AString *name = GetStringFromKeyPair(item, "Name", "string"); + if (!name || name->IsEmpty()) + name = GetStringFromKeyPair(item, "CFName", "string"); + if (name) + file.Name = *name; + } + RINOK(file.Parse(rawBuf, destLen)); } } - - // PackPos for each new file is 0 in some DMG files. So we use additional StartPos - bool allStartAreZeros = true; - for (i = 0; i < _files.Size(); i++) - { - const CFile &file = _files[i]; - if (!file.Blocks.IsEmpty() && file.Blocks[0].PackPos != 0) - allStartAreZeros = false; - } - UInt64 startPos = 0; - if (allStartAreZeros) + if (masterChecksum.IsCrc32()) { + UInt32 crc = CRC_INIT_VAL; + unsigned i; for (i = 0; i < _files.Size(); i++) { - CFile &file = _files[i]; - file.StartPos = startPos; - if (!file.Blocks.IsEmpty()) - startPos += file.Blocks.Back().GetNextPackOffset(); + const CChecksum &cs = _files[i].Checksum; + if ((cs.NumBits & 0x7) != 0) + break; + UInt32 len = cs.NumBits >> 3; + if (len > kChecksumSize_Max) + break; + crc = CrcUpdate(crc, cs.Data, (size_t)len); } + if (i == _files.Size()) + _masterCrcError = (CRC_GET_DIGEST(crc) != masterChecksum.GetCrc32()); } return S_OK; @@ -431,24 +777,27 @@ STDMETHODIMP CHandler::Open(IInStream *stream, STDMETHODIMP CHandler::Close() { + _phySize = 0; _inStream.Release(); - _fileIndices.Clear(); _files.Clear(); - _xml.Empty(); + _masterCrcError = false; + #ifdef DMG_SHOW_RAW + _extras.Clear(); + #endif return S_OK; } STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { - *numItems = _fileIndices.Size() + *numItems = _files.Size() #ifdef DMG_SHOW_RAW - + _files.Size() + 1; + + _extras.Size() #endif ; return S_OK; } -#define RAW_PREFIX L"raw" WSTRING_PATH_SEPARATOR +#define RAW_PREFIX "raw" STRING_PATH_SEPARATOR STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { @@ -456,69 +805,58 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val NWindows::NCOM::CPropVariant prop; #ifdef DMG_SHOW_RAW - if ((int)index == _fileIndices.Size()) + if ((int)index >= _files.Size()) { - switch(propID) + const CExtraFile &extra = _extras[index - _files.Size()]; + switch (propID) { case kpidPath: - prop = RAW_PREFIX L"a.xml"; + prop = (AString)RAW_PREFIX + extra.Name; break; case kpidSize: case kpidPackSize: - prop = (UInt64)_xml.Length(); + prop = (UInt64)extra.Data.Size(); break; } } - else if ((int)index > _fileIndices.Size()) + else + #endif { - int rawIndex = (int)index - (_fileIndices.Size() + 1); - switch(propID) + const CFile &item = _files[index]; + switch (propID) { - case kpidPath: + case kpidSize: prop = item.Size; break; + case kpidPackSize: prop = item.PackSize; break; + case kpidCRC: { - wchar_t s[32] = RAW_PREFIX; - ConvertUInt64ToString(rawIndex, s + MyStringLen(s)); - prop = s; + if (item.Checksum.IsCrc32() && item.FullFileChecksum) + prop = item.Checksum.GetCrc32(); break; } - case kpidSize: - case kpidPackSize: - prop = (UInt64)_files[rawIndex].Raw.GetCapacity(); - break; - } - } - else - #endif - { - int itemIndex = _fileIndices[index]; - const CFile &item = _files[itemIndex]; - switch(propID) - { + case kpidMethod: { CMethods m; m.Update(item); - UString resString = m.GetString(); - if (!resString.IsEmpty()) - prop = resString; + AString s; + m.GetString(s); + if (!s.IsEmpty()) + prop = s; break; } - // case kpidExtension: prop = L"hfs"; break; - case kpidPath: { - // break; UString name; - wchar_t s[32]; - ConvertUInt64ToString(index, s); + wchar_t s[16]; + ConvertUInt32ToString(index, s); name = s; - int num = 10; - int numDigits; - for (numDigits = 1; num < _fileIndices.Size(); numDigits++) + unsigned num = 10; + unsigned numDigits; + for (numDigits = 1; num < _files.Size(); numDigits++) num *= 10; - while (name.Length() < numDigits) - name = L'0' + name; + while (name.Len() < numDigits) + name.InsertAtFront(L'0'); AString subName; int pos1 = item.Name.Find('('); @@ -528,23 +866,27 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val int pos2 = item.Name.Find(')', pos1); if (pos2 >= 0) { - subName = item.Name.Mid(pos1, pos2 - pos1); + subName.SetFrom(item.Name.Ptr(pos1), pos2 - pos1); pos1 = subName.Find(':'); if (pos1 >= 0) - subName = subName.Left(pos1); + subName.DeleteFrom(pos1); } } subName.Trim(); if (!subName.IsEmpty()) { - if (subName == "Apple_HFS") - subName = "hfs"; - else if (subName == "Apple_HFSX") - subName = "hfsx"; - else if (subName == "Apple_Free") - subName = "free"; - else if (subName == "DDM") - subName = "ddm"; + for (unsigned n = 0; n < kNumAppleNames; n++) + { + const CAppleName &appleName = k_Names[n]; + if (appleName.Ext) + { + if (subName == appleName.AppleName) + { + subName = appleName.Ext; + break; + } + } + } UString name2; ConvertUTF8ToUnicode(subName, name2); name += L'.'; @@ -561,6 +903,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = name; break; } + case kpidComment: { UString name; @@ -568,9 +911,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = name; break; } - - case kpidSize: prop = item.GetUnpackSize(); break; - case kpidPackSize: prop = item.GetPackSize(); break; } } prop.Detach(value); @@ -585,11 +925,13 @@ class CAdcDecoder: CLzOutWindow m_OutWindowStream; CInBuffer m_InStream; + /* void ReleaseStreams() { m_OutWindowStream.ReleaseStream(); m_InStream.ReleaseStream(); } + */ class CCoderReleaser { @@ -601,7 +943,7 @@ class CAdcDecoder: { if (NeedFlush) m_Coder->m_OutWindowStream.Flush(); - m_Coder->ReleaseStreams(); + // m_Coder->ReleaseStreams(); } }; friend class CCoderReleaser; @@ -711,7 +1053,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _files.Size(); if (numItems == 0) @@ -722,13 +1064,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { int index = (int)(allFilesMode ? i : indices[i]); #ifdef DMG_SHOW_RAW - if (index == _fileIndices.Size()) - totalSize += _xml.Length(); - else if (index > _fileIndices.Size()) - totalSize += _files[index - (_fileIndices.Size() + 1)].Raw.GetCapacity(); + if (index >= _files.Size()) + totalSize += _extras[index - _files.Size()].Data.Size(); else #endif - totalSize += _files[_fileIndices[index]].GetUnpackSize(); + totalSize += _files[index].Size; } extractCallback->SetTotal(totalSize); @@ -738,8 +1078,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt64 currentUnpSize = 0; const UInt32 kZeroBufSize = (1 << 14); - CByteBuffer zeroBuf; - zeroBuf.SetCapacity(kZeroBufSize); + CByteBuffer zeroBuf(kZeroBufSize); memset(zeroBuf, 0, kZeroBufSize); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); @@ -774,52 +1113,55 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; Int32 index = allFilesMode ? i : indices[i]; - // const CItemEx &item = _files[index]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - - + if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); + + COutStreamWithCRC *outCrcStreamSpec = new COutStreamWithCRC; + CMyComPtr<ISequentialOutStream> outCrcStream = outCrcStreamSpec; + outCrcStreamSpec->SetStream(realOutStream); + bool needCrc = false; + outCrcStreamSpec->Init(needCrc); + CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); + outStreamSpec->SetStream(outCrcStream); realOutStream.Release(); Int32 opRes = NExtract::NOperationResult::kOK; #ifdef DMG_SHOW_RAW - if (index > _fileIndices.Size()) + if (index >= _files.Size()) { - const CByteBuffer &buf = _files[index - (_fileIndices.Size() + 1)].Raw; - outStreamSpec->Init(buf.GetCapacity()); - RINOK(WriteStream(outStream, buf, buf.GetCapacity())); - currentPackSize = currentUnpSize = buf.GetCapacity(); - } - else if (index == _fileIndices.Size()) - { - outStreamSpec->Init(_xml.Length()); - RINOK(WriteStream(outStream, (const char *)_xml, _xml.Length())); - currentPackSize = currentUnpSize = _xml.Length(); + const CByteBuffer &buf = _extras[index - _files.Size()].Data; + outStreamSpec->Init(buf.Size()); + RINOK(WriteStream(outStream, buf, buf.Size())); + currentPackSize = currentUnpSize = buf.Size(); } else #endif { - const CFile &item = _files[_fileIndices[index]]; - currentPackSize = item.GetPackSize(); - currentUnpSize = item.GetUnpackSize(); + const CFile &item = _files[index]; + currentPackSize = item.PackSize; + currentUnpSize = item.Size; + + needCrc = item.Checksum.IsCrc32(); UInt64 unpPos = 0; UInt64 packPos = 0; { - for (int j = 0; j < item.Blocks.Size(); j++) + FOR_VECTOR (j, item.Blocks) { lps->InSize = currentPackTotal + packPos; lps->OutSize = currentUnpTotal + unpPos; RINOK(lps->SetCur()); const CBlock &block = item.Blocks[j]; + if (!block.ThereAreDataInBlock()) + continue; packPos += block.PackSize; if (block.UnpPos != unpPos) @@ -828,26 +1170,28 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, break; } - RINOK(_inStream->Seek(item.StartPos + block.PackPos, STREAM_SEEK_SET, NULL)); + RINOK(_inStream->Seek(_startPos + item.StartPos + block.PackPos, STREAM_SEEK_SET, NULL)); streamSpec->Init(block.PackSize); - // UInt64 startSize = outStreamSpec->GetSize(); bool realMethod = true; outStreamSpec->Init(block.UnpSize); HRESULT res = S_OK; - switch(block.Type) + outCrcStreamSpec->EnableCalc(needCrc); + + switch (block.Type) { case METHOD_ZERO_0: case METHOD_ZERO_2: realMethod = false; if (block.PackSize != 0) - opRes = NExtract::NOperationResult::kUnSupportedMethod; + opRes = NExtract::NOperationResult::kUnsupportedMethod; + outCrcStreamSpec->EnableCalc(block.Type == METHOD_ZERO_0); break; case METHOD_COPY: if (block.UnpSize != block.PackSize) { - opRes = NExtract::NOperationResult::kUnSupportedMethod; + opRes = NExtract::NOperationResult::kUnsupportedMethod; break; } res = copyCoder->Code(inStream, outStream, NULL, NULL, progress); @@ -862,6 +1206,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, case METHOD_ZLIB: { res = zlibCoder->Code(inStream, outStream, NULL, NULL, progress); + if (res == S_OK) + if (zlibCoderSpec->GetInputProcessedSize() != block.PackSize) + opRes = NExtract::NOperationResult::kDataError; break; } @@ -869,13 +1216,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { res = bzip2Coder->Code(inStream, outStream, NULL, NULL, progress); if (res == S_OK) - if (streamSpec->GetSize() != block.PackSize) + if (bzip2CoderSpec->GetInputProcessedSize() != block.PackSize) opRes = NExtract::NOperationResult::kDataError; break; } default: - opRes = NExtract::NOperationResult::kUnSupportedMethod; + opRes = NExtract::NOperationResult::kUnsupportedMethod; break; } if (res != S_OK) @@ -900,6 +1247,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } } } + if (needCrc && opRes == NExtract::NOperationResult::kOK) + { + if (outCrcStreamSpec->GetCRC() != item.Checksum.GetCrc32()) + opRes = NExtract::NOperationResult::kCRCError; + } } outStream.Release(); RINOK(extractCallback->SetOperationResult(opRes)); @@ -908,10 +1260,286 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +struct CChunk +{ + int BlockIndex; + UInt64 AccessMark; + CByteBuffer Buf; +}; + +class CInStream: + public IInStream, + public CMyUnknownImp +{ + UInt64 _virtPos; + int _latestChunk; + int _latestBlock; + UInt64 _accessMark; + CObjectVector<CChunk> _chunks; + + NCompress::NBZip2::CDecoder *bzip2CoderSpec; + CMyComPtr<ICompressCoder> bzip2Coder; + + NCompress::NZlib::CDecoder *zlibCoderSpec; + CMyComPtr<ICompressCoder> zlibCoder; + + CAdcDecoder *adcCoderSpec; + CMyComPtr<ICompressCoder> adcCoder; + + CBufPtrSeqOutStream *outStreamSpec; + CMyComPtr<ISequentialOutStream> outStream; + + CLimitedSequentialInStream *limitedStreamSpec; + CMyComPtr<ISequentialInStream> inStream; + +public: + CMyComPtr<IInStream> Stream; + UInt64 Size; + const CFile *File; + UInt64 _startPos; + + HRESULT InitAndSeek(UInt64 startPos) + { + _startPos = startPos; + _virtPos = 0; + _latestChunk = -1; + _latestBlock = -1; + _accessMark = 0; + + limitedStreamSpec = new CLimitedSequentialInStream; + inStream = limitedStreamSpec; + limitedStreamSpec->SetStream(Stream); + + outStreamSpec = new CBufPtrSeqOutStream; + outStream = outStreamSpec; + return S_OK; + } + + MY_UNKNOWN_IMP1(IInStream) + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); +}; + + +int FindBlock(const CRecordVector<CBlock> &blocks, UInt64 pos) +{ + int left = 0, right = blocks.Size(); + for (;;) + { + int mid = (left + right) / 2; + if (mid == left) + return left; + if (pos < blocks[mid].UnpPos) + right = mid; + else + left = mid; + } +} + +STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + COM_TRY_BEGIN + + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + if (_virtPos >= Size) + return S_OK; // (Size == _virtPos) ? S_OK: E_FAIL; + { + UInt64 rem = Size - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + + if (_latestBlock >= 0) + { + const CBlock &block = File->Blocks[_latestBlock]; + if (_virtPos < block.UnpPos || (_virtPos - block.UnpPos) >= block.UnpSize) + _latestBlock = -1; + } + if (_latestBlock < 0) + { + _latestChunk = -1; + int blockIndex = FindBlock(File->Blocks, _virtPos); + const CBlock &block = File->Blocks[blockIndex]; + if (!block.IsZeroMethod() && block.Type != METHOD_COPY) + { + unsigned i; + for (i = 0; i < _chunks.Size(); i++) + if (_chunks[i].BlockIndex == blockIndex) + break; + if (i != _chunks.Size()) + _latestChunk = i; + else + { + const int kNumChunksMax = 128; + int chunkIndex; + if (_chunks.Size() != kNumChunksMax) + chunkIndex = _chunks.Add(CChunk()); + else + { + chunkIndex = 0; + for (i = 0; i < _chunks.Size(); i++) + if (_chunks[i].AccessMark < _chunks[chunkIndex].AccessMark) + chunkIndex = i; + } + CChunk &chunk = _chunks[chunkIndex]; + chunk.BlockIndex = -1; + chunk.AccessMark = 0; + if (chunk.Buf.Size() < block.UnpSize) + { + chunk.Buf.Free(); + if (block.UnpSize > ((UInt32)1 << 31)) + return E_FAIL; + chunk.Buf.Alloc((size_t)block.UnpSize); + } + outStreamSpec->Init(chunk.Buf, (size_t)block.UnpSize); + + RINOK(Stream->Seek(_startPos + File->StartPos + block.PackPos, STREAM_SEEK_SET, NULL)); + + limitedStreamSpec->Init(block.PackSize); + HRESULT res = S_OK; + switch (block.Type) + { + case METHOD_COPY: + if (block.PackSize != block.UnpSize) + return E_FAIL; + res = ReadStream_FAIL(inStream, chunk.Buf, (size_t)block.UnpSize); + break; + + case METHOD_ADC: + if (!adcCoder) + { + adcCoderSpec = new CAdcDecoder(); + adcCoder = adcCoderSpec; + } + res = adcCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, NULL); + break; + + case METHOD_ZLIB: + if (!zlibCoder) + { + zlibCoderSpec = new NCompress::NZlib::CDecoder(); + zlibCoder = zlibCoderSpec; + } + res = zlibCoder->Code(inStream, outStream, NULL, NULL, NULL); + if (res == S_OK && zlibCoderSpec->GetInputProcessedSize() != block.PackSize) + res = S_FALSE; + break; + + case METHOD_BZIP2: + if (!bzip2Coder) + { + bzip2CoderSpec = new NCompress::NBZip2::CDecoder(); + bzip2Coder = bzip2CoderSpec; + } + res = bzip2Coder->Code(inStream, outStream, NULL, NULL, NULL); + if (res == S_OK && bzip2CoderSpec->GetInputProcessedSize() != block.PackSize) + res = S_FALSE; + break; + + default: + return E_FAIL; + } + if (res != S_OK) + return res; + if (block.Type != METHOD_COPY && outStreamSpec->GetPos() != block.UnpSize) + return E_FAIL; + chunk.BlockIndex = blockIndex; + _latestChunk = chunkIndex; + } + _chunks[_latestChunk].AccessMark = _accessMark++; + } + _latestBlock = blockIndex; + } + + const CBlock &block = File->Blocks[_latestBlock]; + UInt64 offset = _virtPos - block.UnpPos; + UInt64 rem = block.UnpSize - offset; + if (size > rem) + size = (UInt32)rem; + + HRESULT res = S_OK; + if (block.Type == METHOD_COPY) + { + RINOK(Stream->Seek(_startPos + File->StartPos + block.PackPos + offset, STREAM_SEEK_SET, NULL)); + res = Stream->Read(data, size, &size); + } + else if (block.IsZeroMethod()) + memset(data, 0, size); + else + memcpy(data, _chunks[_latestChunk].Buf + offset, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return res; + COM_TRY_END +} + +STDMETHODIMP CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += Size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = offset; + if (newPosition) + *newPosition = offset; + return S_OK; +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + #ifdef DMG_SHOW_RAW + if (index >= (UInt32)_files.Size()) + return S_FALSE; + #endif + CInStream *spec = new CInStream; + CMyComPtr<ISequentialInStream> specStream = spec; + spec->File = &_files[index]; + const CFile &file = *spec->File; + FOR_VECTOR (i, file.Blocks) + { + const CBlock &block = file.Blocks[i]; + switch (block.Type) + { + case METHOD_ZERO_0: + case METHOD_ZERO_2: + case METHOD_COPY: + case METHOD_ADC: + case METHOD_ZLIB: + case METHOD_BZIP2: + case METHOD_END: + break; + default: + return S_FALSE; + } + } + spec->Stream = _inStream; + spec->Size = spec->File->Size; + RINOK(spec->InitAndSeek(_startPos)); + *stream = specStream.Detach(); + return S_OK; + COM_TRY_END +} + +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"Dmg", L"dmg", 0, 0xE4, { 0 }, 0, false, CreateArc, 0 }; + { "Dmg", "dmg", 0, 0xE4, + 12, { 'k','o','l','y', 0, 0, 0, 4, 0, 0, 2, 0 }, + 0, + NArcInfoFlags::kBackwardOpen | + NArcInfoFlags::kUseGlobalOffset, + CreateArc }; REGISTER_ARC(Dmg) diff --git a/CPP/7zip/Archive/ElfHandler.cpp b/CPP/7zip/Archive/ElfHandler.cpp index c4ad78e9..1736219f 100755..100644 --- a/CPP/7zip/Archive/ElfHandler.cpp +++ b/CPP/7zip/Archive/ElfHandler.cpp @@ -4,11 +4,11 @@ #include "../../../C/CpuArch.h" -#include "Common/Buffer.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" -#include "Windows/PropVariantUtils.h" +#include "../../Windows/PropVariantUtils.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -17,22 +17,44 @@ #include "../Compress/CopyCoder.h" -static UInt16 Get16(const Byte *p, int be) { if (be) return GetBe16(p); return GetUi16(p); } -static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); } -static UInt64 Get64(const Byte *p, int be) { if (be) return GetBe64(p); return GetUi64(p); } - using namespace NWindows; +static UInt16 Get16(const Byte *p, bool be) { if (be) return GetBe16(p); return GetUi16(p); } +static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); } +static UInt64 Get64(const Byte *p, bool be) { if (be) return GetBe64(p); return GetUi64(p); } + +#define G16(offs, v) v = Get16(p + (offs), be) +#define G32(offs, v) v = Get32(p + (offs), be) +#define G64(offs, v) v = Get64(p + (offs), be) + namespace NArchive { namespace NElf { +/* + ELF Structure for most files (real order can be different): + Header + Program (segment) header table (used at runtime) + Segment1 (Section ... Section) + Segment2 + ... + SegmentN + Section header table (the data for linking and relocation) +*/ + #define ELF_CLASS_32 1 #define ELF_CLASS_64 2 #define ELF_DATA_2LSB 1 #define ELF_DATA_2MSB 2 -#define NUM_SCAN_SECTIONS_MAX (1 << 6) +static const UInt32 kHeaderSize32 = 0x34; +static const UInt32 kHeaderSize64 = 0x40; + +static const UInt32 kSegmentSize32 = 0x20; +static const UInt32 kSegmentSize64 = 0x38; + +static const UInt32 kSectionSize32 = 0x28; +static const UInt32 kSectionSize64 = 0x40; struct CHeader { @@ -49,37 +71,30 @@ struct CHeader UInt64 ProgOffset; UInt64 SectOffset; UInt32 Flags; - UInt16 ElfHeaderSize; + UInt16 HeaderSize; UInt16 SegmentEntrySize; UInt16 NumSegments; - UInt16 SectEntrySize; + UInt16 SectionEntrySize; UInt16 NumSections; - // UInt16 SectNameStringTableIndex; + UInt16 NamesSectIndex; bool Parse(const Byte *buf); - bool CheckSegmentEntrySize() const - { - return (Mode64 && SegmentEntrySize == 0x38) || (!Mode64 && SegmentEntrySize == 0x20); - }; - - UInt64 GetHeadersSize() const - { return ElfHeaderSize + - (UInt64)SegmentEntrySize * NumSegments + - (UInt64)SectEntrySize * NumSections; } - + UInt64 GetHeadersSize() const { return (UInt64)HeaderSize + + (UInt32)NumSegments * SegmentEntrySize + + (UInt32)NumSections * SectionEntrySize; } }; bool CHeader::Parse(const Byte *p) { - switch(p[4]) + switch (p[4]) { case ELF_CLASS_32: Mode64 = false; break; case ELF_CLASS_64: Mode64 = true; break; default: return false; } bool be; - switch(p[5]) + switch (p[5]) { case ELF_DATA_2LSB: be = false; break; case ELF_DATA_2MSB: be = true; break; @@ -94,36 +109,72 @@ bool CHeader::Parse(const Byte *p) if (p[i] != 0) return false; - Type = Get16(p + 0x10, be); - Machine = Get16(p + 0x12, be); + G16(0x10, Type); + G16(0x12, Machine); if (Get32(p + 0x14, be) != 1) // Version return false; if (Mode64) { - // EntryVa = Get64(p + 0x18, be); - ProgOffset = Get64(p + 0x20, be); - SectOffset = Get64(p + 0x28, be); + // G64(0x18, EntryVa); + G64(0x20, ProgOffset); + G64(0x28, SectOffset); p += 0x30; } else { - // EntryVa = Get32(p + 0x18, be); - ProgOffset = Get32(p + 0x1C, be); - SectOffset = Get32(p + 0x20, be); + // G32(0x18, EntryVa); + G32(0x1C, ProgOffset); + G32(0x20, SectOffset); p += 0x24; } - Flags = Get32(p + 0, be); - ElfHeaderSize = Get16(p + 4, be); - SegmentEntrySize = Get16(p + 6, be); - NumSegments = Get16(p + 8, be); - SectEntrySize = Get16(p + 10, be); - NumSections = Get16(p + 12, be); - // SectNameStringTableIndex = Get16(p + 14, be); - return CheckSegmentEntrySize(); + G32(0, Flags); + G16(4, HeaderSize); + if (HeaderSize != (Mode64 ? kHeaderSize64 : kHeaderSize32)) + return false; + + G16(6, SegmentEntrySize); + G16(8, NumSegments); + G16(10, SectionEntrySize); + G16(12, NumSections); + G16(14, NamesSectIndex); + + if (ProgOffset < HeaderSize && (ProgOffset != 0 || NumSegments != 0)) return false; + if (SectOffset < HeaderSize && (SectOffset != 0 || NumSections != 0)) return false; + + if (SegmentEntrySize == 0) { if (NumSegments != 0) return false; } + else if (SegmentEntrySize != (Mode64 ? kSegmentSize64 : kSegmentSize32)) return false; + + if (SectionEntrySize == 0) { if (NumSections != 0) return false; } + else if (SectionEntrySize != (Mode64 ? kSectionSize64 : kSectionSize32)) return false; + + return true; } +// The program header table itself. + +#define PT_PHDR 6 + +static const char *g_SegnmentTypes[] = +{ + "Unused", + "Loadable segment", + "Dynamic linking tables", + "Program interpreter path name", + "Note section", + "SHLIB", + "Program header table", + "TLS" +}; + +static const CUInt32PCharPair g_SegmentFlags[] = +{ + { 0, "Execute" }, + { 1, "Write" }, + { 2, "Read" } +}; + struct CSegment { UInt32 Type; @@ -131,14 +182,14 @@ struct CSegment UInt64 Offset; UInt64 Va; // UInt64 Pa; - UInt64 PSize; + UInt64 Size; UInt64 VSize; - // UInt64 Align; + UInt64 Align; void UpdateTotalSize(UInt64 &totalSize) { - UInt64 t = Offset + PSize; - if (t > totalSize) + UInt64 t = Offset + Size; + if (totalSize < t) totalSize = t; } void Parse(const Byte *p, bool mode64, bool be); @@ -146,30 +197,169 @@ struct CSegment void CSegment::Parse(const Byte *p, bool mode64, bool be) { - Type = Get32(p, be); + G32(0, Type); if (mode64) { - Flags = Get32(p + 4, be); - Offset = Get64(p + 8, be); - Va = Get64(p + 0x10, be); - // Pa = Get64(p + 0x18, be); - PSize = Get64(p + 0x20, be); - VSize = Get64(p + 0x28, be); - // Align = Get64(p + 0x30, be); + G32(4, Flags); + G64(8, Offset); + G64(0x10, Va); + // G64(0x18, Pa); + G64(0x20, Size); + G64(0x28, VSize); + G64(0x30, Align); } else { - Offset = Get32(p + 4, be); - Va = Get32(p + 8, be); - // Pa = Get32(p + 12, be); - PSize = Get32(p + 16, be); - VSize = Get32(p + 20, be); - Flags = Get32(p + 24, be); - // Align = Get32(p + 28, be); + G32(4, Offset); + G32(8, Va); + // G32(0x0C, Pa); + G32(0x10, Size); + G32(0x14, VSize); + G32(0x18, Flags); + G32(0x1C, Align); } } -static const CUInt32PCharPair g_MachinePairs[] = +// Section_index = 0 means NO section + +#define SHN_UNDEF 0 + +// Section types + +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_UNKNOWN12 12 +#define SHT_UNKNOWN13 13 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 + + +static const CUInt32PCharPair g_SectTypes[] = +{ + { 0, "NULL" }, + { 1, "PROGBITS" }, + { 2, "SYMTAB" }, + { 3, "STRTAB" }, + { 4, "RELA" }, + { 5, "HASH" }, + { 6, "DYNAMIC" }, + { 7, "NOTE" }, + { 8, "NOBITS" }, + { 9, "REL" }, + { 10, "SHLIB" }, + { 11, "DYNSYM" }, + { 12, "UNKNOWN12" }, + { 13, "UNKNOWN13" }, + { 14, "INIT_ARRAY" }, + { 15, "FINI_ARRAY" }, + { 16, "PREINIT_ARRAY" }, + { 17, "GROUP" }, + { 18, "SYMTAB_SHNDX" }, + { 0x6ffffff5, "GNU_ATTRIBUTES" }, + { 0x6ffffff6, "GNU_HASH" }, + { 0x6ffffffd, "GNU_verdef" }, + { 0x6ffffffe, "GNU_verneed" }, + { 0x6fffffff, "GNU_versym" }, + // { 0x70000001, "X86_64_UNWIND" }, + { 0x70000001, "ARM_EXIDX" }, + { 0x70000002, "ARM_PREEMPTMAP" }, + { 0x70000003, "ARM_ATTRIBUTES" }, + { 0x70000004, "ARM_DEBUGOVERLAY" }, + { 0x70000005, "ARM_OVERLAYSECTION" } +}; + +static const CUInt32PCharPair g_SectionFlags[] = +{ + { 0, "WRITE" }, + { 1, "ALLOC" }, + { 2, "EXECINSTR" }, + + { 4, "MERGE" }, + { 5, "STRINGS" }, + { 6, "INFO_LINK" }, + { 7, "LINK_ORDER" }, + { 8, "OS_NONCONFORMING" }, + { 9, "GROUP" }, + { 10, "TLS" }, + { 11, "CP_SECTION" }, + { 12, "DP_SECTION" }, + { 13, "XCORE_SHF_CP_SECTION" }, + { 28, "64_LARGE" }, +}; + +struct CSection +{ + UInt32 Name; + UInt32 Type; + UInt64 Flags; + UInt64 Va; + UInt64 Offset; + UInt64 VSize; + UInt32 Link; + UInt32 Info; + UInt64 AddrAlign; + UInt64 EntSize; + + UInt64 GetSize() const { return Type == SHT_NOBITS ? 0 : VSize; } + + void UpdateTotalSize(UInt64 &totalSize) + { + UInt64 t = Offset + GetSize(); + if (totalSize < t) + totalSize = t; + } + bool Parse(const Byte *p, bool mode64, bool be); +}; + +bool CSection::Parse(const Byte *p, bool mode64, bool be) +{ + G32(0, Name); + G32(4, Type); + if (mode64) + { + G64(0x08, Flags); + G64(0x10, Va); + G64(0x18, Offset); + G64(0x20, VSize); + G32(0x28, Link); + G32(0x2C, Info); + G64(0x30, AddrAlign); + G64(0x38, EntSize); + } + else + { + G32(0x08, Flags); + G32(0x0C, Va); + G32(0x10, Offset); + G32(0x14, VSize); + G32(0x18, Link); + G32(0x1C, Info); + G32(0x20, AddrAlign); + G32(0x24, EntSize); + } + if (EntSize >= ((UInt32)1 << 31)) + return false; + if (EntSize >= ((UInt32)1 << 10) && + EntSize >= VSize && + VSize != 0) + return false; + return true; +} + +static const CUInt32PCharPair g_Machines[] = { { 0, "None" }, { 1, "AT&T WE 32100" }, @@ -192,6 +382,7 @@ static const CUInt32PCharPair g_MachinePairs[] = { 20, "PowerPC" }, { 21, "PowerPC 64-bit" }, { 22, "IBM S/390" }, + { 23, "SPU" }, { 36, "NEX v800" }, { 37, "Fujitsu FR20" }, @@ -222,6 +413,7 @@ static const CUInt32PCharPair g_MachinePairs[] = { 62, "AMD64" }, { 63, "Sony DSP" }, + { 66, "Siemens FX66" }, { 67, "ST9+" }, { 68, "ST7" }, @@ -251,15 +443,99 @@ static const CUInt32PCharPair g_MachinePairs[] = { 92, "OpenRISC" }, { 93, "ARC Tangent-A5" }, { 94, "Tensilica Xtensa" }, - { 0x9026, "Alpha" } + { 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" }, + // { 0x9026, "Alpha" } }; -static const CUInt32PCharPair g_AbiOS[] = +static const CUInt32PCharPair g_OS[] = { { 0, "None" }, { 1, "HP-UX" }, { 2, "NetBSD" }, { 3, "Linux" }, + { 4, "Hurd" }, { 6, "Solaris" }, { 7, "AIX" }, @@ -271,16 +547,18 @@ static const CUInt32PCharPair g_AbiOS[] = { 13, "OpenVMS" }, { 14, "HP NSK" }, { 15, "AROS" }, + { 16, "FenixOS" }, + { 64, "Bare-metal TMS320C6000" }, + { 65, "Linux TMS320C6000" }, { 97, "ARM" }, { 255, "Standalone" } }; -static const CUInt32PCharPair g_SegmentFlags[] = -{ - { 0, "Execute" }, - { 1, "Write" }, - { 2, "Read" } -}; +#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[] = { @@ -291,101 +569,119 @@ static const char *g_Types[] = "Core file" }; -static const char *g_SegnmentTypes[] = -{ - "Unused", - "Loadable segment", - "Dynamic linking tables", - "Program interpreter path name", - "Note section", - "SHLIB", - "Program header table", - "TLS" -}; - class CHandler: public IInArchive, + public IArchiveAllowTail, public CMyUnknownImp { + CRecordVector<CSegment> _segments; + CRecordVector<CSection> _sections; + CByteBuffer _namesData; CMyComPtr<IInStream> _inStream; - CObjectVector<CSegment> _sections; - UInt32 _peOffset; - CHeader _header; UInt64 _totalSize; + CHeader _header; + bool _headersError; + bool _allowTail; + + void GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const; HRESULT Open2(IInStream *stream); - bool Parse(const Byte *buf, UInt32 size); public: - MY_UNKNOWN_IMP1(IInArchive) + MY_UNKNOWN_IMP2(IInArchive, IArchiveAllowTail) INTERFACE_IInArchive(;) -}; + STDMETHOD(AllowTail)(Int32 allowTail); -#define ELF_PT_PHDR 6 + CHandler(): _allowTail(false) {} +}; -bool CHandler::Parse(const Byte *buf, UInt32 size) +void CHandler::GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const { - if (size < 64) - return false; - if (!_header.Parse(buf)) - return false; - if (_header.ProgOffset > size || - _header.ProgOffset + (UInt64)_header.SegmentEntrySize * _header.NumSegments > size || - _header.NumSegments > NUM_SCAN_SECTIONS_MAX) - return false; - const Byte *p = buf + _header.ProgOffset; - _totalSize = _header.ProgOffset; - - for (int i = 0; i < _header.NumSegments; i++, p += _header.SegmentEntrySize) + if (index >= _sections.Size()) + return; + const CSection §ion = _sections[index]; + UInt32 offset = section.Name; + if (index == SHN_UNDEF /* && section.Type == SHT_NULL && offset == 0 */) { - CSegment sect; - sect.Parse(p, _header.Mode64, _header.Be); - sect.UpdateTotalSize(_totalSize); - if (sect.Type != ELF_PT_PHDR) - _sections.Add(sect); + if (showNULL) + prop = "NULL"; + return; } - UInt64 total2 = _header.SectOffset + (UInt64)_header.SectEntrySize * _header.NumSections; - if (total2 > _totalSize) - _totalSize = total2; - return true; + const Byte *p = _namesData; + size_t size = _namesData.Size(); + for (size_t i = offset; i < size; i++) + if (p[i] == 0) + { + prop = (const char *)(p + offset); + return; + } } -STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = +{ + kpidCpu, + kpidBit64, + kpidBigEndian, + kpidHostOS, + kpidCharacts, + kpidHeadersSize, + kpidName +}; + +enum { - { NULL, kpidCpu, VT_BSTR}, - { NULL, kpidBit64, VT_BOOL}, - { NULL, kpidBigEndian, VT_BOOL}, - { NULL, kpidHostOS, VT_BSTR}, - { NULL, kpidCharacts, VT_BSTR}, - { NULL, kpidPhySize, VT_UI8}, - { NULL, kpidHeadersSize, VT_UI8} - }; - -STATPROPSTG kProps[] = + kpidLinkSection = kpidUserDefined, + kpidInfoSection +}; + +static const STATPROPSTG kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidType, VT_BSTR}, - { NULL, kpidCharacts, VT_BSTR}, - { NULL, kpidOffset, VT_UI8}, - { NULL, kpidVa, VT_UI8} + { NULL, kpidPath, VT_BSTR }, + { NULL, kpidSize, VT_UI8 }, + { NULL, kpidVirtualSize, VT_UI8 }, + { NULL, kpidOffset, VT_UI8 }, + { NULL, kpidVa, VT_UI8 }, + { NULL, kpidType, VT_BSTR }, + { NULL, kpidCharacts, VT_BSTR } + , { L"Link Section", kpidLinkSection, VT_BSTR} + , { L"Info Section", kpidInfoSection, VT_BSTR} }; -IMP_IInArchive_Props +IMP_IInArchive_Props_WITH_NAME IMP_IInArchive_ArcProps STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NCOM::CPropVariant prop; - switch(propID) + switch (propID) { - case kpidPhySize: prop = _totalSize; break; - case kpidHeadersSize: prop = _header.GetHeadersSize(); break; - case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break; - case kpidBigEndian: if (_header.Be) prop = _header.Be; break; - case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break; - case kpidHostOS: PAIR_TO_PROP(g_AbiOS, _header.Os, prop); break; - case kpidCharacts: TYPE_TO_PROP(g_Types, _header.Type, prop); break; + case kpidPhySize: prop = _totalSize; break; + case kpidHeadersSize: prop = _header.GetHeadersSize(); break; + 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 kpidHostOS: PAIR_TO_PROP(g_OS, _header.Os, prop); break; + case kpidCharacts: TYPE_TO_PROP(g_Types, _header.Type, prop); break; + case kpidExtension: + { + const char *s = NULL; + if (_header.Type == ET_DYN) + s = "so"; + else if (_header.Type == ET_REL) + s = "o"; + if (s) + prop = s; + break; + } + // case kpidIsSelfExe: prop = (_header.Type != ET_DYN) && (_header.Type == ET_REL); break; + case kpidErrorFlags: + { + UInt32 flags = 0; + if (_headersError) flags |= kpv_ErrorFlags_HeadersError; + if (flags != 0) + prop = flags; + break; + } } prop.Detach(value); return S_OK; @@ -396,22 +692,45 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { COM_TRY_BEGIN NCOM::CPropVariant prop; - const CSegment &item = _sections[index]; - switch(propID) + if (index < _segments.Size()) { - case kpidPath: + const CSegment &item = _segments[index]; + switch (propID) { - wchar_t sz[32]; - ConvertUInt64ToString(index, sz); - prop = sz; - break; + case kpidPath: + { + char sz[16]; + ConvertUInt32ToString(index, sz); + prop = sz; + break; + } + case kpidOffset: prop = item.Offset; break; + case kpidVa: prop = item.Va; break; + case kpidSize: + case kpidPackSize: prop = (UInt64)item.Size; break; + case kpidVirtualSize: prop = (UInt64)item.VSize; break; + case kpidType: TYPE_TO_PROP(g_SegnmentTypes, item.Type, prop); break; + case kpidCharacts: FLAGS_TO_PROP(g_SegmentFlags, item.Flags, prop); break; + + } + } + else + { + index -= _segments.Size(); + const CSection &item = _sections[index]; + switch (propID) + { + case kpidPath: GetSectionName(index, prop, true); break; + case kpidOffset: prop = item.Offset; break; + case kpidVa: prop = item.Va; break; + case kpidSize: + case kpidPackSize: prop = (UInt64)(item.Type == SHT_NOBITS ? 0 : item.VSize); break; + case kpidVirtualSize: prop = item.GetSize(); break; + case kpidType: PAIR_TO_PROP(g_SectTypes, item.Type, prop); break; + case kpidCharacts: FLAGS_TO_PROP(g_SectionFlags, (UInt32)item.Flags, prop); break; + case kpidLinkSection: GetSectionName(item.Link, prop, false); break; + case kpidInfoSection: GetSectionName(item.Info, prop, false); break; } - case kpidSize: prop = (UInt64)item.VSize; break; - case kpidPackSize: prop = (UInt64)item.PSize; break; - case kpidOffset: prop = item.Offset; break; - case kpidVa: prop = item.Va; break; - case kpidType: TYPE_TO_PROP(g_SegnmentTypes, item.Type, prop); break; - case kpidCharacts: FLAGS_TO_PROP(g_SegmentFlags, item.Flags, prop); break; } prop.Detach(value); return S_OK; @@ -420,25 +739,118 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val HRESULT CHandler::Open2(IInStream *stream) { - const UInt32 kBufSize = 1 << 18; - const UInt32 kSigSize = 4; - - CByteBuffer buffer; - buffer.SetCapacity(kBufSize); - Byte *buf = buffer; - - size_t processed = kSigSize; - RINOK(ReadStream_FALSE(stream, buf, processed)); - if (buf[0] != 0x7F || buf[1] != 'E' || buf[2] != 'L' || buf[3] != 'F') + const UInt32 kStartSize = kHeaderSize64; + Byte h[kStartSize]; + RINOK(ReadStream_FALSE(stream, h, kStartSize)); + if (h[0] != 0x7F || h[1] != 'E' || h[2] != 'L' || h[3] != 'F') return S_FALSE; - processed = kBufSize - kSigSize; - RINOK(ReadStream(stream, buf + kSigSize, &processed)); - processed += kSigSize; - if (!Parse(buf, (UInt32)processed)) + if (!_header.Parse(h)) return S_FALSE; - UInt64 fileSize; - RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); - return (fileSize == _totalSize) ? S_OK : S_FALSE; + + _totalSize = _header.HeaderSize; + + bool addSegments = false; + bool addSections = false; + + if (_header.NumSections > 1) + addSections = true; + else + addSegments = true; + + if (_header.NumSegments != 0) + { + if (_header.ProgOffset > (UInt64)1 << 60) return S_FALSE; + RINOK(stream->Seek(_header.ProgOffset, STREAM_SEEK_SET, NULL)); + size_t size = (size_t)_header.SegmentEntrySize * _header.NumSegments; + + CByteArr buf(size); + + RINOK(ReadStream_FALSE(stream, buf, size)); + + UInt64 total = _header.ProgOffset + size; + if (_totalSize < total) + _totalSize = total; + + const Byte *p = buf; + + if (addSegments) + _segments.ClearAndReserve(_header.NumSegments); + for (unsigned i = 0; i < _header.NumSegments; i++, p += _header.SegmentEntrySize) + { + CSegment seg; + seg.Parse(p, _header.Mode64, _header.Be); + seg.UpdateTotalSize(_totalSize); + if (addSegments) + if (seg.Type != PT_PHDR) + _segments.AddInReserved(seg); + } + } + + if (_header.NumSections != 0) + { + if (_header.SectOffset > (UInt64)1 << 60) return S_FALSE; + RINOK(stream->Seek(_header.SectOffset, STREAM_SEEK_SET, NULL)); + size_t size = (size_t)_header.SectionEntrySize * _header.NumSections; + + CByteArr buf(size); + + RINOK(ReadStream_FALSE(stream, buf, size)); + + UInt64 total = _header.SectOffset + size; + if (_totalSize < total) + _totalSize = total; + + const Byte *p = buf; + + if (addSections) + _sections.ClearAndReserve(_header.NumSections); + for (unsigned i = 0; i < _header.NumSections; i++, p += _header.SectionEntrySize) + { + CSection sect; + if (!sect.Parse(p, _header.Mode64, _header.Be)) + { + _headersError = true; + return S_FALSE; + } + sect.UpdateTotalSize(_totalSize); + if (addSections) + _sections.AddInReserved(sect); + } + } + + if (addSections) + { + if (_header.NamesSectIndex < _sections.Size()) + { + const CSection § = _sections[_header.NamesSectIndex]; + UInt64 size = sect.GetSize(); + if (size != 0 + && size < ((UInt64)1 << 31) + && (Int64)sect.Offset >= 0) + { + _namesData.Alloc((size_t)size); + RINOK(stream->Seek(sect.Offset, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, _namesData, (size_t)size)); + } + } + + /* + // we will not delete NULL sections, since we have links to section via indexes + for (int i = _sections.Size() - 1; i >= 0; i--) + if (_sections[i].Type == SHT_NULL) + _items.Delete(i); + */ + } + + if (!_allowTail) + { + UInt64 fileSize; + RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); + if (fileSize > _totalSize) + return S_FALSE; + } + + return S_OK; } STDMETHODIMP CHandler::Open(IInStream *inStream, @@ -455,14 +867,19 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, STDMETHODIMP CHandler::Close() { + _totalSize = 0; + _headersError = false; + _inStream.Release(); + _segments.Clear(); _sections.Clear(); + _namesData.Free(); return S_OK; } STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { - *numItems = _sections.Size(); + *numItems = _segments.Size() + _sections.Size(); return S_OK; } @@ -470,15 +887,20 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) - numItems = _sections.Size(); + numItems = _segments.Size() + _sections.Size(); if (numItems == 0) return S_OK; UInt64 totalSize = 0; UInt32 i; for (i = 0; i < numItems; i++) - totalSize += _sections[allFilesMode ? i : indices[i]].PSize; + { + UInt32 index = allFilesMode ? i : indices[i]; + totalSize += (index < _segments.Size()) ? + _segments[index].Size : + _sections[index - _segments.Size()].GetSize(); + } extractCallback->SetTotal(totalSize); UInt64 currentTotalSize = 0; @@ -503,8 +925,19 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; UInt32 index = allFilesMode ? i : indices[i]; - const CSegment &item = _sections[index]; - currentItemSize = item.PSize; + UInt64 offset; + if (index < _segments.Size()) + { + const CSegment &item = _segments[index]; + currentItemSize = item.Size; + offset = item.Offset; + } + else + { + const CSection &item = _sections[index - _segments.Size()]; + currentItemSize = item.GetSize(); + offset = item.Offset; + } CMyComPtr<ISequentialOutStream> outStream; RINOK(extractCallback->GetStream(index, &outStream, askMode)); @@ -512,7 +945,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(_inStream->Seek(item.Offset, STREAM_SEEK_SET, NULL)); + RINOK(_inStream->Seek(offset, STREAM_SEEK_SET, NULL)); streamSpec->Init(currentItemSize); RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); outStream.Release(); @@ -524,10 +957,20 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +STDMETHODIMP CHandler::AllowTail(Int32 allowTail) +{ + _allowTail = IntToBool(allowTail); + return S_OK; +} + +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"ELF", L"", 0, 0xDE, { 0 }, 0, false, CreateArc, 0 }; + { "ELF", "elf", 0, 0xDE, + 4, { 0x7F, 'E', 'L', 'F' }, + 0, + NArcInfoFlags::kPreArc, + CreateArc }; REGISTER_ARC(Elf) diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp index 1c374a44..51064a1a 100755..100644 --- a/CPP/7zip/Archive/FatHandler.cpp +++ b/CPP/7zip/Archive/FatHandler.cpp @@ -6,14 +6,14 @@ #include "../../../C/CpuArch.h" -#include "Common/Buffer.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/MyCom.h" -#include "Common/StringConvert.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/MyCom.h" +#include "../../Common/StringConvert.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -109,6 +109,16 @@ static int GetLog(UInt32 num) return -1; } +static const UInt32 kHeaderSize = 512; + +API_FUNC_static_IsArc IsArc_Fat(const Byte *p, size_t size) +{ + if (size < kHeaderSize) + return k_IsArc_Res_NEED_MORE; + CHeader h; + return h.Parse(p) ? k_IsArc_Res_YES : k_IsArc_Res_NO; +} + bool CHeader::Parse(const Byte *p) { if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) @@ -130,7 +140,7 @@ bool CHeader::Parse(const Byte *p) if (s < 0) return false; SectorsPerClusterLog = (Byte)s; - ClusterSizeLog = SectorSizeLog + SectorsPerClusterLog; + ClusterSizeLog = (Byte)(SectorSizeLog + SectorsPerClusterLog); } NumReservedSectors = Get16(p + 14); @@ -151,7 +161,8 @@ bool CHeader::Parse(const Byte *p) } else { - if (codeOffset < 62) + // Some FAT12s don't contain VolFields + if (codeOffset < 62 - 24) return false; NumFatBits = 0; UInt32 mask = (1 << (SectorSizeLog - 5)) - 1; @@ -174,6 +185,7 @@ bool CHeader::Parse(const Byte *p) // memcpy(OemName, p + 3, 5); + int curOffset = 36; p += 36; if (IsFat32()) { @@ -192,13 +204,23 @@ bool CHeader::Parse(const Byte *p) if (p[i] != 0) return false; p += 28; + curOffset += 28; } // DriveNumber = p[0]; - VolFieldsDefined = (p[2] == 0x29); // ExtendedBootSig - VolId = Get32(p + 3); - // memcpy(VolName, p + 7, 11); - // memcpy(FileSys, p + 18, 8); + VolFieldsDefined = false; + if (codeOffset >= curOffset + 3) + { + VolFieldsDefined = (p[2] == 0x29); // ExtendedBootSig + if (VolFieldsDefined) + { + if (codeOffset < curOffset + 26) + return false; + VolId = Get32(p + 3); + // memcpy(VolName, p + 7, 11); + // memcpy(FileSys, p + 18, 8); + } + } if (NumFatSectors == 0) return false; @@ -214,7 +236,7 @@ bool CHeader::Parse(const Byte *p) { if (NumFatBits == 32) return false; - NumFatBits = (numClusters < 0xFF5) ? 12: 16; + NumFatBits = (Byte)(numClusters < 0xFF5 ? 12 : 16); BadCluster &= ((1 << NumFatBits) - 1); } else if (NumFatBits != 32) @@ -258,7 +280,7 @@ static int CopyAndTrim(char *dest, const char *src, int size, bool toLower) { char c = dest[i]; if (c >= 'A' && c <= 'Z') - dest[i] = c + 0x20; + dest[i] = (char)(c + 0x20); } for (i = size - 1; i >= 0 && dest[i] == ' '; i--); return i + 1; @@ -313,6 +335,8 @@ struct CDatabase CByteBuffer ByteBuf; UInt64 NumCurUsedBytes; + UInt64 PhySize; + CDatabase(): Fat(0) {} ~CDatabase() { ClearAndClose(); } @@ -340,6 +364,7 @@ HRESULT CDatabase::SeekToSector(UInt32 sector) void CDatabase::Clear() { + PhySize = 0; VolItemDefined = false; NumDirClusters = 0; NumCurUsedBytes = 0; @@ -386,7 +411,11 @@ UString CDatabase::GetItemPath(Int32 index) const if (index < 0) return name; item = &Items[index]; - name = item->GetName() + WCHAR_PATH_SEPARATOR + name; + name.InsertAtFront(WCHAR_PATH_SEPARATOR); + if (item->UName.IsEmpty()) + name.Insert(0, item->GetShortName()); + else + name.Insert(0, item->UName); } } @@ -417,7 +446,7 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level) RINOK(SeekToSector(Header.RootDirSector)); } - ByteBuf.SetCapacity(blockSize); + ByteBuf.Alloc(blockSize); UString curName; int checkSum = -1; int numLongRecords = -1; @@ -516,7 +545,7 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level) { Byte sum = 0; for (int i = 0; i < 11; i++) - sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i]; + sum = (Byte)(((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i]); if (sum == checkSum) item.UName = curName; } @@ -578,7 +607,6 @@ HRESULT CDatabase::Open() Clear(); bool numFreeClustersDefined = false; { - static const UInt32 kHeaderSize = 512; Byte buf[kHeaderSize]; RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)); if (!Header.Parse(buf)) @@ -618,7 +646,7 @@ HRESULT CDatabase::Open() if (Header.NumFatBits == 32) { const UInt32 kBufSize = (1 << 15); - byteBuf.SetCapacity(kBufSize); + byteBuf.Alloc(kBufSize); for (UInt32 i = 0; i < Header.FatSize;) { UInt32 size = Header.FatSize - i; @@ -656,7 +684,7 @@ HRESULT CDatabase::Open() { const UInt32 kBufSize = (UInt32)Header.CalcFatSizeInSectors() << Header.SectorSizeLog; NumCurUsedBytes += kBufSize; - byteBuf.SetCapacity(kBufSize); + byteBuf.Alloc(kBufSize); Byte *p = byteBuf; RINOK(ReadStream_FALSE(InStream, p, kBufSize)); UInt32 fatSize = Header.FatSize; @@ -682,7 +710,10 @@ HRESULT CDatabase::Open() if ((Fat[0] & 0xFF) != Header.MediaType) return S_FALSE; - return ReadDir(-1, Header.RootCluster, 0); + RINOK(ReadDir(-1, Header.RootCluster, 0)); + + PhySize = Header.GetPhySize(); + return S_OK; } class CHandler: @@ -710,7 +741,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) streamSpec->Size = item.Size; UInt32 numClusters = Header.GetNumClusters(item.Size); - streamSpec->Vector.Reserve(numClusters); + streamSpec->Vector.ClearAndReserve(numClusters); UInt32 cluster = item.Cluster; UInt32 size = item.Size; @@ -726,7 +757,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) { if (!Header.IsValidCluster(cluster)) return S_FALSE; - streamSpec->Vector.Add(cluster - 2); + streamSpec->Vector.AddInReserved(cluster - 2); cluster = Fat[cluster]; if (size <= clusterSize) break; @@ -740,17 +771,17 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidATime, VT_FILETIME}, - { NULL, kpidAttrib, VT_UI8}, - { NULL, kpidShortName, VT_BSTR} + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidAttrib, + kpidShortName }; enum @@ -761,11 +792,10 @@ enum // kpidFileSysType }; -STATPROPSTG kArcProps[] = +static const STATPROPSTG kArcProps[] = { { NULL, kpidFileSystem, VT_BSTR}, { NULL, kpidClusterSize, VT_UI4}, - { NULL, kpidPhySize, VT_UI8}, { NULL, kpidFreeSpace, VT_UI8}, { NULL, kpidHeadersSize, VT_UI8}, { NULL, kpidMTime, VT_FILETIME}, @@ -819,16 +849,20 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { case kpidFileSystem: { - wchar_t s[32] = { L'F', L'A', L'T' }; + char s[16]; + s[0] = 'F'; + s[1] = 'A'; + s[2] = 'T'; ConvertUInt32ToString(Header.NumFatBits, s + 3); prop = s; break; } case kpidClusterSize: prop = Header.ClusterSize(); break; - case kpidPhySize: prop = Header.GetPhySize(); break; + case kpidPhySize: prop = PhySize; break; case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break; case kpidHeadersSize: prop = GetHeadersSize(); break; case kpidMTime: if (VolItemDefined) FatTimeToProp(VolItem.MTime, 0, prop); break; + case kpidShortComment: case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break; case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break; case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break; @@ -901,7 +935,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = Items.Size(); if (numItems == 0) @@ -986,10 +1020,14 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"FAT", L"fat img", 0, 0xDA, { 0x55, 0xAA }, 2, false, CreateArc, 0 }; + { "FAT", "fat img", 0, 0xDA, + 2, { 0x55, 0xAA }, + 0x1FE, + 0, + CreateArc, NULL, IsArc_Fat }; REGISTER_ARC(Fat) diff --git a/CPP/7zip/Archive/FlvHandler.cpp b/CPP/7zip/Archive/FlvHandler.cpp index a22c29e3..3bb4620b 100755..100644 --- a/CPP/7zip/Archive/FlvHandler.cpp +++ b/CPP/7zip/Archive/FlvHandler.cpp @@ -4,13 +4,13 @@ #include "../../../C/CpuArch.h" -#include "Common/Buffer.h" -#include "Common/ComTry.h" -// #include "Common/Defs.h" -#include "Common/MyString.h" +#include "../../Common/ComTry.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/MyString.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" +#include "../Common/InBuffer.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamObjects.h" @@ -29,9 +29,9 @@ namespace NArchive { namespace NFlv { static const UInt32 kFileSizeMax = (UInt32)1 << 30; -static const int kNumChunksMax = (UInt32)1 << 23; +static const UInt32 kNumChunksMax = (UInt32)1 << 23; -const UInt32 kTagHeaderSize = 11; +static const UInt32 kTagHeaderSize = 11; static const Byte kFlag_Video = 1; static const Byte kFlag_Audio = 4; @@ -39,13 +39,11 @@ static const Byte kFlag_Audio = 4; static const Byte kType_Audio = 8; static const Byte kType_Video = 9; static const Byte kType_Meta = 18; -static const int kNumTypes = 19; +static const unsigned kNumTypes = 19; struct CItem { - UInt32 Offset; - UInt32 Size; - // UInt32 Time; + CByteBuffer Data; Byte Type; }; @@ -55,7 +53,7 @@ struct CItem2 Byte SubType; Byte Props; bool SameSubTypes; - int NumChunks; + unsigned NumChunks; size_t Size; CReferenceBuf *BufSpec; @@ -69,10 +67,12 @@ class CHandler: public IInArchiveGetStream, public CMyUnknownImp { - int _isRaw; CMyComPtr<IInStream> _stream; CObjectVector<CItem2> _items2; // CByteBuffer _metadata; + bool _isRaw; + UInt64 _phySize; + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); AString GetComment(); public: @@ -81,76 +81,64 @@ public: STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidSize, VT_UI8}, - { NULL, kpidNumBlocks, VT_UI4}, - { NULL, kpidComment, VT_BSTR} + kpidSize, + kpidNumBlocks, + kpidComment }; -/* -STATPROPSTG kArcProps[] = -{ - { NULL, kpidComment, VT_BSTR} -}; -*/ - IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO +IMP_IInArchive_ArcProps_NO_Table static const char *g_AudioTypes[16] = { - "pcm", - "adpcm", - "mp3", - "pcm_le", - "nellymoser16", - "nellymoser8", - "nellymoser", - "g711a", - "g711m", - "audio9", - "aac", - "speex", - "audio12", - "audio13", - "mp3", - "audio15" + "pcm" + , "adpcm" + , "mp3" + , "pcm_le" + , "nellymoser16" + , "nellymoser8" + , "nellymoser" + , "g711a" + , "g711m" + , "audio9" + , "aac" + , "speex" + , "audio12" + , "audio13" + , "mp3" + , "audio15" }; static const char *g_VideoTypes[16] = { - "video0", - "jpeg", - "h263", - "screen", - "vp6", - "vp6alpha", - "screen2", - "avc", - "video8", - "video9", - "video10", - "video11", - "video12", - "video13", - "video14", - "video15" + "video0" + , "jpeg" + , "h263" + , "screen" + , "vp6" + , "vp6alpha" + , "screen2" + , "avc" + , "video8" + , "video9" + , "video10" + , "video11" + , "video12" + , "video13" + , "video14" + , "video15" }; static const char *g_Rates[4] = { - "5.5 kHz", - "11 kHz", - "22 kHz", - "44 kHz" + "5.5 kHz" + , "11 kHz" + , "22 kHz" + , "44 kHz" }; -static void MyStrCat(char *d, const char *s) -{ - MyStringCopy(d + MyStringLen(d), s); -} - STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { NWindows::NCOM::CPropVariant prop; @@ -170,13 +158,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidComment: { char sz[64]; - MyStringCopy(sz, (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) ); + char *s = MyStpCpy(sz, (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) ); if (item.IsAudio()) { - MyStrCat(sz, " "); - MyStrCat(sz, g_Rates[(item.Props >> 2) & 3]); - MyStrCat(sz, (item.Props & 2) ? " 16-bit" : " 8-bit"); - MyStrCat(sz, (item.Props & 1) ? " stereo" : " mono"); + *s++ = ' '; + s = MyStpCpy(s, g_Rates[(item.Props >> 2) & 3]); + s = MyStpCpy(s, (item.Props & 2) ? " 16-bit" : " 8-bit"); + s = MyStpCpy(s, (item.Props & 1) ? " stereo" : " mono"); } prop = sz; break; @@ -190,7 +178,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val AString CHandler::GetComment() { const Byte *p = _metadata; - size_t size = _metadata.GetCapacity(); + size_t size = _metadata.Size(); AString res; if (size > 0) { @@ -264,24 +252,25 @@ AString CHandler::GetComment() return res; } +*/ + STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { - COM_TRY_BEGIN + // COM_TRY_BEGIN NWindows::NCOM::CPropVariant prop; switch(propID) { - case kpidComment: prop = GetComment(); break; + // case kpidComment: prop = GetComment(); break; + case kpidPhySize: prop = (UInt64)_phySize; break; + case kpidIsNotArcType: prop = true; break; } prop.Detach(value); return S_OK; - COM_TRY_END + // COM_TRY_END } -*/ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) { - CRecordVector<CItem> items; - const UInt32 kHeaderSize = 13; Byte header[kHeaderSize]; RINOK(ReadStream_FALSE(stream, header, kHeaderSize)); @@ -291,69 +280,51 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) header[3] != 1 || (header[4] & 0xFA) != 0) return S_FALSE; - UInt32 offset = Get32(header + 5); + UInt64 offset = Get32(header + 5); if (offset != 9 || Get32(header + 9) != 0) return S_FALSE; - offset += 4; + offset = kHeaderSize; - CByteBuffer inBuf; - size_t fileSize; - { - UInt64 fileSize64; - RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize64)); - if (fileSize64 > kFileSizeMax) - return S_FALSE; - - if (callback) - RINOK(callback->SetTotal(NULL, &fileSize64)) - - RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); - fileSize = (size_t)fileSize64; - inBuf.SetCapacity(fileSize); - for (size_t pos = 0; pos < fileSize;) - { - UInt64 offset64 = pos; - if (callback) - RINOK(callback->SetCompleted(NULL, &offset64)) - size_t rem = MyMin(fileSize - pos, (size_t)(1 << 20)); - RINOK(ReadStream_FALSE(stream, inBuf + pos, rem)); - pos += rem; - } - } + CInBuffer inBuf; + if (!inBuf.Create(1 << 15)) + return E_OUTOFMEMORY; + inBuf.SetStream(stream); + CObjectVector<CItem> items; int lasts[kNumTypes]; - int i; + unsigned i; for (i = 0; i < kNumTypes; i++) lasts[i] = -1; - while (offset < fileSize) + _phySize = offset; + for (;;) { + Byte buf[kTagHeaderSize]; CItem item; - item.Offset = offset; - const Byte *buf = inBuf + offset; - offset += kTagHeaderSize; - if (offset > fileSize) - return S_FALSE; - + if (inBuf.ReadBytes(buf, kTagHeaderSize) != kTagHeaderSize) + break; item.Type = buf[0]; UInt32 size = Get24(buf + 1); if (size < 1) - return S_FALSE; + break; // item.Time = Get24(buf + 4); // item.Time |= (UInt32)buf[7] << 24; if (Get24(buf + 8) != 0) // streamID - return S_FALSE; + break; UInt32 curSize = kTagHeaderSize + size + 4; - item.Size = curSize; - - offset += curSize - kTagHeaderSize; - if (offset > fileSize) - return S_FALSE; - - if (Get32(buf + kTagHeaderSize + size) != kTagHeaderSize + size) - return S_FALSE; + item.Data.Alloc(curSize); + memcpy(item.Data, buf, kTagHeaderSize); + if (inBuf.ReadBytes(item.Data + kTagHeaderSize, size) != size) + break; + if (inBuf.ReadBytes(item.Data + kTagHeaderSize + size, 4) != 4) + break; + if (Get32(item.Data + kTagHeaderSize + size) != kTagHeaderSize + size) + break; + + offset += curSize; + // printf("\noffset = %6X type = %2d time = %6d size = %6d", (UInt32)offset, item.Type, item.Time, item.Size); if (item.Type == kType_Meta) @@ -363,20 +334,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) else { if (item.Type != kType_Audio && item.Type != kType_Video) - return S_FALSE; + break; if (items.Size() >= kNumChunksMax) return S_FALSE; Byte firstByte = buf[kTagHeaderSize]; Byte subType, props; if (item.Type == kType_Audio) { - subType = firstByte >> 4; - props = firstByte & 0xF; + subType = (Byte)(firstByte >> 4); + props = (Byte)(firstByte & 0xF); } else { - subType = firstByte & 0xF; - props = firstByte >> 4; + subType = (Byte)(firstByte & 0xF); + props = (Byte)(firstByte >> 4); } int last = lasts[item.Type]; if (last < 0) @@ -401,7 +372,14 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) } items.Add(item); } + _phySize = offset; + if (callback && (items.Size() & 0xFF) == 0) + { + RINOK(callback->SetCompleted(NULL, &offset)) + } } + if (items.IsEmpty()) + return S_FALSE; _isRaw = (_items2.Size() == 1); for (i = 0; i < _items2.Size(); i++) @@ -412,12 +390,12 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) { if (!item2.SameSubTypes) return S_FALSE; - itemBuf.SetCapacity((size_t)item2.Size - (kTagHeaderSize + 4 + 1) * item2.NumChunks); + itemBuf.Alloc((size_t)item2.Size - (size_t)(kTagHeaderSize + 4 + 1) * item2.NumChunks); item2.Size = 0; } else { - itemBuf.SetCapacity(kHeaderSize + (size_t)item2.Size); + itemBuf.Alloc(kHeaderSize + (size_t)item2.Size); memcpy(itemBuf, header, kHeaderSize); itemBuf[4] = item2.IsAudio() ? kFlag_Audio : kFlag_Video; item2.Size = kHeaderSize; @@ -428,8 +406,8 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) { const CItem &item = items[i]; CItem2 &item2 = _items2[lasts[item.Type]]; - size_t size = item.Size; - const Byte *src = inBuf + item.Offset; + size_t size = item.Data.Size(); + const Byte *src = item.Data; if (_isRaw) { src += kTagHeaderSize + 1; @@ -464,6 +442,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal STDMETHODIMP CHandler::Close() { + _phySize = 0; _stream.Release(); _items2.Clear(); // _metadata.SetCapacity(0); @@ -480,7 +459,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items2.Size(); if (numItems == 0) @@ -514,7 +493,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->PrepareOperation(askMode)); if (outStream) { - RINOK(WriteStream(outStream, item.BufSpec->Buf, item.BufSpec->Buf.GetCapacity())); + RINOK(WriteStream(outStream, item.BufSpec->Buf, item.BufSpec->Buf.Size())); } RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); } @@ -534,10 +513,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"FLV", L"flv", 0, 0xD6, { 'F', 'L', 'V' }, 3, false, CreateArc, 0 }; + { "FLV", "flv", 0, 0xD6, + 4, { 'F', 'L', 'V', 1, }, + 0, + 0, + CreateArc }; REGISTER_ARC(Flv) diff --git a/CPP/7zip/Archive/GzHandler.cpp b/CPP/7zip/Archive/GzHandler.cpp index ede6b01b..69b3c3be 100755..100644 --- a/CPP/7zip/Archive/GzHandler.cpp +++ b/CPP/7zip/Archive/GzHandler.cpp @@ -2,13 +2,16 @@ #include "StdAfx.h" +// #include <stdio.h> + #include "../../../C/CpuArch.h" -#include "Common/ComTry.h" -#include "Common/StringConvert.h" +#include "../../Common/ComTry.h" +#include "../../Common/Defs.h" +#include "../../Common/StringConvert.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" @@ -26,13 +29,19 @@ using namespace NWindows; +using namespace NCompress; +using namespace NDeflate; + namespace NArchive { namespace NGz { -static const UInt16 kSignature = 0x8B1F; + static const Byte kSignature_0 = 0x1F; + static const Byte kSignature_1 = 0x8B; + static const Byte kSignature_2 = 8; // NCompressionMethod::kDeflate + + // Latest versions of gzip program don't write comment field to gz archive. + // We also don't write comment field to gz archive. -namespace NHeader -{ namespace NFlags { const Byte kIsText = 1 << 0; @@ -40,6 +49,7 @@ namespace NHeader const Byte kExtra = 1 << 2; const Byte kName = 1 << 3; const Byte kComment = 1 << 4; + const Byte kReserved = 0xE0; } namespace NExtraFlags @@ -48,11 +58,6 @@ namespace NHeader const Byte kFastest = 4; } - namespace NCompressionMethod - { - const Byte kDeflate = 8; - } - namespace NHostOS { enum EEnum @@ -79,30 +84,29 @@ namespace NHeader kUnknown = 255 }; } -} static const char *kHostOSes[] = { - "FAT", - "AMIGA", - "VMS", - "Unix", - "VM/CMS", - "Atari", - "HPFS", - "Macintosh", - "Z-System", - "CP/M", - "TOPS-20", - "NTFS", - "SMS/QDOS", - "Acorn", - "VFAT", - "MVS", - "BeOS", - "Tandem", - "OS/400", - "OS/X" + "FAT" + , "AMIGA" + , "VMS" + , "Unix" + , "VM/CMS" + , "Atari" + , "HPFS" + , "Macintosh" + , "Z-System" + , "CP/M" + , "TOPS-20" + , "NTFS" + , "SMS/QDOS" + , "Acorn" + , "VFAT" + , "MVS" + , "BeOS" + , "Tandem" + , "OS/400" + , "OS/X" }; static const char *kUnknownOS = "Unknown"; @@ -111,7 +115,6 @@ class CItem { bool TestFlag(Byte flag) const { return (Flags & flag) != 0; } public: - Byte Method; Byte Flags; Byte ExtraFlags; Byte HostOS; @@ -123,11 +126,12 @@ public: AString Comment; // CByteBuffer Extra; - // bool IsText() const { return TestFlag(NHeader::NFlags::kIsText); } - bool HeaderCrcIsPresent() const { return TestFlag(NHeader::NFlags::kCrc); } - bool ExtraFieldIsPresent() const { return TestFlag(NHeader::NFlags::kExtra); } - bool NameIsPresent() const { return TestFlag(NHeader::NFlags::kName); } - bool CommentIsPresent() const { return TestFlag(NHeader::NFlags::kComment); } + // bool IsText() const { return TestFlag(NFlags::kIsText); } + bool HeaderCrcIsPresent() const { return TestFlag(NFlags::kCrc); } + bool ExtraFieldIsPresent() const { return TestFlag(NFlags::kExtra); } + bool NameIsPresent() const { return TestFlag(NFlags::kName); } + bool CommentIsPresent() const { return TestFlag(NFlags::kComment); } + bool IsSupported() const { return (Flags & NFlags::kReserved) == 0; } void Clear() { @@ -136,48 +140,48 @@ public: // Extra.SetCapacity(0); } - HRESULT ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream); - HRESULT ReadFooter1(NCompress::NDeflate::NDecoder::CCOMCoder *stream); + HRESULT ReadHeader(NDecoder::CCOMCoder *stream); + HRESULT ReadFooter1(NDecoder::CCOMCoder *stream); HRESULT ReadFooter2(ISequentialInStream *stream); HRESULT WriteHeader(ISequentialOutStream *stream); HRESULT WriteFooter(ISequentialOutStream *stream); }; -static HRESULT ReadBytes(NCompress::NDeflate::NDecoder::CCOMCoder *stream, Byte *data, UInt32 size) +static HRESULT ReadBytes(NDecoder::CCOMCoder *stream, Byte *data, UInt32 size) { for (UInt32 i = 0; i < size; i++) - data[i] = stream->ReadByte(); + data[i] = stream->ReadAlignedByte(); return stream->InputEofError() ? S_FALSE : S_OK; } -static HRESULT SkipBytes(NCompress::NDeflate::NDecoder::CCOMCoder *stream, UInt32 size) +static HRESULT SkipBytes(NDecoder::CCOMCoder *stream, UInt32 size) { for (UInt32 i = 0; i < size; i++) - stream->ReadByte(); + stream->ReadAlignedByte(); return stream->InputEofError() ? S_FALSE : S_OK; } -static HRESULT ReadUInt16(NCompress::NDeflate::NDecoder::CCOMCoder *stream, UInt16 &value /* , UInt32 &crc */) +static HRESULT ReadUInt16(NDecoder::CCOMCoder *stream, UInt32 &value /* , UInt32 &crc */) { value = 0; for (int i = 0; i < 2; i++) { - Byte b = stream->ReadByte(); + Byte b = stream->ReadAlignedByte(); if (stream->InputEofError()) return S_FALSE; // crc = CRC_UPDATE_BYTE(crc, b); - value |= (UInt16(b) << (8 * i)); + value |= ((UInt32)(b) << (8 * i)); } return S_OK; } -static HRESULT ReadString(NCompress::NDeflate::NDecoder::CCOMCoder *stream, AString &s, UInt32 limit /* , UInt32 &crc */) +static HRESULT ReadString(NDecoder::CCOMCoder *stream, AString &s, size_t limit /* , UInt32 &crc */) { s.Empty(); - for (UInt32 i = 0; i < limit; i++) + for (size_t i = 0; i < limit; i++) { - Byte b = stream->ReadByte(); + Byte b = stream->ReadAlignedByte(); if (stream->InputEofError()) return S_FALSE; // crc = CRC_UPDATE_BYTE(crc, b); @@ -188,7 +192,134 @@ static HRESULT ReadString(NCompress::NDeflate::NDecoder::CCOMCoder *stream, AStr return S_FALSE; } -HRESULT CItem::ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream) +static UInt32 Is_Deflate(const Byte *p, size_t size) +{ + if (size < 1) + return k_IsArc_Res_NEED_MORE; + Byte b = *p; + p++; + size--; + unsigned type = ((unsigned)b >> 1) & 3; + if (type == 3) + return k_IsArc_Res_NO; + if (type == 0) + { + // Stored (uncompreessed data) + if ((b >> 3) != 0) + return k_IsArc_Res_NO; + if (size < 4) + return k_IsArc_Res_NEED_MORE; + if (GetUi16(p) != (UInt16)~GetUi16(p + 2)) + return k_IsArc_Res_NO; + } + else if (type == 2) + { + // Dynamic Huffman + if (size < 1) + return k_IsArc_Res_NEED_MORE; + if ((*p & 0x1F) + 1 > 30) // numDistLevels + return k_IsArc_Res_NO; + } + return k_IsArc_Res_YES; +} + +static unsigned kNameMaxLen = 1 << 12; +static unsigned kCommentMaxLen = 1 << 16; + +API_FUNC_static_IsArc IsArc_Gz(const Byte *p, size_t size) +{ + if (size < 10) + return k_IsArc_Res_NEED_MORE; + if (p[0] != kSignature_0 || + p[1] != kSignature_1 || + p[2] != kSignature_2) + return k_IsArc_Res_NO; + + Byte flags = p[3]; + if ((flags & NFlags::kReserved) != 0) + return k_IsArc_Res_NO; + + Byte extraFlags = p[8]; + // maybe that flag can have another values for some gz archives? + if (extraFlags != 0 && + extraFlags != NExtraFlags::kMaximum && + extraFlags != NExtraFlags::kFastest) + return k_IsArc_Res_NO; + + size -= 10; + p += 10; + + if ((flags & NFlags::kExtra) != 0) + { + if (size < 2) + return k_IsArc_Res_NEED_MORE; + unsigned xlen = GetUi16(p); + size -= 2; + p += 2; + while (xlen != 0) + { + if (xlen < 4) + return k_IsArc_Res_NO; + if (size < 4) + return k_IsArc_Res_NEED_MORE; + unsigned len = GetUi16(p + 2); + size -= 4; + xlen -= 4; + p += 4; + if (len > xlen) + return k_IsArc_Res_NO; + if (len > size) + return k_IsArc_Res_NEED_MORE; + size -= len; + xlen -= len; + p += len; + } + } + + if ((flags & NFlags::kName) != 0) + { + size_t limit = kNameMaxLen; + if (limit > size) + limit = size; + size_t i; + for (i = 0; i < limit && p[i] != 0; i++); + if (i == size) + return k_IsArc_Res_NEED_MORE; + if (i == limit) + return k_IsArc_Res_NO; + i++; + p += i; + size -= i; + } + + if ((flags & NFlags::kComment) != 0) + { + size_t limit = kCommentMaxLen; + if (limit > size) + limit = size; + size_t i; + for (i = 0; i < limit && p[i] != 0; i++); + if (i == size) + return k_IsArc_Res_NEED_MORE; + if (i == limit) + return k_IsArc_Res_NO; + i++; + p += i; + size -= i; + } + + if ((flags & NFlags::kCrc) != 0) + { + if (size < 2) + return k_IsArc_Res_NEED_MORE; + p += 2; + size -= 2; + } + + return Is_Deflate(p, size); +} + +HRESULT CItem::ReadHeader(NDecoder::CCOMCoder *stream) { Clear(); @@ -198,15 +329,15 @@ HRESULT CItem::ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream) RINOK(ReadBytes(stream, buf, 10)); - if (GetUi16(buf) != kSignature) + if (buf[0] != kSignature_0 || + buf[1] != kSignature_1 || + buf[2] != kSignature_2) return S_FALSE; - Method = buf[2]; - - if (Method != NHeader::NCompressionMethod::kDeflate) + Flags = buf[3]; + if (!IsSupported()) return S_FALSE; - Flags = buf[3]; Time = Get32(buf + 4); ExtraFlags = buf[8]; HostOS = buf[9]; @@ -215,21 +346,21 @@ HRESULT CItem::ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream) if (ExtraFieldIsPresent()) { - UInt16 extraSize; - RINOK(ReadUInt16(stream, extraSize /* , crc */)); - RINOK(SkipBytes(stream, extraSize)); - // Extra.SetCapacity(extraSize); - // RINOK(ReadStream_FALSE(stream, Extra, extraSize)); - // crc = CrcUpdate(crc, Extra, extraSize); + UInt32 xlen; + RINOK(ReadUInt16(stream, xlen /* , crc */)); + RINOK(SkipBytes(stream, xlen)); + // Extra.SetCapacity(xlen); + // RINOK(ReadStream_FALSE(stream, Extra, xlen)); + // crc = CrcUpdate(crc, Extra, xlen); } if (NameIsPresent()) - RINOK(ReadString(stream, Name, (1 << 10) /* , crc */)); + RINOK(ReadString(stream, Name, kNameMaxLen /* , crc */)); if (CommentIsPresent()) - RINOK(ReadString(stream, Comment, (1 << 16) /* , crc */)); + RINOK(ReadString(stream, Comment, kCommentMaxLen /* , crc */)); if (HeaderCrcIsPresent()) { - UInt16 headerCRC; + UInt32 headerCRC; // UInt32 dummy = 0; RINOK(ReadUInt16(stream, headerCRC /* , dummy */)); /* @@ -240,7 +371,7 @@ HRESULT CItem::ReadHeader(NCompress::NDeflate::NDecoder::CCOMCoder *stream) return stream->InputEofError() ? S_FALSE : S_OK; } -HRESULT CItem::ReadFooter1(NCompress::NDeflate::NDecoder::CCOMCoder *stream) +HRESULT CItem::ReadFooter1(NDecoder::CCOMCoder *stream) { Byte buf[8]; RINOK(ReadBytes(stream, buf, 8)); @@ -261,10 +392,11 @@ HRESULT CItem::ReadFooter2(ISequentialInStream *stream) HRESULT CItem::WriteHeader(ISequentialOutStream *stream) { Byte buf[10]; - SetUi16(buf, kSignature); - buf[2] = Method; - buf[3] = Flags & NHeader::NFlags::kName; - // buf[3] |= NHeader::NFlags::kCrc; + buf[0] = kSignature_0; + buf[1] = kSignature_1; + buf[2] = kSignature_2; + buf[3] = (Byte)(Flags & NFlags::kName); + // buf[3] |= NFlags::kCrc; SetUi32(buf + 4, Time); buf[8] = ExtraFlags; buf[9] = HostOS; @@ -272,8 +404,8 @@ HRESULT CItem::WriteHeader(ISequentialOutStream *stream) // crc = CrcUpdate(CRC_INIT_VAL, buf, 10); if (NameIsPresent()) { - // crc = CrcUpdate(crc, (const char *)Name, Name.Length() + 1); - RINOK(WriteStream(stream, (const char *)Name, Name.Length() + 1)); + // crc = CrcUpdate(crc, (const char *)Name, Name.Len() + 1); + RINOK(WriteStream(stream, (const char *)Name, Name.Len() + 1)); } // SetUi16(buf, (UInt16)CRC_GET_DIGEST(crc)); // RINOK(WriteStream(stream, buf, 2)); @@ -296,54 +428,93 @@ class CHandler: public CMyUnknownImp { CItem _item; - UInt64 _startPosition; - UInt64 _headerSize; + + bool _isArc; + bool _needSeekToStart; + bool _dataAfterEnd; + bool _needMoreInput; + + bool _packSize_Defined; + bool _unpackSize_Defined; + bool _numStreams_Defined; + UInt64 _packSize; - bool _packSizeDefined; + UInt64 _unpackSize; // real unpack size (NOT from footer) + UInt64 _numStreams; + UInt64 _headerSize; // only start header (without footer) + CMyComPtr<IInStream> _stream; CMyComPtr<ICompressCoder> _decoder; - NCompress::NDeflate::NDecoder::CCOMCoder *_decoderSpec; + NDecoder::CCOMCoder *_decoderSpec; CSingleMethodProps _props; public: - MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties) + MY_UNKNOWN_IMP4( + IInArchive, + IArchiveOpenSeq, + IOutArchive, + ISetProperties) INTERFACE_IInArchive(;) INTERFACE_IOutArchive(;) STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps); + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); CHandler() { - _decoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder; + _decoderSpec = new NDecoder::CCOMCoder; _decoder = _decoderSpec; } }; -static STATPROPSTG const kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidHostOS, VT_BSTR}, - { NULL, kpidCRC, VT_UI4} - // { NULL, kpidComment, VT_BSTR} -} -; + kpidPath, + kpidSize, + kpidPackSize, + kpidMTime, + kpidHostOS, + kpidCRC + // kpidComment +}; + +static const Byte kArcProps[] = +{ + kpidHeadersSize, + kpidNumStreams +}; + IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table +IMP_IInArchive_ArcProps STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { + COM_TRY_BEGIN NCOM::CPropVariant prop; - switch(propID) + switch (propID) { - case kpidPhySize: if (_packSizeDefined) prop = _packSize; break; + case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; + case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break; + case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break; + case kpidHeadersSize: if (_headerSize != 0) prop = _headerSize; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; + if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; + prop = v; + break; + } + case kpidName: + if (_item.NameIsPresent()) + prop = MultiByteToUnicodeString(_item.Name, CP_ACP) + L".gz"; + break; } prop.Detach(value); return S_OK; + COM_TRY_END } @@ -353,11 +524,11 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) + NCOM::CPropVariant prop; + switch (propID) { case kpidPath: if (_item.NameIsPresent()) @@ -365,7 +536,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIA break; // case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break; case kpidMTime: - { if (_item.Time != 0) { FILETIME utc; @@ -373,10 +543,21 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIA prop = utc; } break; + case kpidSize: + { + if (_unpackSize_Defined) + prop = _unpackSize; + else if (_stream) + prop = (UInt64)_item.Size32; + break; } - case kpidSize: if (_stream) prop = (UInt64)_item.Size32; break; - case kpidPackSize: if (_packSizeDefined) prop = _packSize; break; - case kpidHostOS: prop = (_item.HostOS < sizeof(kHostOSes) / sizeof(kHostOSes[0])) ? + case kpidPackSize: + { + if (_packSize_Defined || _stream) + prop = _packSize; + break; + } + case kpidHostOS: prop = (_item.HostOS < ARRAY_SIZE(kHostOSes)) ? kHostOSes[_item.HostOS] : kUnknownOS; break; case kpidCRC: if (_stream) prop = _item.Crc; break; } @@ -385,56 +566,81 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIA COM_TRY_END } -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) +class CCompressProgressInfoImp: + public ICompressProgressInfo, + public CMyUnknownImp { - COM_TRY_BEGIN - HRESULT res; - try + CMyComPtr<IArchiveOpenCallback> Callback; +public: + UInt64 Offset; + MY_UNKNOWN_IMP1(ICompressProgressInfo) + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); + void Init(IArchiveOpenCallback *callback) { Callback = callback; } +}; + +STDMETHODIMP CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */) +{ + if (Callback) { - RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPosition)); - res = OpenSeq(stream); - if (res == S_OK) - { - UInt64 endPos; - res = stream->Seek(-8, STREAM_SEEK_END, &endPos); - _packSize = endPos + 8 - _startPosition; - _packSizeDefined = true; - if (res == S_OK) - { - res = _item.ReadFooter2(stream); - _stream = stream; - } - } + UInt64 files = 0; + UInt64 value = Offset + *inSize; + return Callback->SetCompleted(&files, &value); } - catch(...) { res = S_FALSE; } - if (res != S_OK) - Close(); - return res; + return S_OK; +} + +/* +*/ + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) +{ + COM_TRY_BEGIN + RINOK(OpenSeq(stream)); + _isArc = false; + UInt64 endPos; + RINOK(stream->Seek(-8, STREAM_SEEK_END, &endPos)); + _packSize = endPos + 8; + RINOK(_item.ReadFooter2(stream)); + _stream = stream; + _isArc = true; + _needSeekToStart = true; + return S_OK; COM_TRY_END } STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) { COM_TRY_BEGIN - HRESULT res; try { Close(); _decoderSpec->SetInStream(stream); _decoderSpec->InitInStream(true); - res = _item.ReadHeader(_decoderSpec); + RINOK(_item.ReadHeader(_decoderSpec)); + if (_decoderSpec->InputEofError()) + return S_FALSE; _headerSize = _decoderSpec->GetInputProcessedSize(); + _isArc = true; + return S_OK; } - catch(...) { res = S_FALSE; } - if (res != S_OK) - Close(); - return res; + catch(const CInBufferException &e) { return e.ErrorCode; } COM_TRY_END } STDMETHODIMP CHandler::Close() { - _packSizeDefined = false; + _isArc = false; + _needSeekToStart = false; + _dataAfterEnd = false; + _needMoreInput = false; + + _packSize_Defined = false; + _unpackSize_Defined = false; + _numStreams_Defined = false; + + _packSize = 0; + _headerSize = 0; + _stream.Release(); _decoderSpec->ReleaseInStream(); return S_OK; @@ -446,13 +652,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_BEGIN if (numItems == 0) return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; - if (_stream) - extractCallback->SetTotal(_packSize); - UInt64 currentTotalPacked = 0; - RINOK(extractCallback->SetCompleted(¤tTotalPacked)); + // if (_stream) extractCallback->SetTotal(_packSize); + // UInt64 currentTotalPacked = 0; + // RINOK(extractCallback->SetCompleted(¤tTotalPacked)); CMyComPtr<ISequentialOutStream> realOutStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : @@ -473,71 +678,166 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, true); - if (_stream) + bool needReadFirstItem = _needSeekToStart; + + if (_needSeekToStart) { - RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL)); + if (!_stream) + return E_FAIL; + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); _decoderSpec->InitInStream(true); + // printf("\nSeek"); } + else + _needSeekToStart = true; + bool firstItem = true; - Int32 opRes; + + UInt64 packSize = _decoderSpec->GetInputProcessedSize(); + // printf("\npackSize = %d", (unsigned)packSize); + + UInt64 unpackedSize = 0; + UInt64 numStreams = 0; + + bool crcError = false; + + HRESULT result = S_OK; + + try { + for (;;) { - lps->InSize = _packSize = _decoderSpec->GetInputProcessedSize(); - _packSizeDefined = true; - lps->OutSize = outStreamSpec->GetSize(); + lps->InSize = packSize; + lps->OutSize = unpackedSize; + RINOK(lps->SetCur()); CItem item; - if (!firstItem || _stream) + + if (!firstItem || needReadFirstItem) { - HRESULT result = item.ReadHeader(_decoderSpec); + result = item.ReadHeader(_decoderSpec); + + if (result != S_OK && result != S_FALSE) + return result; + + if (_decoderSpec->InputEofError()) + result = S_FALSE; + + if (result != S_OK && firstItem) + { + _isArc = false; + break; + } + + if (packSize == _decoderSpec->GetStreamSize()) + { + result = S_OK; + break; + } + if (result != S_OK) { - if (result != S_FALSE) - return result; - opRes = firstItem ? - NExtract::NOperationResult::kDataError : - NExtract::NOperationResult::kOK; + _dataAfterEnd = true; break; } } + + numStreams++; firstItem = false; UInt64 startOffset = outStreamSpec->GetSize(); outStreamSpec->InitCRC(); - HRESULT result = _decoderSpec->CodeResume(outStream, NULL, progress); - if (result != S_OK) + result = _decoderSpec->CodeResume(outStream, NULL, progress); + + packSize = _decoderSpec->GetInputProcessedSize(); + unpackedSize = outStreamSpec->GetSize(); + + if (result != S_OK && result != S_FALSE) + return result; + + if (_decoderSpec->InputEofError()) { - if (result != S_FALSE) - return result; - opRes = NExtract::NOperationResult::kDataError; - break; + packSize = _decoderSpec->GetStreamSize(); + _needMoreInput = true; + result = S_FALSE; } + if (result != S_OK) + break; + _decoderSpec->AlignToByte(); - if (item.ReadFooter1(_decoderSpec) != S_OK) + + result = item.ReadFooter1(_decoderSpec); + + packSize = _decoderSpec->GetInputProcessedSize(); + + if (result != S_OK && result != S_FALSE) + return result; + + if (result != S_OK) { - opRes = NExtract::NOperationResult::kDataError; + if (_decoderSpec->InputEofError()) + { + _needMoreInput = true; + result = S_FALSE; + } break; } + if (item.Crc != outStreamSpec->GetCRC() || - item.Size32 != (UInt32)(outStreamSpec->GetSize() - startOffset)) + item.Size32 != (UInt32)(unpackedSize - startOffset)) { - opRes = NExtract::NOperationResult::kCRCError; + crcError = true; + result = S_FALSE; break; } } + + } catch(const CInBufferException &e) { return e.ErrorCode; } + + if (!firstItem) + { + _packSize = packSize; + _unpackSize = unpackedSize; + _numStreams = numStreams; + + _packSize_Defined = true; + _unpackSize_Defined = true; + _numStreams_Defined = true; + } + outStream.Release(); - return extractCallback->SetOperationResult(opRes); + + Int32 retResult = NExtract::NOperationResult::kDataError; + + if (!_isArc) + retResult = NExtract::NOperationResult::kIsNotArc; + else if (_needMoreInput) + retResult = NExtract::NOperationResult::kUnexpectedEnd; + else if (crcError) + retResult = NExtract::NOperationResult::kCRCError; + else if (_dataAfterEnd) + retResult = NExtract::NOperationResult::kDataAfterEnd; + else if (result == S_FALSE) + retResult = NExtract::NOperationResult::kDataError; + else if (result == S_OK) + retResult = NExtract::NOperationResult::kOK; + else + return result; + + return extractCallback->SetOperationResult(retResult); + + COM_TRY_END } static const Byte kHostOS = #ifdef _WIN32 - NHeader::NHostOS::kFAT; + NHostOS::kFAT; #else - NHeader::NHostOS::kUnix; + NHostOS::kUnix; #endif static HRESULT UpdateArchive( @@ -565,16 +865,15 @@ static HRESULT UpdateArchive( lps->Init(updateCallback, true); CItem item = newItem; - item.Method = NHeader::NCompressionMethod::kDeflate; item.ExtraFlags = props.GetLevel() >= 7 ? - NHeader::NExtraFlags::kMaximum : - NHeader::NExtraFlags::kFastest; + NExtraFlags::kMaximum : + NExtraFlags::kFastest; item.HostOS = kHostOS; RINOK(item.WriteHeader(outStream)); - NCompress::NDeflate::NEncoder::CCOMCoder *deflateEncoderSpec = new NCompress::NDeflate::NEncoder::CCOMCoder; + NEncoder::CCOMCoder *deflateEncoderSpec = new NEncoder::CCOMCoder; CMyComPtr<ICompressCoder> deflateEncoder = deflateEncoderSpec; RINOK(props.SetCoderProps(deflateEncoderSpec, NULL)); RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress)); @@ -582,7 +881,7 @@ static HRESULT UpdateArchive( item.Crc = inStreamSpec->GetCRC(); item.Size32 = (UInt32)inStreamSpec->GetSize(); RINOK(item.WriteFooter(outStream)); - return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); + return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK); } STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) @@ -609,13 +908,14 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (IntToBool(newProps)) { { - FILETIME utcTime; NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(0, kpidMTime, &prop)); - if (prop.vt != VT_FILETIME) + if (prop.vt == VT_FILETIME) + NTime::FileTimeToUnixTime(prop.filetime, newItem.Time); + else if (prop.vt == VT_EMPTY) + newItem.Time = 0; + else return E_INVALIDARG; - utcTime = prop.filetime; - NTime::FileTimeToUnixTime(utcTime, newItem.Time); } { NCOM::CPropVariant prop; @@ -623,12 +923,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (prop.vt == VT_BSTR) { UString name = prop.bstrVal; - int dirDelimiterPos = name.ReverseFind(CHAR_PATH_SEPARATOR); + int dirDelimiterPos = name.ReverseFind(WCHAR_PATH_SEPARATOR); if (dirDelimiterPos >= 0) - name = name.Mid(dirDelimiterPos + 1); + name = name.Ptr(dirDelimiterPos + 1); newItem.Name = UnicodeStringToMultiByte(name, CP_ACP); if (!newItem.Name.IsEmpty()) - newItem.Flags |= NHeader::NFlags::kName; + newItem.Flags |= NFlags::kName; } else if (prop.vt != VT_EMPTY) return E_INVALIDARG; @@ -665,7 +965,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (!_stream) return E_NOTIMPL; - UInt64 offset = _startPosition; + UInt64 offset = 0; if (IntToBool(newProps)) { newItem.WriteHeader(outStream); @@ -675,20 +975,20 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return NCompress::CopyStream(_stream, outStream, NULL); } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { return _props.SetProperties(names, values, numProps); } -static IInArchive *CreateArc() { return new CHandler; } -#ifndef EXTRACT_ONLY -static IOutArchive *CreateArcOut() { return new CHandler; } -#else -#define CreateArcOut 0 -#endif +IMP_CreateArcIn +IMP_CreateArcOut static CArcInfo g_ArcInfo = - { L"gzip", L"gz gzip tgz tpz", L"* * .tar .tar", 0xEF, { 0x1F, 0x8B, 8 }, 3, true, CreateArc, CreateArcOut }; + { "gzip", "gz gzip tgz tpz", "* * .tar .tar", 0xEF, + 3, { kSignature_0, kSignature_1, kSignature_2 }, + 0, + NArcInfoFlags::kKeepName, + REF_CreateArc_Pair, IsArc_Gz }; REGISTER_ARC(GZip) diff --git a/CPP/7zip/Archive/Hfs/HfsHandler.cpp b/CPP/7zip/Archive/Hfs/HfsHandler.cpp deleted file mode 100755 index f226458d..00000000 --- a/CPP/7zip/Archive/Hfs/HfsHandler.cpp +++ /dev/null @@ -1,243 +0,0 @@ -// HfsHandler.cpp - -#include "StdAfx.h" - -#include "Common/ComTry.h" -#include "Windows/PropVariant.h" -#include "../../Common/StreamUtils.h" -#include "HfsHandler.h" - -namespace NArchive { -namespace NHfs { - -STATPROPSTG kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidATime, VT_FILETIME} -}; - -STATPROPSTG kArcProps[] = -{ - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidClusterSize, VT_UI4}, - { NULL, kpidFreeSpace, VT_UI8}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidMTime, VT_FILETIME} -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop) -{ - FILETIME ft; - HfsTimeToFileTime(hfsTime, ft); - prop = ft; -} - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) - { - case kpidMethod: prop = _db.Header.IsHfsX() ? L"HFSX" : L"HFS+"; break; - case kpidClusterSize: prop = (UInt32)1 << _db.Header.BlockSizeLog; break; - case kpidFreeSpace: prop = (UInt64)_db.Header.NumFreeBlocks << _db.Header.BlockSizeLog; break; - case kpidMTime: HfsTimeToProp(_db.Header.MTime, prop); break; - case kpidCTime: - { - FILETIME localFt, ft; - HfsTimeToFileTime(_db.Header.CTime, localFt); - if (LocalFileTimeToFileTime(&localFt, &ft)) - prop = ft; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = _db.Items[index]; - switch(propID) - { - case kpidPath: prop = _db.GetItemPath(index); break; - case kpidIsDir: prop = item.IsDir(); break; - - case kpidCTime: HfsTimeToProp(item.CTime, prop); break; - case kpidMTime: HfsTimeToProp(item.MTime, prop); break; - case kpidATime: HfsTimeToProp(item.ATime, prop); break; - - case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumBlocks << _db.Header.BlockSizeLog; break; - case kpidSize: if (!item.IsDir()) prop = item.Size; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -class CProgressImp: public CProgressVirt -{ - CMyComPtr<IArchiveOpenCallback> _callback; -public: - HRESULT SetTotal(UInt64 numFiles); - HRESULT SetCompleted(UInt64 numFiles); - CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {} -}; - -HRESULT CProgressImp::SetTotal(UInt64 numFiles) -{ - if (_callback) - return _callback->SetTotal(&numFiles, NULL); - return S_OK; -} - -HRESULT CProgressImp::SetCompleted(UInt64 numFiles) -{ - if (_callback) - return _callback->SetCompleted(&numFiles, NULL); - return S_OK; -} - -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback *callback) -{ - COM_TRY_BEGIN - Close(); - try - { - CProgressImp progressImp(callback); - HRESULT res = _db.Open(inStream, &progressImp); - if (res == E_ABORT) - return res; - if (res != S_OK) - return S_FALSE; - _stream = inStream; - } - catch(...) { return S_FALSE; } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::Close() -{ - _stream.Release(); - _db.Clear(); - return S_OK; -} - -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) -{ - COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); - if (allFilesMode) - numItems = _db.Items.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - UInt64 totalSize = 0; - for (i = 0; i < numItems; i++) - { - const CItem &item = _db.Items[allFilesMode ? i : indices[i]]; - if (!item.IsDir()) - totalSize += item.Size; - } - RINOK(extractCallback->SetTotal(totalSize)); - - UInt64 currentTotalSize = 0, currentItemSize = 0; - - CByteBuffer buf; - const UInt32 kBufSize = (1 << 16); - buf.SetCapacity(kBufSize); - - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) - { - RINOK(extractCallback->SetCompleted(¤tTotalSize)); - Int32 index = allFilesMode ? i : indices[i]; - const CItem &item = _db.Items[index]; - currentItemSize = 0; - if (!item.IsDir()) - currentItemSize = item.Size; - - CMyComPtr<ISequentialOutStream> realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - - if (item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); - continue; - } - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)); - UInt64 pos = 0; - int res = NExtract::NOperationResult::kOK; - int i; - for (i = 0; i < item.Extents.Size(); i++) - { - if (item.Size == pos) - break; - if (res != NExtract::NOperationResult::kOK) - break; - const CExtent &e = item.Extents[i]; - RINOK(_stream->Seek((UInt64)e.Pos << _db.Header.BlockSizeLog, STREAM_SEEK_SET, NULL)); - UInt64 extentSize = (UInt64)e.NumBlocks << _db.Header.BlockSizeLog; - for (;;) - { - if (extentSize == 0) - break; - UInt64 rem = item.Size - pos; - if (rem == 0) - { - if (extentSize >= (UInt64)((UInt32)1 << _db.Header.BlockSizeLog)) - res = NExtract::NOperationResult::kDataError; - break; - } - UInt32 curSize = kBufSize; - if (curSize > rem) - curSize = (UInt32)rem; - if (curSize > extentSize) - curSize = (UInt32)extentSize; - RINOK(ReadStream_FALSE(_stream, buf, curSize)); - if (realOutStream) - { - RINOK(WriteStream(realOutStream, buf, curSize)); - } - pos += curSize; - extentSize -= curSize; - UInt64 processed = currentTotalSize + pos; - RINOK(extractCallback->SetCompleted(&processed)); - } - } - if (i != item.Extents.Size() || item.Size != pos) - res = NExtract::NOperationResult::kDataError; - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(res)); - } - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) -{ - *numItems = _db.Items.Size(); - return S_OK; -} - -}} diff --git a/CPP/7zip/Archive/Hfs/HfsHandler.h b/CPP/7zip/Archive/Hfs/HfsHandler.h deleted file mode 100755 index 269af218..00000000 --- a/CPP/7zip/Archive/Hfs/HfsHandler.h +++ /dev/null @@ -1,26 +0,0 @@ -// HfsHandler.h - -#ifndef __ARCHIVE_HFS_HANDLER_H -#define __ARCHIVE_HFS_HANDLER_H - -#include "Common/MyCom.h" -#include "../IArchive.h" -#include "HfsIn.h" - -namespace NArchive { -namespace NHfs { - -class CHandler: - public IInArchive, - public CMyUnknownImp -{ - CMyComPtr<IInStream> _stream; - CDatabase _db; -public: - MY_UNKNOWN_IMP1(IInArchive) - INTERFACE_IInArchive(;) -}; - -}} - -#endif diff --git a/CPP/7zip/Archive/Hfs/HfsIn.cpp b/CPP/7zip/Archive/Hfs/HfsIn.cpp deleted file mode 100755 index 8391dd93..00000000 --- a/CPP/7zip/Archive/Hfs/HfsIn.cpp +++ /dev/null @@ -1,480 +0,0 @@ -// HfsIn.cpp - -#include "StdAfx.h" - -#include "../../Common/StreamUtils.h" -#include "Common/IntToString.h" - -#include "HfsIn.h" - -#include "../../../../C/CpuArch.h" - -#define Get16(p) GetBe16(p) -#define Get32(p) GetBe32(p) -#define Get64(p) GetBe64(p) - -namespace NArchive { -namespace NHfs { - -#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } - -static int CompareIdToIndex(const CIdIndexPair *p1, const CIdIndexPair *p2, void * /* param */) -{ - RINOZ(MyCompare(p1->ID, p2->ID)); - return MyCompare(p1->Index, p2->Index); -} - -bool operator< (const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID < a2.ID); } -bool operator> (const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID > a2.ID); } -bool operator==(const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID == a2.ID); } -bool operator!=(const CIdIndexPair &a1, const CIdIndexPair &a2) { return (a1.ID != a2.ID); } - -static UString GetSpecName(const UString &name, UInt32 /* id */) -{ - UString name2 = name; - name2.Trim(); - if (name2.IsEmpty()) - { - /* - wchar_t s[32]; - ConvertUInt64ToString(id, s); - return L"[" + (UString)s + L"]"; - */ - return L"[]"; - } - return name; -} - -UString CDatabase::GetItemPath(int index) const -{ - const CItem *item = &Items[index]; - UString name = GetSpecName(item->Name, item->ID); - - for (int i = 0; i < 1000; i++) - { - if (item->ParentID < 16 && item->ParentID != 2) - { - if (item->ParentID != 1) - break; - return name; - } - CIdIndexPair pair; - pair.ID = item->ParentID; - pair.Index = 0; - int indexInMap = IdToIndexMap.FindInSorted(pair); - if (indexInMap < 0) - break; - item = &Items[IdToIndexMap[indexInMap].Index]; - name = GetSpecName(item->Name, item->ID) + WCHAR_PATH_SEPARATOR + name; - } - return (UString)L"Unknown" + WCHAR_PATH_SEPARATOR + name; -} - -void CFork::Parse(const Byte *p) -{ - Size = Get64(p); - // ClumpSize = Get32(p + 8); - NumBlocks = Get32(p + 0xC); - for (int i = 0; i < 8; i++) - { - CExtent &e = Extents[i]; - e.Pos = Get32(p + 0x10 + i * 8); - e.NumBlocks = Get32(p + 0x10 + i * 8 + 4); - } -} - -static HRESULT ReadExtent(int blockSizeLog, IInStream *inStream, Byte *buf, const CExtent &e) -{ - RINOK(inStream->Seek((UInt64)e.Pos << blockSizeLog, STREAM_SEEK_SET, NULL)); - return ReadStream_FALSE(inStream, buf, (size_t)e.NumBlocks << blockSizeLog); -} - -HRESULT CDatabase::ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream) -{ - if (fork.NumBlocks >= Header.NumBlocks) - return S_FALSE; - size_t totalSize = (size_t)fork.NumBlocks << Header.BlockSizeLog; - if ((totalSize >> Header.BlockSizeLog) != fork.NumBlocks) - return S_FALSE; - buf.SetCapacity(totalSize); - UInt32 curBlock = 0; - for (int i = 0; i < 8; i++) - { - if (curBlock >= fork.NumBlocks) - break; - const CExtent &e = fork.Extents[i]; - if (fork.NumBlocks - curBlock < e.NumBlocks || e.Pos >= Header.NumBlocks) - return S_FALSE; - RINOK(ReadExtent(Header.BlockSizeLog, inStream, - (Byte *)buf + ((size_t)curBlock << Header.BlockSizeLog), e)); - curBlock += e.NumBlocks; - } - return S_OK; -} - -struct CNodeDescriptor -{ - UInt32 fLink; - UInt32 bLink; - Byte Kind; - Byte Height; - UInt16 NumRecords; - // UInt16 Reserved; - void Parse(const Byte *p); -}; - -void CNodeDescriptor::Parse(const Byte *p) -{ - fLink = Get32(p); - bLink = Get32(p + 4); - Kind = p[8]; - Height = p[9]; - NumRecords = Get16(p + 10); -} - -struct CHeaderRec -{ - // UInt16 TreeDepth; - // UInt32 RootNode; - // UInt32 LeafRecords; - UInt32 FirstLeafNode; - // UInt32 LastLeafNode; - int NodeSizeLog; - // UInt16 MaxKeyLength; - UInt32 TotalNodes; - // UInt32 FreeNodes; - // UInt16 Reserved1; - // UInt32 ClumpSize; - // Byte BtreeType; - // Byte KeyCompareType; - // UInt32 Attributes; - // UInt32 Reserved3[16]; - - HRESULT Parse(const Byte *p); -}; - -HRESULT CHeaderRec::Parse(const Byte *p) -{ - // TreeDepth = Get16(p); - // RootNode = Get32(p + 2); - // LeafRecords = Get32(p + 6); - FirstLeafNode = Get32(p + 0xA); - // LastLeafNode = Get32(p + 0xE); - UInt32 nodeSize = Get16(p + 0x12); - - int i; - for (i = 9; ((UInt32)1 << i) != nodeSize; i++) - if (i == 16) - return S_FALSE; - NodeSizeLog = i; - - // MaxKeyLength = Get16(p + 0x14); - TotalNodes = Get32(p + 0x16); - // FreeNodes = Get32(p + 0x1A); - // Reserved1 = Get16(p + 0x1E); - // ClumpSize = Get32(p + 0x20); - // BtreeType = p[0x24]; - // KeyCompareType = p[0x25]; - // Attributes = Get32(p + 0x26); - /* - for (int i = 0; i < 16; i++) - Reserved3[i] = Get32(p + 0x2A + i * 4); - */ - return S_OK; -} - - -enum ENodeType -{ - NODE_TYPE_LEAF = 0xFF, - NODE_TYPE_INDEX = 0, - NODE_TYPE_HEADER = 1, - NODE_TYPE_MODE = 2 -}; - -HRESULT CDatabase::LoadExtentFile(IInStream *inStream) -{ - // FileExtents.Clear(); - // ResExtents.Clear(); - - CByteBuffer extents; - RINOK(ReadFile(Header.ExtentsFile, extents, inStream)); - - const Byte *p = (const Byte *)extents; - - // CNodeDescriptor nodeDesc; - // nodeDesc.Parse(p); - CHeaderRec hr; - RINOK(hr.Parse(p + 14)); - - UInt32 node = hr.FirstLeafNode; - if (node != 0) - return S_FALSE; - /* - while (node != 0) - { - size_t nodeOffset = node * hr.NodeSize; - if ((node + 1)* hr.NodeSize > CatalogBuf.GetCapacity()) - return S_FALSE; - CNodeDescriptor desc; - desc.Parse(p + nodeOffset); - if (desc.Kind != NODE_TYPE_LEAF) - return S_FALSE; - UInt32 ptr = hr.NodeSize; - for (int i = 0; i < desc.NumRecords; i++) - { - UInt32 offs = Get16(p + nodeOffset + hr.NodeSize - (i + 1) * 2); - UInt32 offsNext = Get16(p + nodeOffset + hr.NodeSize - (i + 2) * 2); - - const Byte *r = p + nodeOffset + offs; - int keyLength = Get16(r); - Byte forkType = r[2]; - UInt32 id = Get16(r + 4); - UInt32 startBlock = Get16(r + 4); - CObjectVector<CIdExtents> *extents = (forkType == 0) ? &FileExtents : &ResExtents; - if (extents->Size() == 0) - extents->Add(CIdExtents()); - else - { - CIdExtents &e = extents->Back(); - if (e.ID != id) - { - if (e.ID > id) - return S_FALSE; - extents->Add(CIdExtents()); - } - } - CIdExtents &e = extents->Back(); - for (UInt32 k = offs + 10 + 2; k + 8 <= offsNext; k += 8) - { - CExtent ee; - ee.Pos = Get32(p + nodeOffset + k); - ee.NumBlocks = Get32(p + nodeOffset + k * 4); - e.Extents.Add(ee); - } - } - node = desc.fLink; - } - */ - return S_OK; -} - - -HRESULT CDatabase::LoadCatalog(IInStream *inStream, CProgressVirt *progress) -{ - Items.Clear(); - IdToIndexMap.ClearAndFree(); - - CByteBuffer catalogBuf; - RINOK(ReadFile(Header.CatalogFile, catalogBuf, inStream)); - const Byte *p = (const Byte *)catalogBuf; - - // CNodeDescriptor nodeDesc; - // nodeDesc.Parse(p); - CHeaderRec hr; - hr.Parse(p + 14); - - // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC); - - if ((catalogBuf.GetCapacity() >> hr.NodeSizeLog) < hr.TotalNodes) - return S_FALSE; - - CByteBuffer usedBuf; - usedBuf.SetCapacity(hr.TotalNodes); - for (UInt32 i = 0; i < hr.TotalNodes; i++) - usedBuf[i] = 0; - - UInt32 node = hr.FirstLeafNode; - while (node != 0) - { - if (node >= hr.TotalNodes) - return S_FALSE; - if (usedBuf[node]) - return S_FALSE; - usedBuf[node] = 1; - size_t nodeOffset = (size_t)node << hr.NodeSizeLog; - CNodeDescriptor desc; - desc.Parse(p + nodeOffset); - if (desc.Kind != NODE_TYPE_LEAF) - return S_FALSE; - for (int 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); - UInt32 recSize = offsNext - offs; - if (offsNext >= nodeSize || offsNext < offs || recSize < 6) - return S_FALSE; - - CItem item; - - const Byte *r = p + nodeOffset + offs; - UInt32 keyLength = Get16(r); - item.ParentID = Get32(r + 2); - UString name; - if (keyLength < 6 || (keyLength & 1) != 0 || keyLength + 2 > recSize) - return S_FALSE; - r += 6; - recSize -= 6; - keyLength -= 6; - - int nameLength = Get16(r); - if (nameLength * 2 != (int)keyLength) - return S_FALSE; - r += 2; - recSize -= 2; - - wchar_t *pp = name.GetBuffer(nameLength + 1); - - int j; - for (j = 0; j < nameLength; j++) - pp[j] = ((wchar_t)r[j * 2] << 8) | r[j * 2 + 1]; - pp[j] = 0; - name.ReleaseBuffer(); - r += j * 2; - recSize -= j * 2; - - if (recSize < 2) - return S_FALSE; - item.Type = Get16(r); - - if (item.Type != RECORD_TYPE_FOLDER && item.Type != RECORD_TYPE_FILE) - continue; - if (recSize < 0x58) - return S_FALSE; - - // item.Flags = Get16(r + 2); - // item.Valence = Get32(r + 4); - item.ID = Get32(r + 8); - item.CTime = Get32(r + 0xC); - item.MTime = Get32(r + 0x10); - // item.AttrMTime = Get32(r + 0x14); - item.ATime = Get32(r + 0x18); - // item.BackupDate = Get32(r + 0x1C); - - /* - item.OwnerID = Get32(r + 0x20); - item.GroupID = Get32(r + 0x24); - item.AdminFlags = r[0x28]; - item.OwnerFlags = r[0x29]; - item.FileMode = Get16(r + 0x2A); - item.special.iNodeNum = Get16(r + 0x2C); - */ - - item.Name = name; - - if (item.IsDir()) - { - CIdIndexPair pair; - pair.ID = item.ID; - pair.Index = Items.Size(); - IdToIndexMap.Add(pair); - } - else - { - CFork fd; - recSize -= 0x58; - r += 0x58; - if (recSize < 0x50 * 2) - return S_FALSE; - fd.Parse(r); - item.Size = fd.Size; - item.NumBlocks = fd.NumBlocks; - UInt32 curBlock = 0; - for (int j = 0; j < 8; j++) - { - if (curBlock >= fd.NumBlocks) - break; - const CExtent &e = fd.Extents[j]; - item.Extents.Add(e); - curBlock += e.NumBlocks; - } - } - Items.Add(item); - if (progress && Items.Size() % 100 == 0) - { - RINOK(progress->SetCompleted(Items.Size())); - } - } - node = desc.fLink; - } - IdToIndexMap.Sort(CompareIdToIndex, NULL); - return S_OK; -} - -HRESULT CDatabase::Open(IInStream *inStream, CProgressVirt *progress) -{ - static const UInt32 kHeaderSize = 1024 + 512; - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)); - int i; - for (i = 0; i < 1024; i++) - if (buf[i] != 0) - return S_FALSE; - const Byte *p = buf + 1024; - CVolHeader &h = Header; - - h.Header[0] = p[0]; - h.Header[1] = p[1]; - if (p[0] != 'H' || (p[1] != '+' && p[1] != 'X')) - return S_FALSE; - h.Version = Get16(p + 2); - if (h.Version < 4 || h.Version > 5) - return S_FALSE; - - // h.Attr = Get32(p + 4); - // h.LastMountedVersion = Get32(p + 8); - // h.JournalInfoBlock = Get32(p + 0xC); - - h.CTime = Get32(p + 0x10); - h.MTime = Get32(p + 0x14); - // h.BackupTime = Get32(p + 0x18); - // h.CheckedTime = Get32(p + 0x1C); - - // h.NumFiles = Get32(p + 0x20); - // h.NumFolders = Get32(p + 0x24); - - UInt32 numFiles = Get32(p + 0x20); - UInt32 numFolders = Get32(p + 0x24);; - if (progress) - { - RINOK(progress->SetTotal(numFolders + numFiles)); - } - - UInt32 blockSize = Get32(p + 0x28); - - for (i = 9; ((UInt32)1 << i) != blockSize; i++) - if (i == 31) - return S_FALSE; - h.BlockSizeLog = i; - - h.NumBlocks = Get32(p + 0x2C); - h.NumFreeBlocks = Get32(p + 0x30); - - /* - h.WriteCount = Get32(p + 0x44); - for (i = 0; i < 6; i++) - h.FinderInfo[i] = Get32(p + 0x50 + i * 4); - h.VolID = Get64(p + 0x68); - */ - - UInt64 endPos; - RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); - if ((endPos >> h.BlockSizeLog) < h.NumBlocks) - return S_FALSE; - - // h.AllocationFile.Parse(p + 0x70 + 0x50 * 0); - h.ExtentsFile.Parse( p + 0x70 + 0x50 * 1); - h.CatalogFile.Parse( p + 0x70 + 0x50 * 2); - // h.AttributesFile.Parse(p + 0x70 + 0x50 * 3); - // h.StartupFile.Parse( p + 0x70 + 0x50 * 4); - - RINOK(LoadExtentFile(inStream)); - RINOK(LoadCatalog(inStream, progress)); - - // if (Header.NumFiles + Header.NumFolders != (UInt32)Items.Size()) return S_OK; - - return S_OK; -} - -}} diff --git a/CPP/7zip/Archive/Hfs/HfsIn.h b/CPP/7zip/Archive/Hfs/HfsIn.h deleted file mode 100755 index c1953905..00000000 --- a/CPP/7zip/Archive/Hfs/HfsIn.h +++ /dev/null @@ -1,154 +0,0 @@ -// HfsIn.h - -#ifndef __ARCHIVE_HFS_IN_H -#define __ARCHIVE_HFS_IN_H - -#include "Common/MyString.h" -#include "Common/Buffer.h" - -namespace NArchive { -namespace NHfs { - -struct CExtent -{ - UInt32 Pos; - UInt32 NumBlocks; -}; - -struct CFork -{ - UInt64 Size; - // UInt32 ClumpSize; - UInt32 NumBlocks; - CExtent Extents[8]; - void Parse(const Byte *p); -}; - -struct CVolHeader -{ - Byte Header[2]; - UInt16 Version; - // UInt32 Attr; - // UInt32 LastMountedVersion; - // UInt32 JournalInfoBlock; - - UInt32 CTime; - UInt32 MTime; - // UInt32 BackupTime; - // UInt32 CheckedTime; - - // UInt32 NumFiles; - // UInt32 NumFolders; - int BlockSizeLog; - UInt32 NumBlocks; - UInt32 NumFreeBlocks; - - // UInt32 WriteCount; - // UInt32 FinderInfo[8]; - // UInt64 VolID; - - // CFork AllocationFile; - CFork ExtentsFile; - CFork CatalogFile; - // CFork AttributesFile; - // CFork StartupFile; - - bool IsHfsX() const { return Version > 4; } -}; - -inline void HfsTimeToFileTime(UInt32 hfsTime, FILETIME &ft) -{ - UInt64 v = ((UInt64)3600 * 24 * (365 * 303 + 24 * 3) + hfsTime) * 10000000; - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); -} - -enum ERecordType -{ - RECORD_TYPE_FOLDER = 1, - RECORD_TYPE_FILE = 2, - RECORD_TYPE_FOLDER_THREAD = 3, - RECORD_TYPE_FILE_THREAD = 4 -}; - -struct CItem -{ - UString Name; - - UInt32 ParentID; - - UInt16 Type; - // UInt16 Flags; - // UInt32 Valence; - UInt32 ID; - UInt32 CTime; - UInt32 MTime; - // UInt32 AttrMTime; - UInt32 ATime; - // UInt32 BackupDate; - - /* - UInt32 OwnerID; - UInt32 GroupID; - Byte AdminFlags; - Byte OwnerFlags; - UInt16 FileMode; - union - { - UInt32 iNodeNum; - UInt32 LinkCount; - UInt32 RawDevice; - } special; - */ - - UInt64 Size; - UInt32 NumBlocks; - CRecordVector<CExtent> Extents; - - bool IsDir() const { return Type == RECORD_TYPE_FOLDER; } - CItem(): Size(0), NumBlocks(0) {} -}; - -struct CIdIndexPair -{ - UInt32 ID; - int Index; -}; - -struct CProgressVirt -{ - virtual HRESULT SetTotal(UInt64 numFiles) PURE; - virtual HRESULT SetCompleted(UInt64 numFiles) PURE; -}; - -class CDatabase -{ - // CObjectVector<CIdExtents> FileExtents; - // CObjectVector<CIdExtents> ResExtents; - CRecordVector<CIdIndexPair> IdToIndexMap; - - HRESULT LoadExtentFile(IInStream *inStream); - HRESULT LoadCatalog(IInStream *inStream, CProgressVirt *progress); - - HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream); -public: - CVolHeader Header; - CObjectVector<CItem> Items; - // bool CaseSensetive; - - void Clear() - { - // CaseSensetive = false; - Items.Clear(); - // FileExtents.Clear(); - // ResExtents.Clear(); - IdToIndexMap.Clear(); - } - - UString GetItemPath(int index) const; - HRESULT Open(IInStream *inStream, CProgressVirt *progress); -}; - -}} - -#endif diff --git a/CPP/7zip/Archive/Hfs/HfsRegister.cpp b/CPP/7zip/Archive/Hfs/HfsRegister.cpp deleted file mode 100755 index 51c3c2b1..00000000 --- a/CPP/7zip/Archive/Hfs/HfsRegister.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// HfsRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "HfsHandler.h" -static IInArchive *CreateArc() { return new NArchive::NHfs::CHandler; } - -static CArcInfo g_ArcInfo = - { L"HFS", L"hfs", 0, 0xE3, { 'H', '+', 0, 4 }, 4, false, CreateArc, 0 }; - -REGISTER_ARC(Hfs) diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp new file mode 100644 index 00000000..ca1370d8 --- /dev/null +++ b/CPP/7zip/Archive/HfsHandler.cpp @@ -0,0 +1,1874 @@ +// HfsHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/ZlibDecoder.h" + +/* if HFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files + and resource forks. In most cases it looks useless. So we disable it. */ + +// #define HFS_SHOW_ALT_STREAMS + +#define Get16(p) GetBe16(p) +#define Get32(p) GetBe32(p) +#define Get64(p) GetBe64(p) + +namespace NArchive { +namespace NHfs { + +static const wchar_t *kResFileName = L"rsrc"; // L"com.apple.ResourceFork"; + +struct CExtent +{ + UInt32 Pos; + UInt32 NumBlocks; +}; + +struct CIdExtents +{ + UInt32 ID; + UInt32 StartBlock; + CRecordVector<CExtent> Extents; +}; + +struct CFork +{ + UInt64 Size; + UInt32 NumBlocks; + // UInt32 ClumpSize; + CRecordVector<CExtent> Extents; + + CFork(): Size(0), NumBlocks(0) {} + + void Parse(const Byte *p); + + bool IsEmpty() const { return Size == 0 && NumBlocks == 0 && Extents.Size() == 0; } + + UInt32 Calc_NumBlocks_from_Extents() const; + bool Check_NumBlocks() const; + + bool Check_Size_with_NumBlocks(unsigned blockSizeLog) const + { + return Size <= ((UInt64)NumBlocks << blockSizeLog); + } + + bool IsOk(unsigned blockSizeLog) const + { + // we don't check cases with extra (empty) blocks in last extent + return Check_NumBlocks() && Check_Size_with_NumBlocks(blockSizeLog); + } + + bool Upgrade(const CObjectVector<CIdExtents> &items, UInt32 id); + bool UpgradeAndTest(const CObjectVector<CIdExtents> &items, UInt32 id, unsigned blockSizeLog) + { + if (!Upgrade(items, id)) + return false; + return IsOk(blockSizeLog); + } +}; + +static const unsigned kNumFixedExtents = 8; + +void CFork::Parse(const Byte *p) +{ + Extents.Clear(); + Size = Get64(p); + // ClumpSize = Get32(p + 8); + NumBlocks = Get32(p + 12); + p += 16; + for (unsigned i = 0; i < kNumFixedExtents; i++, p += 8) + { + CExtent e; + e.Pos = Get32(p); + e.NumBlocks = Get32(p + 4); + if (e.NumBlocks != 0) + Extents.Add(e); + } +} + +UInt32 CFork::Calc_NumBlocks_from_Extents() const +{ + UInt32 num = 0; + FOR_VECTOR (i, Extents) + { + num += Extents[i].NumBlocks; + } + return num; +} + +bool CFork::Check_NumBlocks() const +{ + UInt32 num = 0; + FOR_VECTOR (i, Extents) + { + UInt32 next = num + Extents[i].NumBlocks; + if (next < num) + return false; + num = next; + } + return num == NumBlocks; +} + +struct CIdIndexPair +{ + UInt32 ID; + int Index; + + int Compare(const CIdIndexPair &a) const; +}; + +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + +int CIdIndexPair::Compare(const CIdIndexPair &a) const +{ + RINOZ(MyCompare(ID, a.ID)); + return MyCompare(Index, a.Index); +} + +static int FindItemIndex(const CRecordVector<CIdIndexPair> &items, UInt32 id) +{ + unsigned left = 0, right = items.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + UInt32 midVal = items[mid].ID; + if (id == midVal) + return items[mid].Index; + if (id < midVal) + right = mid; + else + left = mid + 1; + } + return -1; +} + +static int Find_in_IdExtents(const CObjectVector<CIdExtents> &items, UInt32 id) +{ + unsigned left = 0, right = items.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + UInt32 midVal = items[mid].ID; + if (id == midVal) + return mid; + if (id < midVal) + right = mid; + else + left = mid + 1; + } + return -1; +} + +bool CFork::Upgrade(const CObjectVector<CIdExtents> &items, UInt32 id) +{ + int index = Find_in_IdExtents(items, id); + if (index < 0) + return true; + const CIdExtents &item = items[index]; + if (Calc_NumBlocks_from_Extents() != item.StartBlock) + return false; + Extents += item.Extents; + return true; +} + + +struct CVolHeader +{ + Byte Header[2]; + UInt16 Version; + // UInt32 Attr; + // UInt32 LastMountedVersion; + // UInt32 JournalInfoBlock; + + UInt32 CTime; + UInt32 MTime; + // UInt32 BackupTime; + // UInt32 CheckedTime; + + UInt32 NumFiles; + UInt32 NumFolders; + unsigned BlockSizeLog; + UInt32 NumBlocks; + UInt32 NumFreeBlocks; + + // UInt32 WriteCount; + // UInt32 FinderInfo[8]; + // UInt64 VolID; + + UInt64 GetPhySize() const { return (UInt64)NumBlocks << BlockSizeLog; } + UInt64 GetFreeSize() const { return (UInt64)NumFreeBlocks << BlockSizeLog; } + bool IsHfsX() const { return Version > 4; } +}; + +inline void HfsTimeToFileTime(UInt32 hfsTime, FILETIME &ft) +{ + UInt64 v = ((UInt64)3600 * 24 * (365 * 303 + 24 * 3) + hfsTime) * 10000000; + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} + +enum ERecordType +{ + RECORD_TYPE_FOLDER = 1, + RECORD_TYPE_FILE, + RECORD_TYPE_FOLDER_THREAD, + RECORD_TYPE_FILE_THREAD +}; + +struct CItem +{ + UString Name; + + UInt32 ParentID; + + UInt16 Type; + UInt16 FileMode; + // UInt16 Flags; + // UInt32 Valence; + UInt32 ID; + UInt32 CTime; + UInt32 MTime; + // UInt32 AttrMTime; + UInt32 ATime; + // UInt32 BackupDate; + + /* + UInt32 OwnerID; + UInt32 GroupID; + Byte AdminFlags; + Byte OwnerFlags; + union + { + UInt32 iNodeNum; + UInt32 LinkCount; + UInt32 RawDevice; + } special; + + UInt32 FileType; + UInt32 FileCreator; + UInt16 FinderFlags; + UInt16 Point[2]; + */ + + CFork DataFork; + CFork ResourceFork; + + // for compressed attribute + UInt64 UnpackSize; + size_t DataPos; + UInt32 PackSize; + unsigned Method; + bool UseAttr; + bool UseInlineData; + + CItem(): UseAttr(false), UseInlineData(false) {} + bool IsDir() const { return Type == RECORD_TYPE_FOLDER; } + const CFork &GetFork(bool isResource) const { return (CFork & )*(isResource ? &ResourceFork: &DataFork ); } +}; + +struct CAttr +{ + UInt32 ID; + UInt32 Size; + size_t Pos; + UString Name; +}; + +struct CRef +{ + unsigned ItemIndex; + int AttrIndex; + int Parent; + bool IsResource; + + bool IsAltStream() const { return IsResource || AttrIndex >= 0; } + CRef(): AttrIndex(-1), Parent(-1), IsResource(false) {} +}; + +class CDatabase +{ + HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream); + HRESULT LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector<CIdExtents> *overflowExtentsArray); + HRESULT LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress); + HRESULT LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents> *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress); + bool Parse_decmpgfs(const CAttr &attr, CItem &item, bool &skip); +public: + CRecordVector<CRef> Refs; + CObjectVector<CItem> Items; + CObjectVector<CAttr> Attrs; + + CByteBuffer AttrBuf; + + CVolHeader Header; + bool HeadersError; + bool ThereAreAltStreams; + // bool CaseSensetive; + UString ResFileName; + + UInt64 PhySize; + + void Clear() + { + PhySize = 0; + HeadersError = false; + ThereAreAltStreams = false; + // CaseSensetive = false; + Refs.Clear(); + Items.Clear(); + Attrs.Clear(); + AttrBuf.Free(); + } + + UInt64 Get_UnpackSize_of_Ref(const CRef &ref) const + { + if (ref.AttrIndex >= 0) + return Attrs[ref.AttrIndex].Size; + const CItem &item = Items[ref.ItemIndex]; + if (item.IsDir()) + return 0; + if (item.UseAttr) + return item.UnpackSize; + return item.GetFork(ref.IsResource).Size; + } + + void GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const; + HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *progress); +}; + +enum +{ + kHfsID_Root = 1, + kHfsID_RootFolder = 2, + kHfsID_ExtentsFile = 3, + kHfsID_CatalogFile = 4, + kHfsID_BadBlockFile = 5, + kHfsID_AllocationFile = 6, + kHfsID_StartupFile = 7, + kHfsID_AttributesFile = 8, + kHfsID_RepairCatalogFile = 14, + kHfsID_BogusExtentFile = 15, + kHfsID_FirstUserCatalogNode = 16 +}; + +void CDatabase::GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const +{ + unsigned len = 0; + const unsigned kNumLevelsMax = (1 << 10); + int cur = index; + unsigned i; + + for (i = 0; i < kNumLevelsMax; i++) + { + const CRef &ref = Refs[cur]; + const UString *s; + + if (ref.IsResource) + s = &ResFileName; + else if (ref.AttrIndex >= 0) + s = &Attrs[ref.AttrIndex].Name; + else + s = &Items[ref.ItemIndex].Name; + + len += s->Len(); + len++; + cur = ref.Parent; + if (cur < 0) + break; + } + + len--; + wchar_t *p = path.AllocBstr(len); + p[len] = 0; + cur = index; + + for (;;) + { + const CRef &ref = Refs[cur]; + const UString *s; + wchar_t delimChar = L':'; + + if (ref.IsResource) + s = &ResFileName; + else if (ref.AttrIndex >= 0) + s = &Attrs[ref.AttrIndex].Name; + else + { + delimChar = WCHAR_PATH_SEPARATOR; + s = &Items[ref.ItemIndex].Name; + } + + unsigned curLen = s->Len(); + len -= curLen; + + const wchar_t *src = (const wchar_t *)*s; + wchar_t *dest = p + len; + for (unsigned j = 0; j < curLen; j++) + dest[j] = src[j]; + + if (len == 0) + break; + p[--len] = delimChar; + cur = ref.Parent; + } +} + +// Actually we read all blocks. It can be larger than fork.Size + +HRESULT CDatabase::ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream) +{ + if (fork.NumBlocks >= Header.NumBlocks) + return S_FALSE; + size_t totalSize = (size_t)fork.NumBlocks << Header.BlockSizeLog; + if ((totalSize >> Header.BlockSizeLog) != fork.NumBlocks) + return S_FALSE; + buf.Alloc(totalSize); + UInt32 curBlock = 0; + FOR_VECTOR (i, fork.Extents) + { + if (curBlock >= fork.NumBlocks) + return S_FALSE; + const CExtent &e = fork.Extents[i]; + if (e.Pos > Header.NumBlocks || + e.NumBlocks > fork.NumBlocks - curBlock || + e.NumBlocks > Header.NumBlocks - e.Pos) + return S_FALSE; + RINOK(inStream->Seek((UInt64)e.Pos << Header.BlockSizeLog, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(inStream, + (Byte *)buf + ((size_t)curBlock << Header.BlockSizeLog), + (size_t)e.NumBlocks << Header.BlockSizeLog)); + curBlock += e.NumBlocks; + } + return S_OK; +} + +static const unsigned kNodeDescriptor_Size = 14; + +struct CNodeDescriptor +{ + UInt32 fLink; + // UInt32 bLink; + Byte Kind; + // Byte Height; + unsigned NumRecords; + + bool CheckNumRecords(unsigned nodeSizeLog) + { + return (kNodeDescriptor_Size + ((UInt32)NumRecords + 1) * 2 <= ((UInt32)1 << nodeSizeLog)); + } + void Parse(const Byte *p); +}; + +void CNodeDescriptor::Parse(const Byte *p) +{ + fLink = Get32(p); + // bLink = Get32(p + 4); + Kind = p[8]; + // Height = p[9]; + NumRecords = Get16(p + 10); +} + +struct CHeaderRec +{ + // UInt16 TreeDepth; + // UInt32 RootNode; + // UInt32 LeafRecords; + UInt32 FirstLeafNode; + // UInt32 LastLeafNode; + unsigned NodeSizeLog; + // UInt16 MaxKeyLength; + UInt32 TotalNodes; + // UInt32 FreeNodes; + // UInt16 Reserved1; + // UInt32 ClumpSize; + // Byte BtreeType; + // Byte KeyCompareType; + // UInt32 Attributes; + // UInt32 Reserved3[16]; + + HRESULT Parse(const Byte *p); +}; + +HRESULT CHeaderRec::Parse(const Byte *p) +{ + // TreeDepth = Get16(p); + // RootNode = Get32(p + 2); + // LeafRecords = Get32(p + 6); + FirstLeafNode = Get32(p + 0xA); + // LastLeafNode = Get32(p + 0xE); + UInt32 nodeSize = Get16(p + 0x12); + + unsigned i; + for (i = 9; ((UInt32)1 << i) != nodeSize; i++) + if (i == 16) + return S_FALSE; + NodeSizeLog = i; + + // MaxKeyLength = Get16(p + 0x14); + TotalNodes = Get32(p + 0x16); + // FreeNodes = Get32(p + 0x1A); + // Reserved1 = Get16(p + 0x1E); + // ClumpSize = Get32(p + 0x20); + // BtreeType = p[0x24]; + // KeyCompareType = p[0x25]; + // Attributes = Get32(p + 0x26); + /* + for (int i = 0; i < 16; i++) + Reserved3[i] = Get32(p + 0x2A + i * 4); + */ + return S_OK; +} + + +static const Byte kNodeType_Leaf = 0xFF; +// static const Byte kNodeType_Index = 0; +// static const Byte kNodeType_Header = 1; +// static const Byte kNodeType_Mode = 2; + +static const Byte kExtentForkType_Data = 0; +static const Byte kExtentForkType_Resource = 0xFF; + +/* It loads data extents from Extents Overflow File + Most dmg installers are not fragmented. So there are no extents in Overflow File. */ + +HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector<CIdExtents> *overflowExtentsArray) +{ + if (fork.NumBlocks == 0) + return S_OK; + CByteBuffer buf; + RINOK(ReadFile(fork, buf, inStream)); + const Byte *p = (const Byte *)buf; + + // CNodeDescriptor nodeDesc; + // nodeDesc.Parse(p); + CHeaderRec hr; + RINOK(hr.Parse(p + kNodeDescriptor_Size)); + + if ((buf.Size() >> hr.NodeSizeLog) < hr.TotalNodes) + return S_FALSE; + + UInt32 node = hr.FirstLeafNode; + if (node == 0) + return S_OK; + + CByteBuffer usedBuf(hr.TotalNodes); + memset(usedBuf, 0, hr.TotalNodes); + + while (node != 0) + { + if (node >= hr.TotalNodes || usedBuf[node] != 0) + return S_FALSE; + usedBuf[node] = 1; + + size_t nodeOffset = (size_t)node << hr.NodeSizeLog; + CNodeDescriptor desc; + desc.Parse(p + nodeOffset); + if (!desc.CheckNumRecords(hr.NodeSizeLog)) + return S_FALSE; + if (desc.Kind != kNodeType_Leaf) + return S_FALSE; + + UInt32 endBlock = 0; + + 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); + if (offs > nodeSize || offsNext > nodeSize) + return S_FALSE; + UInt32 recSize = offsNext - offs; + const unsigned kKeyLen = 10; + + if (recSize != 2 + kKeyLen + kNumFixedExtents * 8) + return S_FALSE; + + const Byte *r = p + nodeOffset + offs; + if (Get16(r) != kKeyLen) + return S_FALSE; + + Byte forkType = r[2]; + unsigned forkTypeIndex; + if (forkType == kExtentForkType_Data) + forkTypeIndex = 0; + else if (forkType == kExtentForkType_Resource) + forkTypeIndex = 1; + else + continue; + CObjectVector<CIdExtents> &overflowExtents = overflowExtentsArray[forkTypeIndex]; + + UInt32 id = Get32(r + 4); + UInt32 startBlock = Get32(r + 8); + r += 2 + kKeyLen; + + bool needNew = true; + + if (overflowExtents.Size() != 0) + { + CIdExtents &e = overflowExtents.Back(); + if (e.ID == id) + { + if (endBlock != startBlock) + return S_FALSE; + needNew = false; + } + } + + if (needNew) + { + CIdExtents &e = overflowExtents.AddNew(); + e.ID = id; + e.StartBlock = startBlock; + endBlock = startBlock; + } + + CIdExtents &e = overflowExtents.Back(); + + for (unsigned k = 0; k < kNumFixedExtents; k++, r += 8) + { + CExtent ee; + ee.Pos = Get32(r); + ee.NumBlocks = Get32(r + 4); + if (ee.NumBlocks != 0) + { + e.Extents.Add(ee); + endBlock += ee.NumBlocks; + } + } + } + + node = desc.fLink; + } + return S_OK; +} + +static void LoadName(const Byte *data, unsigned len, UString &dest) +{ + wchar_t *p = dest.GetBuffer(len); + unsigned i; + for (i = 0; i < len; i++) + p[i] = Get16(data + i * 2); + p[i] = 0; + dest.ReleaseBuffer(); +} + +static bool IsNameEqualTo(const Byte *data, const char *name) +{ + for (unsigned i = 0;; i++) + { + char c = name[i]; + if (c == 0) + return true; + if (Get16(data + i * 2) != (Byte)c) + return false; + } +} + +static const UInt32 kAttrRecordType_Inline = 0x10; +// static const UInt32 kAttrRecordType_Fork = 0x20; +// static const UInt32 kAttrRecordType_Extents = 0x30; + +HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress) +{ + if (fork.NumBlocks == 0) + return S_OK; + + RINOK(ReadFile(fork, AttrBuf, inStream)); + const Byte *p = (const Byte *)AttrBuf; + + // CNodeDescriptor nodeDesc; + // nodeDesc.Parse(p); + CHeaderRec hr; + RINOK(hr.Parse(p + kNodeDescriptor_Size)); + + // 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; + + CByteBuffer usedBuf(hr.TotalNodes); + memset(usedBuf, 0, hr.TotalNodes); + + CFork resFork; + + while (node != 0) + { + if (node >= hr.TotalNodes || usedBuf[node] != 0) + return S_FALSE; + usedBuf[node] = 1; + + size_t nodeOffset = (size_t)node << hr.NodeSizeLog; + CNodeDescriptor desc; + desc.Parse(p + nodeOffset); + if (!desc.CheckNumRecords(hr.NodeSizeLog)) + return S_FALSE; + if (desc.Kind != kNodeType_Leaf) + return S_FALSE; + + 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); + UInt32 recSize = offsNext - offs; + if (offs >= nodeSize + || offsNext >= nodeSize + || offsNext < offs) + return S_FALSE; + + const unsigned kHeadSize = 14; + if (recSize < kHeadSize) + return S_FALSE; + + const Byte *r = p + nodeOffset + offs; + UInt32 keyLen = Get16(r); + + // UInt16 pad = Get16(r + 2); + UInt32 fileID = Get32(r + 4); + unsigned startBlock = Get32(r + 8); + if (startBlock != 0) + { + // that case is still unsupported + HeadersError = true; + continue; + } + unsigned nameLen = Get16(r + 12); + + if (keyLen + 2 > recSize || + keyLen != kHeadSize - 2 + nameLen * 2) + return S_FALSE; + r += kHeadSize; + recSize -= kHeadSize; + + const Byte *name = r; + r += nameLen * 2; + recSize -= nameLen * 2; + + if (recSize < 4) + return S_FALSE; + + UInt32 recordType = Get32(r); + if (recordType != kAttrRecordType_Inline) + { + // Probably only kAttrRecordType_Inline now is used in real HFS files + HeadersError = true; + continue; + } + + const UInt32 kRecordHeaderSize = 16; + if (recSize < kRecordHeaderSize) + return S_FALSE; + UInt32 dataSize = Get32(r + 12); + + r += kRecordHeaderSize; + recSize -= kRecordHeaderSize; + + if (recSize < dataSize) + return S_FALSE; + + CAttr &attr = Attrs.AddNew(); + attr.ID = fileID; + attr.Pos = nodeOffset + offs + 2 + keyLen + kRecordHeaderSize; + attr.Size = dataSize; + LoadName(name, nameLen, attr.Name); + + if (progress && (i & 0xFFF) == 0) + { + UInt64 numFiles = 0; + RINOK(progress->SetCompleted(&numFiles, NULL)); + } + } + + node = desc.fLink; + } + return S_OK; +} + +static const UInt32 kMethod_Attr = 3; // data stored in attribute file +static const UInt32 kMethod_Resource = 4; // data stored in resource fork + +bool CDatabase::Parse_decmpgfs(const CAttr &attr, CItem &item, bool &skip) +{ + skip = false; + if (attr.Name != L"com.apple.decmpfs") + return true; + if (item.UseAttr || !item.DataFork.IsEmpty()) + return false; + + const UInt32 k_decmpfs_headerSize = 16; + UInt32 dataSize = attr.Size; + if (dataSize < k_decmpfs_headerSize) + return false; + const Byte *r = AttrBuf + attr.Pos; + if (GetUi32(r) != 0x636D7066) // magic == "fpmc" + return false; + item.Method = GetUi32(r + 4); + item.UnpackSize = GetUi64(r + 8); + dataSize -= k_decmpfs_headerSize; + r += k_decmpfs_headerSize; + if (item.Method == kMethod_Resource) + { + if (dataSize != 0) + return false; + item.UseAttr = true; + } + else if (item.Method == kMethod_Attr) + { + if (dataSize == 0) + return false; + Byte b = r[0]; + if ((b & 0xF) == 0xF) + { + dataSize--; + if (item.UnpackSize > dataSize) + return false; + item.DataPos = attr.Pos + k_decmpfs_headerSize + 1; + item.PackSize = dataSize; + item.UseAttr = true; + item.UseInlineData = true; + } + else + { + item.DataPos = attr.Pos + k_decmpfs_headerSize; + item.PackSize = dataSize; + item.UseAttr = true; + } + } + else + return false; + skip = true; + return true; +} + +HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents> *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress) +{ + unsigned reserveSize = (unsigned)(Header.NumFolders + 1 + Header.NumFiles); + Items.ClearAndReserve(reserveSize); + Refs.ClearAndReserve(reserveSize); + + CRecordVector<CIdIndexPair> IdToIndexMap; + IdToIndexMap.ClearAndReserve(reserveSize); + + CByteBuffer buf; + RINOK(ReadFile(fork, buf, inStream)); + const Byte *p = (const Byte *)buf; + + // CNodeDescriptor nodeDesc; + // nodeDesc.Parse(p); + CHeaderRec hr; + hr.Parse(p + kNodeDescriptor_Size); + + // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC); + + if ((buf.Size() >> hr.NodeSizeLog) < hr.TotalNodes) + return S_FALSE; + + CByteBuffer usedBuf(hr.TotalNodes); + memset(usedBuf, 0, hr.TotalNodes); + + CFork resFork; + + UInt32 node = hr.FirstLeafNode; + UInt32 numFiles = 0; + UInt32 numFolders = 0; + + while (node != 0) + { + if (node >= hr.TotalNodes || usedBuf[node] != 0) + return S_FALSE; + usedBuf[node] = 1; + + size_t nodeOffset = (size_t)node << hr.NodeSizeLog; + CNodeDescriptor desc; + desc.Parse(p + nodeOffset); + if (!desc.CheckNumRecords(hr.NodeSizeLog)) + return S_FALSE; + if (desc.Kind != kNodeType_Leaf) + return S_FALSE; + + 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); + UInt32 recSize = offsNext - offs; + if (offs >= nodeSize + || offs >= nodeSize + || offsNext < offs + || recSize < 6) + return S_FALSE; + + const Byte *r = p + nodeOffset + offs; + UInt32 keyLen = Get16(r); + UInt32 parentID = Get32(r + 2); + if (keyLen < 6 || (keyLen & 1) != 0 || keyLen + 2 > recSize) + return S_FALSE; + r += 6; + recSize -= 6; + keyLen -= 6; + + unsigned nameLen = Get16(r); + if (nameLen * 2 != (unsigned)keyLen) + return S_FALSE; + r += 2; + recSize -= 2; + + r += nameLen * 2; + recSize -= nameLen * 2; + + if (recSize < 2) + return S_FALSE; + UInt16 type = Get16(r); + + if (type != RECORD_TYPE_FOLDER && + type != RECORD_TYPE_FILE) + continue; + + const unsigned kBasicRecSize = 0x58; + if (recSize < kBasicRecSize) + return S_FALSE; + + CItem &item = Items.AddNew(); + item.ParentID = parentID; + item.Type = type; + // item.Flags = Get16(r + 2); + // item.Valence = Get32(r + 4); + item.ID = Get32(r + 8); + { + const Byte *name = r - (nameLen * 2); + LoadName(name, nameLen, item.Name); + if (item.Name.Len() <= 1) + { + if (item.Name.IsEmpty() && nameLen == 21) + { + if (GetUi32(name) == 0 && + GetUi32(name + 4) == 0 && + IsNameEqualTo(name + 8, "HFS+ Private Data")) + { + // it's folder for "Hard Links" files + item.Name = L"[HFS+ Private Data]"; + } + } + + // Some dmg files have ' ' folder item. + if (item.Name.IsEmpty() || item.Name[0] == L' ') + item.Name = L"[]"; + } + } + + item.CTime = Get32(r + 0xC); + item.MTime = Get32(r + 0x10); + // item.AttrMTime = Get32(r + 0x14); + item.ATime = Get32(r + 0x18); + // item.BackupDate = Get32(r + 0x1C); + + /* + item.OwnerID = Get32(r + 0x20); + item.GroupID = Get32(r + 0x24); + item.AdminFlags = r[0x28]; + item.OwnerFlags = r[0x29]; + item.FileMode = Get16(r + 0x2A); + item.special.iNodeNum = Get16(r + 0x2C); // or .linkCount + item.FileType = Get32(r + 0x30); + item.FileCreator = Get32(r + 0x34); + item.FinderFlags = Get16(r + 0x38); + item.Point[0] = Get16(r + 0x3A); // v + item.Point[1] = Get16(r + 0x3C); // h + */ + + // const refIndex = Refs.Size(); + CIdIndexPair pair; + pair.ID = item.ID; + pair.Index = Items.Size() - 1; + IdToIndexMap.Add(pair); + + recSize -= kBasicRecSize; + r += kBasicRecSize; + if (item.IsDir()) + { + numFolders++; + if (recSize != 0) + return S_FALSE; + } + else + { + numFiles++; + const unsigned kForkRecSize = 16 + kNumFixedExtents * 8; + if (recSize != kForkRecSize * 2) + return S_FALSE; + + item.DataFork.Parse(r); + + if (!item.DataFork.UpgradeAndTest(overflowExtentsArray[0], item.ID, Header.BlockSizeLog)) + HeadersError = true; + + item.ResourceFork.Parse(r + kForkRecSize); + if (!item.ResourceFork.IsEmpty()) + { + if (!item.ResourceFork.UpgradeAndTest(overflowExtentsArray[1], item.ID, Header.BlockSizeLog)) + HeadersError = true; + ThereAreAltStreams = true; + } + } + if (progress && (Items.Size() & 0xFFF) == 0) + { + UInt64 numItems = Items.Size(); + RINOK(progress->SetCompleted(&numItems, NULL)); + } + } + node = desc.fLink; + } + + if (Header.NumFiles != numFiles || + Header.NumFolders + 1 != numFolders) + HeadersError = true; + + IdToIndexMap.Sort2(); + { + for (unsigned i = 1; i < IdToIndexMap.Size(); i++) + if (IdToIndexMap[i - 1].ID == IdToIndexMap[i].ID) + return S_FALSE; + } + + + CBoolArr skipAttr(Attrs.Size()); + { + for (unsigned i = 0; i < Attrs.Size(); i++) + skipAttr[i] = false; + } + + { + FOR_VECTOR (i, Attrs) + { + const CAttr &attr = Attrs[i]; + + int itemIndex = FindItemIndex(IdToIndexMap, attr.ID); + if (itemIndex < 0) + { + HeadersError = true; + continue; + } + if (!Parse_decmpgfs(attr, Items[itemIndex], skipAttr[i])) + HeadersError = true; + } + } + + IdToIndexMap.ClearAndReserve(Items.Size()); + + { + FOR_VECTOR (i, Items) + { + const CItem &item = Items[i]; + + CIdIndexPair pair; + pair.ID = item.ID; + pair.Index = Refs.Size(); + IdToIndexMap.Add(pair); + + CRef ref; + ref.ItemIndex = i; + Refs.Add(ref); + + #ifdef HFS_SHOW_ALT_STREAMS + + if (item.ResourceFork.IsEmpty()) + continue; + if (item.UseAttr && item.Method == kMethod_Resource) + continue; + CRef resRef; + resRef.ItemIndex = i; + resRef.IsResource = true; + resRef.Parent = Refs.Size() - 1; + Refs.Add(resRef); + + #endif + } + } + + IdToIndexMap.Sort2(); + + { + FOR_VECTOR (i, Refs) + { + CRef &ref = Refs[i]; + if (ref.IsResource) + continue; + CItem &item = Items[ref.ItemIndex]; + ref.Parent = FindItemIndex(IdToIndexMap, item.ParentID); + if (ref.Parent >= 0) + { + if (!Items[Refs[ref.Parent].ItemIndex].IsDir()) + { + ref.Parent = -1; + HeadersError = true; + } + } + } + } + + #ifdef HFS_SHOW_ALT_STREAMS + { + FOR_VECTOR (i, Attrs) + { + if (skipAttr[i]) + continue; + const CAttr &attr = Attrs[i]; + + int refIndex = FindItemIndex(IdToIndexMap, attr.ID); + if (refIndex < 0) + { + HeadersError = true; + continue; + } + + CRef ref; + ref.AttrIndex = i; + ref.Parent = refIndex; + ref.ItemIndex = Refs[refIndex].ItemIndex; + Refs.Add(ref); + } + } + #endif + + return S_OK; +} + +static const unsigned kHeaderPadSize = (1 << 10); + +HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress) +{ + Clear(); + static const unsigned kHeaderSize = kHeaderPadSize + 512; + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)); + { + for (unsigned i = 0; i < kHeaderPadSize; i++) + if (buf[i] != 0) + return S_FALSE; + } + const Byte *p = buf + kHeaderPadSize; + CVolHeader &h = Header; + + h.Header[0] = p[0]; + h.Header[1] = p[1]; + if (p[0] != 'H' || (p[1] != '+' && p[1] != 'X')) + return S_FALSE; + h.Version = Get16(p + 2); + if (h.Version < 4 || h.Version > 5) + return S_FALSE; + + // h.Attr = Get32(p + 4); + // h.LastMountedVersion = Get32(p + 8); + // h.JournalInfoBlock = Get32(p + 0xC); + + h.CTime = Get32(p + 0x10); + h.MTime = Get32(p + 0x14); + // h.BackupTime = Get32(p + 0x18); + // h.CheckedTime = Get32(p + 0x1C); + + h.NumFiles = Get32(p + 0x20); + h.NumFolders = Get32(p + 0x24); + + if (h.NumFolders > ((UInt32)1 << 29) || + h.NumFiles > ((UInt32)1 << 30)) + return S_FALSE; + if (progress) + { + UInt64 numFiles = (UInt64)h.NumFiles + h.NumFolders + 1; + RINOK(progress->SetTotal(&numFiles, NULL)); + } + + UInt32 blockSize = Get32(p + 0x28); + + { + unsigned i; + for (i = 9; ((UInt32)1 << i) != blockSize; i++) + if (i == 31) + return S_FALSE; + h.BlockSizeLog = i; + } + + h.NumBlocks = Get32(p + 0x2C); + h.NumFreeBlocks = Get32(p + 0x30); + + /* + h.NextCalatlogNodeID = Get32(p + 0x40); + h.WriteCount = Get32(p + 0x44); + for (i = 0; i < 6; i++) + h.FinderInfo[i] = Get32(p + 0x50 + i * 4); + h.VolID = Get64(p + 0x68); + */ + + /* + UInt64 endPos; + RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); + if ((endPos >> h.BlockSizeLog) < h.NumBlocks) + return S_FALSE; + */ + + ResFileName = kResFileName; + + CFork extentsFork, catalogFork, attrFork; + // allocationFork.Parse(p + 0x70 + 0x50 * 0); + extentsFork.Parse(p + 0x70 + 0x50 * 1); + catalogFork.Parse(p + 0x70 + 0x50 * 2); + attrFork.Parse (p + 0x70 + 0x50 * 3); + // startupFork.Parse(p + 0x70 + 0x50 * 4); + + CObjectVector<CIdExtents> overflowExtents[2]; + if (!extentsFork.IsOk(Header.BlockSizeLog)) + HeadersError = true; + else + { + HRESULT res = LoadExtentFile(extentsFork, inStream, overflowExtents); + if (res == S_FALSE) + HeadersError = true; + else if (res != S_OK) + return res; + } + + if (!catalogFork.UpgradeAndTest(overflowExtents[0], kHfsID_CatalogFile, Header.BlockSizeLog)) + return S_FALSE; + + if (!attrFork.UpgradeAndTest(overflowExtents[0], kHfsID_AttributesFile, Header.BlockSizeLog)) + HeadersError = true; + else + { + if (attrFork.Size != 0) + RINOK(LoadAttrs(attrFork, inStream, progress)); + } + + RINOK(LoadCatalog(catalogFork, overflowExtents, inStream, progress)); + + PhySize = Header.GetPhySize(); + return S_OK; +} + + + +class CHandler: + public IInArchive, + public IArchiveGetRawProps, + public IInArchiveGetStream, + public CMyUnknownImp, + public CDatabase +{ + CMyComPtr<IInStream> _stream; + + HRESULT GetForkStream(const CFork &fork, ISequentialInStream **stream); + + HRESULT ExtractZlibFile( + ISequentialOutStream *realOutStream, + const CItem &item, + NCompress::NZlib::CDecoder *_zlibDecoderSpec, + CByteBuffer &buf, + UInt64 progressStart, + IArchiveExtractCallback *extractCallback); +public: + MY_UNKNOWN_IMP3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream) + INTERFACE_IInArchive(;) + INTERFACE_IArchiveGetRawProps(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidCTime, + kpidMTime, + kpidATime, + kpidPosixAttrib +}; + +static const Byte kArcProps[] = +{ + kpidMethod, + kpidClusterSize, + kpidFreeSpace, + kpidCTime, + kpidMTime +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop) +{ + FILETIME ft; + HfsTimeToFileTime(hfsTime, ft); + prop = ft; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidExtension: prop = Header.IsHfsX() ? "hfsx" : "hfs"; break; + case kpidMethod: prop = Header.IsHfsX() ? "HFSX" : "HFS+"; break; + case kpidPhySize: prop = PhySize; break; + case kpidClusterSize: prop = (UInt32)1 << Header.BlockSizeLog; break; + case kpidFreeSpace: prop = (UInt64)Header.GetFreeSize(); break; + case kpidMTime: HfsTimeToProp(Header.MTime, prop); break; + case kpidCTime: + { + FILETIME localFt, ft; + HfsTimeToFileTime(Header.CTime, localFt); + if (LocalFileTimeToFileTime(&localFt, &ft)) + prop = ft; + break; + } + case kpidIsTree: prop = true; break; + case kpidErrorFlags: + { + UInt32 flags = 0; + if (HeadersError) flags |= kpv_ErrorFlags_HeadersError; + if (flags != 0) + prop = flags; + break; + } + case kpidIsAltStream: prop = ThereAreAltStreams; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) +{ + *numProps = 0; + return S_OK; +} + +STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) +{ + *name = NULL; + *propID = 0; + return S_OK; +} + +STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType) +{ + const CRef &ref = Refs[index]; + *parentType = ref.IsAltStream() ? + NParentType::kAltStream : + NParentType::kDir; + *parent = (UInt32)(Int32)ref.Parent; + return S_OK; +} + +STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + #ifdef MY_CPU_LE + if (propID == kpidName) + { + const CRef &ref = Refs[index]; + const UString *s; + if (ref.IsResource) + s = &ResFileName; + else if (ref.AttrIndex >= 0) + s = &Attrs[ref.AttrIndex].Name; + else + s = &Items[ref.ItemIndex].Name; + *data = (const wchar_t *)(*s); + *dataSize = (s->Len() + 1) * sizeof(wchar_t); + *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE; + return S_OK; + } + #endif + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CRef &ref = Refs[index]; + const CItem &item = Items[ref.ItemIndex]; + switch (propID) + { + case kpidPath: GetItemPath(index, prop); break; + case kpidName: + const UString *s; + if (ref.IsResource) + s = &ResFileName; + else if (ref.AttrIndex >= 0) + s = &Attrs[ref.AttrIndex].Name; + else + s = &item.Name; + prop = *s; + break; + case kpidPackSize: + { + UInt64 size; + if (ref.AttrIndex >= 0) + size = Attrs[ref.AttrIndex].Size; + else if (item.IsDir()) + break; + else if (item.UseAttr) + { + if (item.Method == kMethod_Resource) + size = item.ResourceFork.NumBlocks << Header.BlockSizeLog; + else + size = item.PackSize; + } + else + size = item.GetFork(ref.IsResource).NumBlocks << Header.BlockSizeLog; + prop = size; + break; + } + case kpidSize: + { + UInt64 size; + if (ref.AttrIndex >= 0) + size = Attrs[ref.AttrIndex].Size; + else if (item.IsDir()) + break; + else if (item.UseAttr) + size = item.UnpackSize; + else + size = item.GetFork(ref.IsResource).Size; + prop = size; + break; + } + case kpidIsDir: prop = item.IsDir(); break; + case kpidIsAltStream: prop = ref.IsAltStream(); break; + + case kpidCTime: HfsTimeToProp(item.CTime, prop); break; + case kpidMTime: HfsTimeToProp(item.MTime, prop); break; + case kpidATime: HfsTimeToProp(item.ATime, prop); break; + + case kpidPosixAttrib: if (ref.AttrIndex < 0) prop = (UInt32)item.FileMode; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(inStream, callback)); + _stream = inStream; + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _stream.Release(); + Clear(); + return S_OK; +} + +static const UInt32 kCompressionBlockSize = 1 << 16; + +HRESULT CHandler::ExtractZlibFile( + ISequentialOutStream *outStream, + const CItem &item, + NCompress::NZlib::CDecoder *_zlibDecoderSpec, + CByteBuffer &buf, + UInt64 progressStart, + IArchiveExtractCallback *extractCallback) +{ + CMyComPtr<ISequentialInStream> inStream; + const CFork &fork = item.ResourceFork; + RINOK(GetForkStream(fork, &inStream)); + const unsigned kHeaderSize = 0x100 + 8; + RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)); + UInt32 dataPos = Get32(buf); + UInt32 mapPos = Get32(buf + 4); + UInt32 dataSize = Get32(buf + 8); + UInt32 mapSize = Get32(buf + 12); + + const UInt32 kResMapSize = 50; + + if (mapSize != kResMapSize + || dataPos + dataSize != mapPos + || mapPos + mapSize != fork.Size) + return S_FALSE; + + UInt32 dataSize2 = Get32(buf + 0x100); + if (4 + dataSize2 != dataSize || dataSize2 < 8) + return S_FALSE; + + UInt32 numBlocks = GetUi32(buf + 0x100 + 4); + if (((dataSize2 - 4) >> 3) < numBlocks) + return S_FALSE; + if (item.UnpackSize > (UInt64)numBlocks * kCompressionBlockSize) + return S_FALSE; + + if (item.UnpackSize + kCompressionBlockSize < (UInt64)numBlocks * kCompressionBlockSize) + return S_FALSE; + + UInt32 tableSize = (numBlocks << 3); + + CByteBuffer tableBuf(tableSize); + + RINOK(ReadStream_FALSE(inStream, tableBuf, tableSize)); + + UInt32 prev = 4 + tableSize; + + UInt32 i; + for (i = 0; i < numBlocks; i++) + { + UInt32 offset = GetUi32(tableBuf + i * 8); + UInt32 size = GetUi32(tableBuf + i * 8 + 4); + if (size == 0) + return S_FALSE; + if (prev != offset) + return S_FALSE; + if (offset > dataSize2 || + size > dataSize2 - offset) + return S_FALSE; + prev = offset + size; + } + + if (prev != dataSize2) + return S_FALSE; + + CBufInStream *bufInStreamSpec = new CBufInStream; + CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec; + + UInt64 outPos = 0; + for (i = 0; i < numBlocks; i++) + { + UInt64 rem = item.UnpackSize - outPos; + if (rem == 0) + return S_FALSE; + UInt32 blockSize = kCompressionBlockSize; + if (rem < kCompressionBlockSize) + blockSize = (UInt32)rem; + + UInt32 size = GetUi32(tableBuf + i * 8 + 4); + + RINOK(ReadStream_FALSE(inStream, buf, size)); + + if ((buf[0] & 0xF) == 0xF) + { + // that code was not tested. Are there HFS archives with uncompressed block + if (size - 1 != blockSize) + return S_FALSE; + + if (outStream) + { + RINOK(WriteStream(outStream, buf, blockSize)); + } + } + else + { + UInt64 blockSize64 = blockSize; + bufInStreamSpec->Init(buf, size); + RINOK(_zlibDecoderSpec->Code(bufInStream, outStream, NULL, &blockSize64, NULL)); + if (_zlibDecoderSpec->GetOutputProcessedSize() != blockSize || + _zlibDecoderSpec->GetInputProcessedSize() != size) + return S_FALSE; + } + + outPos += blockSize; + UInt64 progressPos = progressStart + outPos; + RINOK(extractCallback->SetCompleted(&progressPos)); + } + + if (outPos != item.UnpackSize) + return S_FALSE; + + /* We check Resource Map + Are there HFS files with another values in Resource Map ??? */ + + RINOK(ReadStream_FALSE(inStream, buf, mapSize)); + UInt32 types = Get16(buf + 24); + UInt32 names = Get16(buf + 26); + UInt32 numTypes = Get16(buf + 28); + if (numTypes != 0 || types != 28 || names != kResMapSize) + return S_FALSE; + UInt32 resType = Get32(buf + 30); + UInt32 numResources = Get16(buf + 34); + UInt32 resListOffset = Get16(buf + 36); + if (resType != 0x636D7066) // cmpf + return S_FALSE; + if (numResources != 0 || resListOffset != 10) + return S_FALSE; + + UInt32 entryId = Get16(buf + 38); + UInt32 nameOffset = Get16(buf + 40); + // Byte attrib = buf[42]; + UInt32 resourceOffset = Get32(buf + 42) & 0xFFFFFF; + if (entryId != 1 || nameOffset != 0xFFFF || resourceOffset != 0) + return S_FALSE; + + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = Refs.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + UInt64 totalSize = 0; + for (i = 0; i < numItems; i++) + { + const CRef &ref = Refs[allFilesMode ? i : indices[i]]; + totalSize += Get_UnpackSize_of_Ref(ref); + } + RINOK(extractCallback->SetTotal(totalSize)); + + UInt64 currentTotalSize = 0, currentItemSize = 0; + + const size_t kBufSize = kCompressionBlockSize; + CByteBuffer buf(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header + + NCompress::NZlib::CDecoder *_zlibDecoderSpec = NULL; + CMyComPtr<ICompressCoder> _zlibDecoder; + + for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + { + RINOK(extractCallback->SetCompleted(¤tTotalSize)); + UInt32 index = allFilesMode ? i : indices[i]; + const CRef &ref = Refs[index]; + const CItem &item = Items[ref.ItemIndex]; + currentItemSize = Get_UnpackSize_of_Ref(ref); + + CMyComPtr<ISequentialOutStream> realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + if (ref.AttrIndex < 0 && item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + UInt64 pos = 0; + int res = NExtract::NOperationResult::kDataError; + if (ref.AttrIndex >= 0) + { + res = NExtract::NOperationResult::kOK; + if (realOutStream) + { + const CAttr &attr = Attrs[ref.AttrIndex]; + RINOK(WriteStream(realOutStream, AttrBuf + attr.Pos, attr.Size)); + } + } + else if (item.UseAttr) + { + if (item.UseInlineData) + { + res = NExtract::NOperationResult::kOK; + if (realOutStream) + { + RINOK(WriteStream(realOutStream, AttrBuf + item.DataPos, (size_t)item.UnpackSize)); + } + } + else + { + if (!_zlibDecoder) + { + _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); + _zlibDecoder = _zlibDecoderSpec; + } + + if (item.Method == kMethod_Attr) + { + CBufInStream *bufInStreamSpec = new CBufInStream; + CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec; + bufInStreamSpec->Init(AttrBuf + item.DataPos, item.PackSize); + + HRESULT hres = _zlibDecoder->Code(bufInStream, realOutStream, NULL, &item.UnpackSize, NULL); + if (hres != S_FALSE) + { + if (hres != S_OK) + return hres; + if (_zlibDecoderSpec->GetOutputProcessedSize() == item.UnpackSize && + _zlibDecoderSpec->GetInputProcessedSize() == item.PackSize) + res = NExtract::NOperationResult::kOK; + } + } + else + { + HRESULT hres = ExtractZlibFile(realOutStream, item, _zlibDecoderSpec, buf, + currentTotalSize, extractCallback); + if (hres != S_FALSE) + { + if (hres != S_OK) + return hres; + res = NExtract::NOperationResult::kOK; + } + } + } + } + else + { + const CFork &fork = item.GetFork(ref.IsResource); + if (fork.IsOk(Header.BlockSizeLog)) + { + res = NExtract::NOperationResult::kOK; + unsigned extentIndex; + for (extentIndex = 0; extentIndex < fork.Extents.Size(); extentIndex++) + { + if (res != NExtract::NOperationResult::kOK) + break; + if (fork.Size == pos) + break; + const CExtent &e = fork.Extents[extentIndex]; + RINOK(_stream->Seek((UInt64)e.Pos << Header.BlockSizeLog, STREAM_SEEK_SET, NULL)); + UInt64 extentRem = (UInt64)e.NumBlocks << Header.BlockSizeLog; + while (extentRem != 0) + { + UInt64 rem = fork.Size - pos; + if (rem == 0) + { + // Here we check that there are no extra (empty) blocks in last extent. + if (extentRem >= (UInt64)((UInt32)1 << Header.BlockSizeLog)) + res = NExtract::NOperationResult::kDataError; + break; + } + size_t cur = kBufSize; + if (cur > rem) + cur = (size_t)rem; + if (cur > extentRem) + cur = (size_t)extentRem; + RINOK(ReadStream(_stream, buf, &cur)); + if (cur == 0) + { + res = NExtract::NOperationResult::kDataError; + break; + } + if (realOutStream) + { + RINOK(WriteStream(realOutStream, buf, cur)); + } + pos += cur; + extentRem -= cur; + UInt64 processed = currentTotalSize + pos; + RINOK(extractCallback->SetCompleted(&processed)); + } + } + if (extentIndex != fork.Extents.Size() || fork.Size != pos) + res = NExtract::NOperationResult::kDataError; + } + } + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(res)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = Refs.Size(); + return S_OK; +} + +HRESULT CHandler::GetForkStream(const CFork &fork, ISequentialInStream **stream) +{ + *stream = 0; + + if (!fork.IsOk(Header.BlockSizeLog)) + return S_FALSE; + + CExtentsStream *extentStreamSpec = new CExtentsStream(); + CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec; + + UInt64 rem = fork.Size; + UInt64 virt = 0; + + FOR_VECTOR (i, fork.Extents) + { + const CExtent &e = fork.Extents[i]; + if (e.NumBlocks == 0) + continue; + UInt64 cur = ((UInt64)e.NumBlocks << Header.BlockSizeLog); + if (cur > rem) + { + cur = rem; + if (i != fork.Extents.Size() - 1) + return S_FALSE; + } + CSeekExtent se; + se.Phy = (UInt64)e.Pos << Header.BlockSizeLog; + se.Virt = virt; + virt += cur; + rem -= cur; + extentStreamSpec->Extents.Add(se); + } + + if (rem != 0) + return S_FALSE; + + CSeekExtent se; + se.Phy = 0; + se.Virt = virt; + extentStreamSpec->Extents.Add(se); + extentStreamSpec->Stream = _stream; + extentStreamSpec->Init(); + *stream = extentStream.Detach(); + return S_OK; +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + *stream = 0; + + const CRef &ref = Refs[index]; + if (ref.AttrIndex >= 0) + return S_FALSE; + const CItem &item = Items[ref.ItemIndex]; + if (item.IsDir() || item.UseAttr) + return S_FALSE; + + return GetForkStream(item.GetFork(ref.IsResource), stream); +} + +IMP_CreateArcIn + +static CArcInfo g_ArcInfo = + { "HFS", "hfs hfsx", 0, 0xE3, + 2 * (4 + 1), + { + 4, 'H', '+', 0, 4, + 4, 'H', 'X', 0, 5, + }, + kHeaderPadSize, + NArcInfoFlags::kMultiSignature, + CreateArc }; + +REGISTER_ARC(Hfs) + +}} diff --git a/CPP/7zip/Archive/IArchive.h b/CPP/7zip/Archive/IArchive.h index 85320276..63e16ac3 100755..100644 --- a/CPP/7zip/Archive/IArchive.h +++ b/CPP/7zip/Archive/IArchive.h @@ -20,20 +20,43 @@ namespace NFileTimeType }; } +namespace NArcInfoFlags +{ + const UInt32 kKeepName = 1 << 0; // keep name of file in archive name + const UInt32 kAltStreams = 1 << 1; // the handler supports alt streams + const UInt32 kNtSecure = 1 << 2; // the handler supports NT security + const UInt32 kFindSignature = 1 << 3; // the handler can find start of archive + const UInt32 kMultiSignature = 1 << 4; // there are several signatures + const UInt32 kUseGlobalOffset = 1 << 5; // the seek position of stream must be set as global offset + const UInt32 kStartOpen = 1 << 6; // call handler for each start position + const UInt32 kPureStartOpen = 1 << 7; // call handler only for start of file + const UInt32 kBackwardOpen = 1 << 8; // archive can be open backward + const UInt32 kPreArc = 1 << 9; // such archive can be stored before real archive (like SFX stub) + const UInt32 kSymLinks = 1 << 10; // the handler supports symbolic links + const UInt32 kHardLinks = 1 << 11; // the handler supports hard links +} + namespace NArchive { - enum + namespace NHandlerPropID { - kName = 0, - kClassID, - kExtension, - kAddExtension, - kUpdate, - kKeepName, - kStartSignature, - kFinishSignature, - kAssociate - }; + enum + { + kName = 0, // VT_BSTR + kClassID, // binary GUID in VT_BSTR + kExtension, // VT_BSTR + kAddExtension, // VT_BSTR + kUpdate, // VT_BOOL + kKeepName, // VT_BOOL + kSignature, // binary in VT_BSTR + kMultiSignature, // binary in VT_BSTR + kSignatureOffset, // VT_UI4 + kAltStreams, // VT_BOOL + kNtSecure, // VT_BOOL + kFlags // VT_UI4 + // kVersion // VT_UI4 ((VER_MAJOR << 8) | VER_MINOR) + }; + } namespace NExtract { @@ -46,25 +69,32 @@ namespace NArchive kSkip }; } + namespace NOperationResult { enum { kOK = 0, - kUnSupportedMethod, + kUnsupportedMethod, kDataError, - kCRCError + kCRCError, + kUnavailable, + kUnexpectedEnd, + kDataAfterEnd, + kIsNotArc, + kHeadersError }; } } + namespace NUpdate { namespace NOperationResult { enum { - kOK = 0, - kError + kOK = 0 + , // kError }; } } @@ -79,10 +109,16 @@ ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10) INTERFACE_IArchiveOpenCallback(PURE); }; +/* +IArchiveExtractCallback::GetStream + Result: + (*inStream == NULL) - for directories + (*inStream == NULL) - if link (hard link or symbolic link) was created +*/ #define INTERFACE_IArchiveExtractCallback(x) \ INTERFACE_IProgress(x) \ - STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \ + STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \ STDMETHOD(PrepareOperation)(Int32 askExtractMode) x; \ STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) x; \ @@ -115,41 +151,175 @@ ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50) /* +IInArchive::Open + stream + if (kUseGlobalOffset), stream current position can be non 0. + if (!kUseGlobalOffset), stream current position is 0. + if (maxCheckStartPosition == NULL), the handler can try to search archive start in stream + if (*maxCheckStartPosition == 0), the handler must check only current position as archive start + IInArchive::Extract: indices must be sorted - numItems = 0xFFFFFFFF means "all files" + numItems = (UInt32)(Int32)-1 = 0xFFFFFFFF means "all files" testMode != 0 means "test files without writing to outStream" + +IInArchive::GetArchiveProperty: + kpidOffset - start offset of archive. + VT_EMPTY : means offset = 0. + VT_UI4, VT_UI8, VT_I8 : result offset; negative values is allowed + kpidPhySize - size of archive. VT_EMPTY means unknown size. + kpidPhySize is allowed to be larger than file size. In that case it must show + supposed size. + + kpidIsDeleted: + kpidIsAltStream: + kpidIsAux: + kpidINode: + must return VARIANT_TRUE (VT_BOOL), if archive can support that property in GetProperty. + + +Notes: + Don't call IInArchive functions for same IInArchive object from different threads simultaneously. + Some IInArchive handlers will work incorrectly in that case. */ #define INTERFACE_IInArchive(x) \ - STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openArchiveCallback) x; \ - STDMETHOD(Close)() x; \ - STDMETHOD(GetNumberOfItems)(UInt32 *numItems) x; \ - STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \ - STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) x; \ - STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) x; \ - STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties) x; \ - STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \ - STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProperties) x; \ - STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; + STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) throw() x; \ + STDMETHOD(Close)() throw() x; \ + STDMETHOD(GetNumberOfItems)(UInt32 *numItems) throw() x; \ + STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) throw() x; \ + STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) throw() x; \ + STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) throw() x; \ + STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) throw() x; \ + STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) throw() x; \ + STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) throw() x; \ + STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) throw() x; ARCHIVE_INTERFACE(IInArchive, 0x60) { INTERFACE_IInArchive(PURE) }; +namespace NParentType +{ + enum + { + kDir = 0, + kAltStream + }; +}; + +namespace NPropDataType +{ + const UInt32 kMask_ZeroEnd = 1 << 4; + // const UInt32 kMask_BigEndian = 1 << 5; + const UInt32 kMask_Utf = 1 << 6; + // const UInt32 kMask_Utf8 = kMask_Utf | 0; + const UInt32 kMask_Utf16 = kMask_Utf | 1; + // const UInt32 kMask_Utf32 = kMask_Utf | 2; + + const UInt32 kNotDefined = 0; + const UInt32 kRaw = 1; + const UInt32 kUtf16z = kMask_Utf16 | kMask_ZeroEnd; +}; + +// UTF string (pointer to wchar_t) with zero end and little-endian. +#define PROP_DATA_TYPE_wchar_t_PTR_Z_LE ((NPropDataType::kMask_Utf | NPropDataType::kMask_ZeroEnd) + (sizeof(wchar_t) >> 1)) + +/* +GetRawProp: + Result: + S_OK - even if property is not set +*/ + +#define INTERFACE_IArchiveGetRawProps(x) \ + STDMETHOD(GetParent)(UInt32 index, UInt32 *parent, UInt32 *parentType) x; \ + STDMETHOD(GetRawProp)(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \ + STDMETHOD(GetNumRawProps)(UInt32 *numProps) x; \ + STDMETHOD(GetRawPropInfo)(UInt32 index, BSTR *name, PROPID *propID) x; + +ARCHIVE_INTERFACE(IArchiveGetRawProps, 0x70) +{ + INTERFACE_IArchiveGetRawProps(PURE) +}; + +#define INTERFACE_IArchiveGetRootProps(x) \ + STDMETHOD(GetRootProp)(PROPID propID, PROPVARIANT *value) x; \ + STDMETHOD(GetRootRawProp)(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \ + +ARCHIVE_INTERFACE(IArchiveGetRootProps, 0x71) +{ + INTERFACE_IArchiveGetRootProps(PURE) +}; + ARCHIVE_INTERFACE(IArchiveOpenSeq, 0x61) { STDMETHOD(OpenSeq)(ISequentialInStream *stream) PURE; }; +/* + OpenForSize + Result: + S_FALSE - is not archive + ? - DATA error +*/ + +/* +const UInt32 kOpenFlags_RealPhySize = 1 << 0; +const UInt32 kOpenFlags_NoSeek = 1 << 1; +// const UInt32 kOpenFlags_BeforeExtract = 1 << 2; +*/ + +/* +Flags: + 0 - opens archive with IInStream, if IInStream interface is supported + - if phySize is not available, it doesn't try to make full parse to get phySize + kOpenFlags_NoSeek - ArcOpen2 function doesn't use IInStream interface, even if it's available + kOpenFlags_RealPhySize - the handler will try to get PhySize, even if it requires full decompression for file + + if handler is not allowed to use IInStream and the flag kOpenFlags_RealPhySize is not specified, + the handler can return S_OK, but it doesn't check even Signature. + So next Extract can be called for that sequential stream. +*/ + +/* +ARCHIVE_INTERFACE(IArchiveOpen2, 0x62) +{ + STDMETHOD(ArcOpen2)(ISequentialInStream *stream, UInt32 flags, IArchiveOpenCallback *openCallback) PURE; +}; +*/ + +// ---------- UPDATE ---------- + +/* +GetUpdateItemInfo outs: +*newData *newProps + 0 0 - Copy data and properties from archive + 0 1 - Copy data from archive, request new properties + 1 0 - that combination is unused now + 1 1 - Request new data and new properties. It can be used even for folders + + indexInArchive = -1 if there is no item in archive, or if it doesn't matter. + + +GetStream out: + Result: + S_OK: + (*inStream == NULL) - only for directories + - the bug was fixed in 9.33: (*Stream == NULL) was in case of anti-file + (*inStream != NULL) - for any file, even for empty file or anti-file + S_FALSE - skip that file (don't add item to archive) - (client code can't open stream of that file by some reason) + (*inStream == NULL) + +The order of calling for hard links: + - GetStream() + - GetProperty(kpidHardLink) + +*/ + #define INTERFACE_IArchiveUpdateCallback(x) \ INTERFACE_IProgress(x); \ - STDMETHOD(GetUpdateItemInfo)(UInt32 index, \ - Int32 *newData, /*1 - new data, 0 - old data */ \ - Int32 *newProperties, /* 1 - new properties, 0 - old properties */ \ - UInt32 *indexInArchive /* -1 if there is no in archive, or if doesn't matter */ \ - ) x; \ + STDMETHOD(GetUpdateItemInfo)(UInt32 index, Int32 *newData, Int32 *newProps, UInt32 *indexInArchive) x; \ STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream) x; \ STDMETHOD(SetOperationResult)(Int32 operationResult) x; \ @@ -169,6 +339,27 @@ ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82) INTERFACE_IArchiveUpdateCallback2(PURE); }; +/* +UpdateItems() +------------- + + outStream: output stream. (the handler) MUST support the case when + Seek position in outStream is not ZERO. + but the caller calls with empty outStream and seek position is ZERO?? + + archives with stub: + + If archive is open and the handler and (Offset > 0), then the handler + knows about stub size. + UpdateItems(): + 1) the handler MUST copy that stub to outStream + 2) the caller MUST NOT copy the stub to outStream, if + "rsfx" property is set with SetProperties + + the handler must support the case where + ISequentialOutStream *outStream +*/ + #define INTERFACE_IOutArchive(x) \ STDMETHOD(UpdateItems)(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) x; \ @@ -182,47 +373,61 @@ ARCHIVE_INTERFACE(IOutArchive, 0xA0) ARCHIVE_INTERFACE(ISetProperties, 0x03) { - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) PURE; + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) PURE; +}; + +ARCHIVE_INTERFACE(IArchiveKeepModeForNextOpen, 0x04) +{ + STDMETHOD(KeepModeForNextOpen)() PURE; +}; + +/* Exe handler: the handler for executable format (PE, ELF, Mach-O). + SFX archive: executable stub + some tail data. + before 9.31: exe handler didn't parse SFX archives as executable format. + for 9.31+: exe handler parses SFX archives as executable format, only if AllowTail(1) was called */ + +ARCHIVE_INTERFACE(IArchiveAllowTail, 0x05) +{ + STDMETHOD(AllowTail)(Int32 allowTail) PURE; }; #define IMP_IInArchive_GetProp(k) \ (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \ - { if(index >= sizeof(k) / sizeof(k[0])) return E_INVALIDARG; \ - const STATPROPSTG &srcItem = k[index]; \ - *propID = srcItem.propid; *varType = srcItem.vt; *name = 0; return S_OK; } \ + { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \ + *propID = k[index]; *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; *name = 0; return S_OK; } \ #define IMP_IInArchive_GetProp_WITH_NAME(k) \ (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \ - { if(index >= sizeof(k) / sizeof(k[0])) return E_INVALIDARG; \ + { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \ const STATPROPSTG &srcItem = k[index]; \ *propID = srcItem.propid; *varType = srcItem.vt; \ if (srcItem.lpwstrName == 0) *name = 0; else *name = ::SysAllocString(srcItem.lpwstrName); return S_OK; } \ #define IMP_IInArchive_Props \ - STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) \ - { *numProperties = sizeof(kProps) / sizeof(kProps[0]); return S_OK; } \ + STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \ + { *numProps = ARRAY_SIZE(kProps); return S_OK; } \ STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp(kProps) #define IMP_IInArchive_Props_WITH_NAME \ - STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) \ - { *numProperties = sizeof(kProps) / sizeof(kProps[0]); return S_OK; } \ + STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \ + { *numProps = ARRAY_SIZE(kProps); return S_OK; } \ STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kProps) #define IMP_IInArchive_ArcProps \ - STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) \ - { *numProperties = sizeof(kArcProps) / sizeof(kArcProps[0]); return S_OK; } \ + STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \ + { *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \ STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp(kArcProps) #define IMP_IInArchive_ArcProps_WITH_NAME \ - STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) \ - { *numProperties = sizeof(kArcProps) / sizeof(kArcProps[0]); return S_OK; } \ + STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \ + { *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \ STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kArcProps) #define IMP_IInArchive_ArcProps_NO_Table \ - STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) \ - { *numProperties = 0; return S_OK; } \ + STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \ + { *numProps = 0; return S_OK; } \ STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *) \ { return E_NOTIMPL; } \ @@ -231,4 +436,32 @@ ARCHIVE_INTERFACE(ISetProperties, 0x03) STDMETHODIMP CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value) \ { value->vt = VT_EMPTY; return S_OK; } + + +#define k_IsArc_Res_NO 0 +#define k_IsArc_Res_YES 1 +#define k_IsArc_Res_NEED_MORE 2 +// #define k_IsArc_Res_YES_LOW_PROB 3 + +#define API_FUNC_IsArc EXTERN_C UInt32 WINAPI +#define API_FUNC_static_IsArc EXTERN_C static UInt32 WINAPI + +extern "C" +{ + typedef HRESULT (WINAPI *Func_CreateObject)(const GUID *clsID, const GUID *iid, void **outObject); + + typedef UInt32 (WINAPI *Func_IsArc)(const Byte *p, size_t size); + typedef HRESULT (WINAPI *Func_GetIsArc)(UInt32 formatIndex, Func_IsArc *isArc); + + typedef HRESULT (WINAPI *Func_GetNumberOfFormats)(UInt32 *numFormats); + typedef HRESULT (WINAPI *Func_GetHandlerProperty)(PROPID propID, PROPVARIANT *value); + typedef HRESULT (WINAPI *Func_GetHandlerProperty2)(UInt32 index, PROPID propID, PROPVARIANT *value); + + typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive); + typedef HRESULT (WINAPI *Func_SetLargePageMode)(); + + typedef IOutArchive * (*Func_CreateOutArchive)(); + typedef IInArchive * (*Func_CreateInArchive)(); +} + #endif diff --git a/CPP/7zip/Archive/Icons/7z.ico b/CPP/7zip/Archive/Icons/7z.ico Binary files differindex 319753a1..319753a1 100755..100644 --- a/CPP/7zip/Archive/Icons/7z.ico +++ b/CPP/7zip/Archive/Icons/7z.ico diff --git a/CPP/7zip/Archive/Icons/arj.ico b/CPP/7zip/Archive/Icons/arj.ico Binary files differindex c0f8b141..c0f8b141 100755..100644 --- a/CPP/7zip/Archive/Icons/arj.ico +++ b/CPP/7zip/Archive/Icons/arj.ico diff --git a/CPP/7zip/Archive/Icons/bz2.ico b/CPP/7zip/Archive/Icons/bz2.ico Binary files differindex f22abebc..f22abebc 100755..100644 --- a/CPP/7zip/Archive/Icons/bz2.ico +++ b/CPP/7zip/Archive/Icons/bz2.ico diff --git a/CPP/7zip/Archive/Icons/cab.ico b/CPP/7zip/Archive/Icons/cab.ico Binary files differindex c96c0f01..c96c0f01 100755..100644 --- a/CPP/7zip/Archive/Icons/cab.ico +++ b/CPP/7zip/Archive/Icons/cab.ico diff --git a/CPP/7zip/Archive/Icons/cpio.ico b/CPP/7zip/Archive/Icons/cpio.ico Binary files differindex 9abaabc7..9abaabc7 100755..100644 --- a/CPP/7zip/Archive/Icons/cpio.ico +++ b/CPP/7zip/Archive/Icons/cpio.ico diff --git a/CPP/7zip/Archive/Icons/deb.ico b/CPP/7zip/Archive/Icons/deb.ico Binary files differindex 97a08654..97a08654 100755..100644 --- a/CPP/7zip/Archive/Icons/deb.ico +++ b/CPP/7zip/Archive/Icons/deb.ico diff --git a/CPP/7zip/Archive/Icons/dmg.ico b/CPP/7zip/Archive/Icons/dmg.ico Binary files differindex 7d63b09f..7d63b09f 100755..100644 --- a/CPP/7zip/Archive/Icons/dmg.ico +++ b/CPP/7zip/Archive/Icons/dmg.ico diff --git a/CPP/7zip/Archive/Icons/fat.ico b/CPP/7zip/Archive/Icons/fat.ico Binary files differindex 7503d933..7503d933 100755..100644 --- a/CPP/7zip/Archive/Icons/fat.ico +++ b/CPP/7zip/Archive/Icons/fat.ico diff --git a/CPP/7zip/Archive/Icons/gz.ico b/CPP/7zip/Archive/Icons/gz.ico Binary files differindex d402a698..d402a698 100755..100644 --- a/CPP/7zip/Archive/Icons/gz.ico +++ b/CPP/7zip/Archive/Icons/gz.ico diff --git a/CPP/7zip/Archive/Icons/hfs.ico b/CPP/7zip/Archive/Icons/hfs.ico Binary files differindex bf2c1986..bf2c1986 100755..100644 --- a/CPP/7zip/Archive/Icons/hfs.ico +++ b/CPP/7zip/Archive/Icons/hfs.ico diff --git a/CPP/7zip/Archive/Icons/iso.ico b/CPP/7zip/Archive/Icons/iso.ico Binary files differindex b3e3ac2f..b3e3ac2f 100755..100644 --- a/CPP/7zip/Archive/Icons/iso.ico +++ b/CPP/7zip/Archive/Icons/iso.ico diff --git a/CPP/7zip/Archive/Icons/lzh.ico b/CPP/7zip/Archive/Icons/lzh.ico Binary files differindex 84dab49c..84dab49c 100755..100644 --- a/CPP/7zip/Archive/Icons/lzh.ico +++ b/CPP/7zip/Archive/Icons/lzh.ico diff --git a/CPP/7zip/Archive/Icons/lzma.ico b/CPP/7zip/Archive/Icons/lzma.ico Binary files differindex 2de2c249..2de2c249 100755..100644 --- a/CPP/7zip/Archive/Icons/lzma.ico +++ b/CPP/7zip/Archive/Icons/lzma.ico diff --git a/CPP/7zip/Archive/Icons/ntfs.ico b/CPP/7zip/Archive/Icons/ntfs.ico Binary files differindex 6b2aeb00..6b2aeb00 100755..100644 --- a/CPP/7zip/Archive/Icons/ntfs.ico +++ b/CPP/7zip/Archive/Icons/ntfs.ico diff --git a/CPP/7zip/Archive/Icons/rar.ico b/CPP/7zip/Archive/Icons/rar.ico Binary files differindex 2918d294..2918d294 100755..100644 --- a/CPP/7zip/Archive/Icons/rar.ico +++ b/CPP/7zip/Archive/Icons/rar.ico diff --git a/CPP/7zip/Archive/Icons/rpm.ico b/CPP/7zip/Archive/Icons/rpm.ico Binary files differindex cdeb8d1b..cdeb8d1b 100755..100644 --- a/CPP/7zip/Archive/Icons/rpm.ico +++ b/CPP/7zip/Archive/Icons/rpm.ico diff --git a/CPP/7zip/Archive/Icons/split.ico b/CPP/7zip/Archive/Icons/split.ico Binary files differindex 65723ff3..65723ff3 100755..100644 --- a/CPP/7zip/Archive/Icons/split.ico +++ b/CPP/7zip/Archive/Icons/split.ico diff --git a/CPP/7zip/Archive/Icons/squashfs.ico b/CPP/7zip/Archive/Icons/squashfs.ico Binary files differindex b802d942..b802d942 100755..100644 --- a/CPP/7zip/Archive/Icons/squashfs.ico +++ b/CPP/7zip/Archive/Icons/squashfs.ico diff --git a/CPP/7zip/Archive/Icons/tar.ico b/CPP/7zip/Archive/Icons/tar.ico Binary files differindex 6835885b..6835885b 100755..100644 --- a/CPP/7zip/Archive/Icons/tar.ico +++ b/CPP/7zip/Archive/Icons/tar.ico diff --git a/CPP/7zip/Archive/Icons/vhd.ico b/CPP/7zip/Archive/Icons/vhd.ico Binary files differindex 33bed3c9..33bed3c9 100755..100644 --- a/CPP/7zip/Archive/Icons/vhd.ico +++ b/CPP/7zip/Archive/Icons/vhd.ico diff --git a/CPP/7zip/Archive/Icons/wim.ico b/CPP/7zip/Archive/Icons/wim.ico Binary files differindex 887975e6..887975e6 100755..100644 --- a/CPP/7zip/Archive/Icons/wim.ico +++ b/CPP/7zip/Archive/Icons/wim.ico diff --git a/CPP/7zip/Archive/Icons/xar.ico b/CPP/7zip/Archive/Icons/xar.ico Binary files differindex 281aa7dc..281aa7dc 100755..100644 --- a/CPP/7zip/Archive/Icons/xar.ico +++ b/CPP/7zip/Archive/Icons/xar.ico diff --git a/CPP/7zip/Archive/Icons/xz.ico b/CPP/7zip/Archive/Icons/xz.ico Binary files differindex bc07a7eb..bc07a7eb 100755..100644 --- a/CPP/7zip/Archive/Icons/xz.ico +++ b/CPP/7zip/Archive/Icons/xz.ico diff --git a/CPP/7zip/Archive/Icons/z.ico b/CPP/7zip/Archive/Icons/z.ico Binary files differindex 2db53583..2db53583 100755..100644 --- a/CPP/7zip/Archive/Icons/z.ico +++ b/CPP/7zip/Archive/Icons/z.ico diff --git a/CPP/7zip/Archive/Icons/zip.ico b/CPP/7zip/Archive/Icons/zip.ico Binary files differindex 2af46066..2af46066 100755..100644 --- a/CPP/7zip/Archive/Icons/zip.ico +++ b/CPP/7zip/Archive/Icons/zip.ico diff --git a/CPP/7zip/Archive/IhexHandler.cpp b/CPP/7zip/Archive/IhexHandler.cpp new file mode 100644 index 00000000..bc468401 --- /dev/null +++ b/CPP/7zip/Archive/IhexHandler.cpp @@ -0,0 +1,500 @@ +// IhexHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/DynamicBuffer.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyVector.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" +#include "../Common/InBuffer.h" + +namespace NArchive { +namespace NIhex { + +/* We still don't support files with custom record types: 20, 22: used by Samsung */ + +struct CBlock +{ + CByteDynamicBuffer Data; + UInt32 Offset; +}; + +class CHandler: + public IInArchive, + public CMyUnknownImp +{ + bool _isArc; + bool _needMoreInput; + bool _dataError; + + UInt64 _phySize; + + CObjectVector<CBlock> _blocks; +public: + MY_UNKNOWN_IMP1(IInArchive) + INTERFACE_IInArchive(;) +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidVa +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _blocks.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; + if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_dataError) v |= kpv_ErrorFlags_DataError; + prop = v; + } + } + prop.Detach(value); + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CBlock &block = _blocks[index]; + switch (propID) + { + case kpidSize: prop = block.Data.GetPos(); break; + case kpidVa: prop = block.Offset; break; + case kpidPath: + { + if (_blocks.Size() != 1) + { + char s[16]; + ConvertUInt32ToString(index, s); + prop = s; + } + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +static inline int HexToByte(char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + return -1; +} + +static int Parse(const Byte *p) +{ + int c1 = HexToByte(p[0]); if (c1 < 0) return -1; + int c2 = HexToByte(p[1]); if (c2 < 0) return -1; + return (c1 << 4) | c2; +} + +#define kType_Data 0 +#define kType_Eof 1 +#define kType_Seg 2 +#define kType_CsIp 3 +#define kType_High 4 +#define kType_Ip32 5 + +#define kType_MAX 5 + +#define IS_LINE_DELIMITER(c) ((c) == 0 || (c) == 10 || (c) == 13) + +API_FUNC_static_IsArc IsArc_Ihex(const Byte *p, size_t size) +{ + if (size < 1) + return k_IsArc_Res_NEED_MORE; + if (p[0] != ':') + return k_IsArc_Res_NO; + p++; + size--; + + const int kNumLinesToCheck = 3; // 1 line is OK also, but we don't want false detection + + for (int j = 0; j < kNumLinesToCheck; j++) + { + if (size < 4 * 2) + return k_IsArc_Res_NEED_MORE; + + int num = Parse(p); + if (num < 0) + return k_IsArc_Res_NO; + + int type = Parse(p + 6); + if (type < 0 || type > kType_MAX) + return k_IsArc_Res_NO; + + unsigned numChars = ((unsigned)num + 5) * 2; + unsigned sum = 0; + + for (unsigned i = 0; i < numChars; i += 2) + { + if (i + 2 > size) + return k_IsArc_Res_NEED_MORE; + int v = Parse(p + i); + if (v < 0) + return k_IsArc_Res_NO; + sum += (unsigned)v; + } + + if ((sum & 0xFF) != 0) + return k_IsArc_Res_NO; + + if (type == kType_Data) + { + // we don't want to open :0000000000 files + if (num == 0) + return k_IsArc_Res_NO; + } + else + { + if (type == kType_Eof) + { + if (num != 0) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; + } + if (p[2] != 0 || + p[3] != 0 || + p[4] != 0 || + p[5] != 0) + return k_IsArc_Res_NO; + if (type == kType_Seg || type == kType_High) + { + if (num != 2) + return k_IsArc_Res_NO; + } + else + { + if (num != 4) + return k_IsArc_Res_NO; + } + } + + p += numChars; + size -= numChars; + + for (;;) + { + if (size == 0) + return k_IsArc_Res_NEED_MORE; + char b = *p++; + size--; + if (IS_LINE_DELIMITER(b)) + continue; + if (b == ':') + break; + return k_IsArc_Res_NO; + } + } + + return k_IsArc_Res_YES; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *) +{ + COM_TRY_BEGIN + { + Close(); + try + { + const unsigned kStartSize = (2 + (256 + 5) + 2) * 2; + Byte temp[kStartSize]; + { + size_t size = kStartSize; + RINOK(ReadStream(stream, temp, &size)); + UInt32 isArcRes = IsArc_Ihex(temp, size); + if (isArcRes == k_IsArc_Res_NO) + return S_FALSE; + if (isArcRes == k_IsArc_Res_NEED_MORE && size != kStartSize) + return S_FALSE; + } + _isArc = true; + + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + CInBuffer s; + if (!s.Create(1 << 15)) + return E_OUTOFMEMORY; + s.SetStream(stream); + s.Init(); + + { + Byte b; + if (!s.ReadByte(b)) + { + _needMoreInput = true; + return S_FALSE; + } + if (b != ':') + { + _dataError = true; + return S_FALSE; + } + } + + UInt32 globalOffset = 0; + + for (;;) + { + if (s.ReadBytes(temp, 2) != 2) + { + _needMoreInput = true; + return S_FALSE; + } + int num = Parse(temp); + if (num < 0) + { + _dataError = true; + return S_FALSE; + } + + { + size_t numPairs = (num + 4); + size_t numBytes = numPairs * 2; + if (s.ReadBytes(temp, numBytes) != numBytes) + { + _needMoreInput = true; + return S_FALSE; + } + + int sum = num; + for (size_t i = 0; i < numPairs; i++) + { + int a = Parse(temp + i * 2); + if (a < 0) + { + _dataError = true; + return S_FALSE; + } + temp[i] = (Byte)a; + sum += a; + } + if ((sum & 0xFF) != 0) + { + _dataError = true; + return S_FALSE; + } + } + + unsigned type = temp[2]; + if (type > kType_MAX) + { + _dataError = true; + return S_FALSE; + } + + UInt32 a = GetBe16(temp); + + if (type == kType_Data) + { + if (num == 0) + { + // we don't want to open :0000000000 files + // maybe it can mean EOF in old-style files? + _dataError = true; + return S_FALSE; + } + // if (num != 0) + { + UInt32 offs = globalOffset + a; + CBlock *block = NULL; + if (!_blocks.IsEmpty()) + { + block = &_blocks.Back(); + if (block->Offset + block->Data.GetPos() != offs) + block = NULL; + } + if (!block) + { + block = &_blocks.AddNew(); + block->Offset = offs; + } + memcpy(block->Data.GetCurPtrAndGrow(num), temp + 3, num); + } + } + else if (type == kType_Eof) + { + _phySize = s.GetProcessedSize(); + { + Byte b; + if (s.ReadByte(b)) + { + if (b == 10) + _phySize++; + else if (b == 13) + { + _phySize++; + if (s.ReadByte(b)) + { + if (b == 10) + _phySize++; + } + } + } + } + return S_OK; + } + else + { + if (a != 0) + { + _dataError = true; + return S_FALSE; + } + if (type == kType_Seg || type == kType_High) + { + if (num != 2) + { + _dataError = true; + return S_FALSE; + } + UInt32 d = GetBe16(temp + 3); + globalOffset = d << (type == kType_Seg ? 4 : 16); + } + else + { + if (num != 4) + { + _dataError = true; + return S_FALSE; + } + } + } + + for (;;) + { + Byte b; + if (!s.ReadByte(b)) + { + _needMoreInput = true; + return S_FALSE; + } + if (IS_LINE_DELIMITER(b)) + continue; + if (b == ':') + break; + _dataError = true; + return S_FALSE; + } + } + } + catch(const CInBufferException &e) { return e.ErrorCode; } + } + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _phySize = 0; + + _isArc = false; + _needMoreInput = false; + _dataError = false; + + _blocks.Clear(); + return S_OK; +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _blocks.Size(); + if (numItems == 0) + return S_OK; + + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _blocks[allFilesMode ? i : indices[i]].Data.GetPos(); + extractCallback->SetTotal(totalSize); + + UInt64 currentTotalSize = 0; + UInt64 currentItemSize; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + { + currentItemSize = 0; + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + + UInt32 index = allFilesMode ? i : indices[i]; + const CByteDynamicBuffer &data = _blocks[index].Data; + currentItemSize = data.GetPos(); + + CMyComPtr<ISequentialOutStream> realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + if (!testMode && !realOutStream) + continue; + + extractCallback->PrepareOperation(askMode); + + if (realOutStream) + { + RINOK(WriteStream(realOutStream, (const Byte *)data, data.GetPos())); + } + + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + } + + lps->InSize = lps->OutSize = currentTotalSize; + return lps->SetCur(); + + COM_TRY_END +} + +IMP_CreateArcIn + +static CArcInfo g_ArcInfo = + { "IHex", "ihex", 0, 0xCD, + 0, { 0 }, + // 2, { ':', '1' }, + 0, + NArcInfoFlags::kStartOpen, + CreateArc, NULL, IsArc_Ihex }; + +REGISTER_ARC(Z) + +}} diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp index f040b033..fc984048 100755..100644 --- a/CPP/7zip/Archive/Iso/IsoHandler.cpp +++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp @@ -2,12 +2,12 @@ #include "StdAfx.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/StringConvert.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" #include "../../Common/LimitedStreams.h" #include "../../Common/ProgressUtils.h" @@ -24,22 +24,21 @@ using namespace NTime; namespace NArchive { namespace NIso { -static const STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME} + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime }; -static const STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidComment, VT_BSTR}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidMTime, VT_FILETIME} - // { NULL, kpidPhySize, VT_UI8}, - // { NULL, kpidHeadersSize, VT_UI8} + kpidComment, + kpidCTime, + kpidMTime, + // kpidHeadersSize }; IMP_IInArchive_Props @@ -51,13 +50,10 @@ STDMETHODIMP CHandler::Open(IInStream *stream, { COM_TRY_BEGIN Close(); - // try { - if (_archive.Open(stream) != S_OK) - return S_FALSE; + RINOK(_archive.Open(stream)); _stream = stream; } - // catch(...) { return S_FALSE; } return S_OK; COM_TRY_END } @@ -75,9 +71,9 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -static void AddString(AString &s, const char *name, const Byte *p, int size) +static void AddString(AString &s, const char *name, const Byte *p, unsigned size) { - int i; + unsigned i; for (i = 0; i < size && p[i]; i++); for (; i > 0 && p[i - 1] == ' '; i--); if (i != 0) @@ -94,12 +90,21 @@ static void AddString(AString &s, const char *name, const Byte *p, int size) #define ADD_STRING(n, v) AddString(s, n, vol. ## v, sizeof(vol. ## v)) +static void AddErrorMessage(AString &s, const char *message) +{ + if (!s.IsEmpty()) + s += ". "; + s += message; +} + STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; + if (_stream) + { const CVolumeDescriptor &vol = _archive.VolDescs[_archive.MainVolDescIndex]; - switch(propID) + switch (propID) { case kpidComment: { @@ -118,9 +123,35 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } case kpidCTime: { FILETIME utc; if (vol.CTime.GetFileTime(utc)) prop = utc; break; } case kpidMTime: { FILETIME utc; if (vol.MTime.GetFileTime(utc)) prop = utc; break; } - // case kpidPhySize: break; - // case kpidHeadersSize: break; - case kpidError: if (_archive.IncorrectBigEndian) prop = "Incorrect big-endian headers"; break; + } + } + + switch (propID) + { + case kpidPhySize: prop = _archive.PhySize; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; + if (_archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_archive.HeadersError) v |= kpv_ErrorFlags_HeadersError; + prop = v; + break; + } + + case kpidError: + { + AString s; + if (_archive.IncorrectBigEndian) + AddErrorMessage(s, "Incorrect big-endian headers"); + if (_archive.SelfLinkedDirs) + AddErrorMessage(s, "Self-linked directory"); + if (_archive.TooDeepDirs) + AddErrorMessage(s, "Too deep directory levels"); + if (!s.IsEmpty()) + prop = s; + break; + } } prop.Detach(value); return S_OK; @@ -130,22 +161,22 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; if (index >= (UInt32)_archive.Refs.Size()) { index -= _archive.Refs.Size(); const CBootInitialEntry &be = _archive.BootEntries[index]; - switch(propID) + switch (propID) { case kpidPath: { - // wchar_t name[32]; - // ConvertUInt64ToString(index + 1, name); - UString s = L"[BOOT]" WSTRING_PATH_SEPARATOR; + // char name[16]; + // ConvertUInt32ToString(index + 1, name); + AString s = "[BOOT]" STRING_PATH_SEPARATOR; // s += name; - // s += L"-"; + // s += '-'; s += be.GetName(); - prop = (const wchar_t *)s; + prop = s; break; } case kpidIsDir: prop = false; break; @@ -159,7 +190,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { const CRef &ref = _archive.Refs[index]; const CDir &item = ref.Dir->_subItems[ref.Index]; - switch(propID) + switch (propID) { case kpidPath: // if (item.FileId.GetCapacity() >= 0) @@ -171,9 +202,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val s = MultiByteToUnicodeString(item.GetPath(_archive.IsSusp, _archive.SuspSkipSize), CP_OEMCP); int pos = s.ReverseFind(L';'); - if (pos >= 0 && pos == s.Length() - 2) + if (pos >= 0 && pos == (int)s.Len() - 2) if (s.Back() == L'1') - s = s.Left(pos); + s.DeleteFrom(pos); if (!s.IsEmpty()) if (s.Back() == L'.') s.DeleteBack(); @@ -184,7 +215,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidSize: case kpidPackSize: if (!item.IsDir()) - prop = (UInt64)item.DataLength; + prop = (UInt64)ref.TotalSize; break; case kpidMTime: { @@ -204,7 +235,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _archive.Refs.Size(); if (numItems == 0) @@ -219,7 +250,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, const CRef &ref = _archive.Refs[index]; const CDir &item = ref.Dir->_subItems[ref.Index]; if (!item.IsDir()) - totalSize += item.DataLength; + totalSize += ref.TotalSize; } else totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size()); @@ -240,9 +271,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ISequentialInStream> inStream(streamSpec); streamSpec->SetStream(_stream); - CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; - CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) { lps->InSize = lps->OutSize = currentTotalSize; @@ -267,28 +295,54 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); continue; } - currentItemSize = item.DataLength; + currentItemSize = ref.TotalSize; blockIndex = item.ExtentLocation; } else { - int bootIndex = index - _archive.Refs.Size(); + unsigned bootIndex = index - _archive.Refs.Size(); const CBootInitialEntry &be = _archive.BootEntries[bootIndex]; currentItemSize = _archive.GetBootItemSize(bootIndex); blockIndex = be.LoadRBA; } + if (!testMode && !realOutStream) continue; + RINOK(extractCallback->PrepareOperation(askMode)); - outStreamSpec->SetStream(realOutStream); + + bool isOK = true; + if (index < (UInt32)_archive.Refs.Size()) + { + const CRef &ref = _archive.Refs[index]; + UInt64 offset = 0; + for (UInt32 e = 0; e < ref.NumExtents; e++) + { + if (e != 0) + lps->InSize = lps->OutSize = currentTotalSize + offset; + const CDir &item2 = ref.Dir->_subItems[ref.Index + e]; + RINOK(_stream->Seek(item2.ExtentLocation * _archive.BlockSize, STREAM_SEEK_SET, NULL)); + streamSpec->Init(item2.Size); + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize != item2.Size) + { + isOK = false; + break; + } + offset += item2.Size; + } + } + else + { + RINOK(_stream->Seek(blockIndex * _archive.BlockSize, STREAM_SEEK_SET, NULL)); + streamSpec->Init(currentItemSize); + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize != currentItemSize) + isOK = false; + } realOutStream.Release(); - outStreamSpec->Init(currentItemSize); - RINOK(_stream->Seek(blockIndex * _archive.BlockSize, STREAM_SEEK_SET, NULL)); - streamSpec->Init(currentItemSize); - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); - outStreamSpec->ReleaseStream(); - RINOK(extractCallback->SetOperationResult(outStreamSpec->IsFinishedOK() ? + RINOK(extractCallback->SetOperationResult(isOK ? NExtract::NOperationResult::kOK: NExtract::NOperationResult::kDataError)); } @@ -308,12 +362,42 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) const CDir &item = ref.Dir->_subItems[ref.Index]; if (item.IsDir()) return S_FALSE; - currentItemSize = item.DataLength; + + if (ref.NumExtents > 1) + { + CExtentsStream *extentStreamSpec = new CExtentsStream(); + CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec; + + extentStreamSpec->Stream = _stream; + + UInt64 virtOffset = 0; + for (UInt32 i = 0; i < ref.NumExtents; i++) + { + const CDir &item = ref.Dir->_subItems[ref.Index + i]; + if (item.Size == 0) + continue; + CSeekExtent se; + se.Phy = (UInt64)item.ExtentLocation * _archive.BlockSize; + se.Virt = virtOffset; + extentStreamSpec->Extents.Add(se); + virtOffset += item.Size; + } + if (virtOffset != ref.TotalSize) + return S_FALSE; + CSeekExtent se; + se.Phy = 0; + se.Virt = virtOffset; + extentStreamSpec->Extents.Add(se); + extentStreamSpec->Init(); + *stream = extentStream.Detach(); + return S_OK; + } + currentItemSize = item.Size; blockIndex = item.ExtentLocation; } else { - int bootIndex = index - _archive.Refs.Size(); + unsigned bootIndex = index - _archive.Refs.Size(); const CBootInitialEntry &be = _archive.BootEntries[bootIndex]; currentItemSize = _archive.GetBootItemSize(bootIndex); blockIndex = be.LoadRBA; diff --git a/CPP/7zip/Archive/Iso/IsoHandler.h b/CPP/7zip/Archive/Iso/IsoHandler.h index 1dcade8f..1923784d 100755..100644 --- a/CPP/7zip/Archive/Iso/IsoHandler.h +++ b/CPP/7zip/Archive/Iso/IsoHandler.h @@ -3,7 +3,8 @@ #ifndef __ISO_HANDLER_H #define __ISO_HANDLER_H -#include "Common/MyCom.h" +#include "../../../Common/MyCom.h" + #include "../IArchive.h" #include "IsoIn.h" diff --git a/CPP/7zip/Archive/Iso/IsoHeader.cpp b/CPP/7zip/Archive/Iso/IsoHeader.cpp index b3e418bb..1cd2516c 100755..100644 --- a/CPP/7zip/Archive/Iso/IsoHeader.cpp +++ b/CPP/7zip/Archive/Iso/IsoHeader.cpp @@ -9,13 +9,13 @@ namespace NIso { const char *kElToritoSpec = "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0"; -const wchar_t *kMediaTypes[5] = +const char *kMediaTypes[5] = { - L"NoEmulation", - L"1.2M", - L"1.44M", - L"2.88M", - L"HardDisk" + "NoEmulation" + , "1.2M" + , "1.44M" + , "2.88M" + , "HardDisk" }; }} diff --git a/CPP/7zip/Archive/Iso/IsoHeader.h b/CPP/7zip/Archive/Iso/IsoHeader.h index 9702d70a..ce21b0ff 100755..100644 --- a/CPP/7zip/Archive/Iso/IsoHeader.h +++ b/CPP/7zip/Archive/Iso/IsoHeader.h @@ -3,7 +3,7 @@ #ifndef __ARCHIVE_ISO_HEADER_H #define __ARCHIVE_ISO_HEADER_H -#include "Common/Types.h" +#include "../../../Common/MyTypes.h" namespace NArchive { namespace NIso { @@ -22,6 +22,7 @@ const Byte kVersion = 1; namespace NFileFlags { const Byte kDirectory = 1 << 1; + const Byte kNonFinalExtent = 1 << 7; } extern const char *kElToritoSpec; @@ -42,7 +43,7 @@ namespace NBootPlatformId const Byte kMac = 2; } -const BYTE kBootMediaTypeMask = 0xF; +const Byte kBootMediaTypeMask = 0xF; namespace NBootMediaType { @@ -53,8 +54,8 @@ namespace NBootMediaType const Byte kHardDisk = 4; } -const int kNumBootMediaTypes = 5; -extern const wchar_t *kMediaTypes[]; +const unsigned kNumBootMediaTypes = 5; +extern const char *kMediaTypes[]; }} diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp index 7ed618d2..ba12acae 100755..100644 --- a/CPP/7zip/Archive/Iso/IsoIn.cpp +++ b/CPP/7zip/Archive/Iso/IsoIn.cpp @@ -2,24 +2,34 @@ #include "StdAfx.h" -#include "IsoIn.h" +#include "../../../Common/MyException.h" #include "../../Common/StreamUtils.h" +#include "IsoIn.h" + namespace NArchive { namespace NIso { +struct CUnexpectedEndException {}; +struct CHeaderErrorException {}; +struct CEndianErrorException {}; + Byte CInArchive::ReadByte() { if (m_BufferPos >= BlockSize) m_BufferPos = 0; if (m_BufferPos == 0) { - size_t processedSize = BlockSize; - if (ReadStream(_stream, m_Buffer, &processedSize) != S_OK) - throw 1; - if (processedSize != BlockSize) - throw 1; + size_t processed = BlockSize; + HRESULT res = ReadStream(_stream, m_Buffer, &processed); + if (res != S_OK) + throw CSystemException(res); + if (processed != BlockSize) + throw CUnexpectedEndException(); + UInt64 end = _position + processed; + if (PhySize < end) + PhySize = end; } Byte b = m_Buffer[m_BufferPos++]; _position++; @@ -44,16 +54,16 @@ void CInArchive::SkipZeros(size_t size) { Byte b = ReadByte(); if (b != 0) - throw 1; + throw CHeaderErrorException(); } } UInt16 CInArchive::ReadUInt16Spec() { - UInt16 value = 0; + UInt16 val = 0; for (int i = 0; i < 2; i++) - value |= ((UInt16)(ReadByte()) << (8 * i)); - return value; + val |= ((UInt16)(ReadByte()) << (8 * i)); + return val; } @@ -61,47 +71,47 @@ UInt16 CInArchive::ReadUInt16() { Byte b[4]; ReadBytes(b, 4); - UInt32 value = 0; + UInt32 val = 0; for (int i = 0; i < 2; i++) { if (b[i] != b[3 - i]) IncorrectBigEndian = true; - value |= ((UInt16)(b[i]) << (8 * i)); + val |= ((UInt16)(b[i]) << (8 * i)); } - return (UInt16)value; + return (UInt16)val; } UInt32 CInArchive::ReadUInt32Le() { - UInt32 value = 0; + UInt32 val = 0; for (int i = 0; i < 4; i++) - value |= ((UInt32)(ReadByte()) << (8 * i)); - return value; + val |= ((UInt32)(ReadByte()) << (8 * i)); + return val; } UInt32 CInArchive::ReadUInt32Be() { - UInt32 value = 0; + UInt32 val = 0; for (int i = 0; i < 4; i++) { - value <<= 8; - value |= ReadByte(); + val <<= 8; + val |= ReadByte(); } - return value; + return val; } UInt32 CInArchive::ReadUInt32() { Byte b[8]; ReadBytes(b, 8); - UInt32 value = 0; + UInt32 val = 0; for (int i = 0; i < 4; i++) { if (b[i] != b[7 - i]) - throw 1; - value |= ((UInt32)(b[i]) << (8 * i)); + throw CEndianErrorException(); + val |= ((UInt32)(b[i]) << (8 * i)); } - return value; + return val; } UInt32 CInArchive::ReadDigits(int numDigits) @@ -115,7 +125,7 @@ UInt32 CInArchive::ReadDigits(int numDigits) if (b == 0) // it's bug in some CD's b = '0'; else - throw 1; + throw CHeaderErrorException(); } UInt32 d = (UInt32)(b - '0'); res *= 10; @@ -158,16 +168,16 @@ void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len) { r.ExtendedAttributeRecordLen = ReadByte(); if (r.ExtendedAttributeRecordLen != 0) - throw 1; + throw CHeaderErrorException(); r.ExtentLocation = ReadUInt32(); - r.DataLength = ReadUInt32(); + r.Size = ReadUInt32(); ReadRecordingDateTime(r.DateTime); r.FileFlags = ReadByte(); r.FileUnitSize = ReadByte(); r.InterleaveGapSize = ReadByte(); r.VolSequenceNumber = ReadUInt16(); Byte idLen = ReadByte(); - r.FileId.SetCapacity(idLen); + r.FileId.Alloc(idLen); ReadBytes((Byte *)r.FileId, idLen); int padSize = 1 - (idLen & 1); @@ -176,9 +186,9 @@ void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len) int curPos = 33 + idLen + padSize; if (curPos > len) - throw 1; + throw CHeaderErrorException(); int rem = len - curPos; - r.SystemUse.SetCapacity(rem); + r.SystemUse.Alloc(rem); ReadBytes((Byte *)r.SystemUse, rem); } @@ -242,15 +252,34 @@ static inline bool CheckSignature(const Byte *sig, const Byte *data) void CInArchive::SeekToBlock(UInt32 blockIndex) { - if (_stream->Seek((UInt64)blockIndex * VolDescs[MainVolDescIndex].LogicalBlockSize, STREAM_SEEK_SET, &_position) != S_OK) - throw 1; + HRESULT res = _stream->Seek((UInt64)blockIndex * VolDescs[MainVolDescIndex].LogicalBlockSize, STREAM_SEEK_SET, &_position); + if (res != S_OK) + throw CSystemException(res); m_BufferPos = 0; } +static const int kNumLevelsMax = 256; + void CInArchive::ReadDir(CDir &d, int level) { if (!d.IsDir()) return; + if (level > kNumLevelsMax) + { + TooDeepDirs = true; + return; + } + + { + FOR_VECTOR (i, UniqStartLocations) + if (UniqStartLocations[i] == d.ExtentLocation) + { + SelfLinkedDirs = true; + return; + } + UniqStartLocations.Add(d.ExtentLocation); + } + SeekToBlock(d.ExtentLocation); UInt64 startPos = _position; @@ -258,7 +287,7 @@ void CInArchive::ReadDir(CDir &d, int level) for (;;) { UInt64 offset = _position - startPos; - if (offset >= d.DataLength) + if (offset >= d.Size) break; Byte len = ReadByte(); if (len == 0) @@ -273,21 +302,44 @@ void CInArchive::ReadDir(CDir &d, int level) firstItem = false; } - for (int i = 0; i < d._subItems.Size(); i++) + FOR_VECTOR (i, d._subItems) ReadDir(d._subItems[i], level + 1); + + UniqStartLocations.DeleteBack(); } void CInArchive::CreateRefs(CDir &d) { if (!d.IsDir()) return; - for (int i = 0; i < d._subItems.Size(); i++) + for (unsigned i = 0; i < d._subItems.Size();) { CRef ref; CDir &subItem = d._subItems[i]; subItem.Parent = &d; ref.Dir = &d; - ref.Index = i; + ref.Index = i++; + ref.NumExtents = 1; + ref.TotalSize = subItem.Size; + if (subItem.IsNonFinalExtent()) + { + for (;;) + { + if (i == d._subItems.Size()) + { + HeadersError = true; + break; + } + const CDir &next = d._subItems[i]; + if (!subItem.AreMultiPartEqualWith(next)) + break; + i++; + ref.NumExtents++; + ref.TotalSize += next.Size; + if (!next.IsNonFinalExtent()) + break; + } + } Refs.Add(ref); CreateRefs(subItem); } @@ -310,13 +362,13 @@ void CInArchive::ReadBootInfo() CBootValidationEntry e; e.PlatformId = ReadByte(); if (ReadUInt16Spec() != 0) - throw 1; + throw CHeaderErrorException(); ReadBytes(e.Id, sizeof(e.Id)); /* UInt16 checkSum = */ ReadUInt16Spec(); if (ReadByte() != 0x55) - throw 1; + throw CHeaderErrorException(); if (ReadByte() != 0xAA) - throw 1; + throw CHeaderErrorException(); } b = ReadByte(); if (b == NBootEntryId::kInitialEntryBootable || b == NBootEntryId::kInitialEntryNotBootable) @@ -327,11 +379,11 @@ void CInArchive::ReadBootInfo() e.LoadSegment = ReadUInt16Spec(); e.SystemType = ReadByte(); if (ReadByte() != 0) - throw 1; + throw CHeaderErrorException(); e.SectorCount = ReadUInt16Spec(); e.LoadRBA = ReadUInt32Le(); if (ReadByte() != 0) - throw 1; + throw CHeaderErrorException(); BootEntries.Add(e); } else @@ -340,16 +392,22 @@ void CInArchive::ReadBootInfo() HRESULT CInArchive::Open2() { - Clear(); - RINOK(_stream->Seek(kStartPos, STREAM_SEEK_CUR, &_position)); + _position = 0; + RINOK(_stream->Seek(0, STREAM_SEEK_END, &_fileSize)); + if (_fileSize < kStartPos) + return S_FALSE; + RINOK(_stream->Seek(kStartPos, STREAM_SEEK_SET, &_position)); + PhySize = _position; m_BufferPos = 0; BlockSize = kBlockSize; + for (;;) { Byte sig[7]; ReadBytes(sig, 7); Byte ver = sig[6]; + if (!CheckSignature(kSig_CD001, sig + 1)) { return S_FALSE; @@ -372,9 +430,10 @@ HRESULT CInArchive::Open2() continue; */ } + // version = 2 for ISO 9660:1999? if (ver > 2) - throw S_FALSE; + return S_FALSE; if (sig[0] == NVolDescType::kTerminator) { @@ -382,7 +441,8 @@ HRESULT CInArchive::Open2() // Skip(0x800 - 7); // continue; } - switch(sig[0]) + + switch (sig[0]) { case NVolDescType::kBootRecord: { @@ -408,6 +468,7 @@ HRESULT CInArchive::Open2() break; } } + if (VolDescs.IsEmpty()) return S_FALSE; for (MainVolDescIndex = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--) @@ -417,30 +478,58 @@ HRESULT CInArchive::Open2() const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex]; if (vd.LogicalBlockSize != kBlockSize) return S_FALSE; + + IsArc = true; + (CDirRecord &)_rootDir = vd.RootDirRecord; ReadDir(_rootDir, 0); CreateRefs(_rootDir); ReadBootInfo(); + + { + FOR_VECTOR(i, Refs) + { + const CRef &ref = Refs[i]; + for (UInt32 j = 0; j < ref.NumExtents; j++) + { + const CDir &item = ref.Dir->_subItems[ref.Index + j]; + if (!item.IsDir()) + UpdatePhySize(item.ExtentLocation, item.Size); + } + } + } + { + FOR_VECTOR(i, BootEntries) + { + const CBootInitialEntry &be = BootEntries[i]; + UpdatePhySize(be.LoadRBA, GetBootItemSize(i)); + } + } return S_OK; } HRESULT CInArchive::Open(IInStream *inStream) { + Clear(); _stream = inStream; - UInt64 pos; - RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &pos)); - RINOK(_stream->Seek(0, STREAM_SEEK_END, &_archiveSize)); - RINOK(_stream->Seek(pos, STREAM_SEEK_SET, &_position)); - HRESULT res = S_FALSE; - try { res = Open2(); } - catch(...) { Clear(); res = S_FALSE; } - _stream.Release(); - return res; + try { return Open2(); } + catch(const CSystemException &e) { return e.ErrorCode; } + catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; } + catch(CHeaderErrorException &) { HeadersError = true; return S_FALSE; } + catch(CEndianErrorException &) { IncorrectBigEndian = true; return S_FALSE; } } void CInArchive::Clear() { + IsArc = false; + UnexpectedEnd = false; + HeadersError = false; IncorrectBigEndian = false; + TooDeepDirs = false; + SelfLinkedDirs = false; + + UniqStartLocations.Clear(); + Refs.Clear(); _rootDir.Clear(); VolDescs.Clear(); diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h index f9c6f640..614b3744 100755..100644 --- a/CPP/7zip/Archive/Iso/IsoIn.h +++ b/CPP/7zip/Archive/Iso/IsoIn.h @@ -3,8 +3,8 @@ #ifndef __ARCHIVE_ISO_IN_H #define __ARCHIVE_ISO_IN_H -#include "Common/IntToString.h" -#include "Common/MyCom.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/MyCom.h" #include "../../IStream.h" @@ -25,37 +25,37 @@ struct CDir: public CDirRecord _subItems.Clear(); } - int GetLength(bool checkSusp, int skipSize) const + unsigned GetLen(bool checkSusp, unsigned skipSize) const { - int len = GetLengthCur(checkSusp, skipSize); + unsigned len = GetLenCur(checkSusp, skipSize); if (Parent != 0) if (Parent->Parent != 0) - len += 1 + Parent->GetLength(checkSusp, skipSize); + len += 1 + Parent->GetLen(checkSusp, skipSize); return len; } - int GetLengthU() const + unsigned GetLenU() const { - int len = (int)(FileId.GetCapacity() / 2); + unsigned len = (unsigned)(FileId.Size() / 2); if (Parent != 0) if (Parent->Parent != 0) - len += 1 + Parent->GetLengthU(); + len += 1 + Parent->GetLenU(); return len; } - AString GetPath(bool checkSusp, int skipSize) const + AString GetPath(bool checkSusp, unsigned skipSize) const { AString s; - int len = GetLength(checkSusp, skipSize); - char *p = s.GetBuffer(len + 1); + unsigned len = GetLen(checkSusp, skipSize); + char *p = s.GetBuffer(len); p += len; *p = 0; const CDir *cur = this; for (;;) { - int curLen = cur->GetLengthCur(checkSusp, skipSize); + unsigned curLen = cur->GetLenCur(checkSusp, skipSize); p -= curLen; - memmove(p, (const char *)(const Byte *)cur->GetNameCur(checkSusp, skipSize), curLen); + memcpy(p, (const char *)(const Byte *)cur->GetNameCur(checkSusp, skipSize), curLen); cur = cur->Parent; if (cur == 0) break; @@ -71,16 +71,16 @@ struct CDir: public CDirRecord UString GetPathU() const { UString s; - int len = GetLengthU(); - wchar_t *p = s.GetBuffer(len + 1); + unsigned len = GetLenU(); + wchar_t *p = s.GetBuffer(len); p += len; *p = 0; const CDir *cur = this; for (;;) { - int curLen = (int)(cur->FileId.GetCapacity() / 2); + unsigned curLen = (unsigned)(cur->FileId.Size() / 2); p -= curLen; - for (int i = 0; i < curLen; i++) + for (unsigned i = 0; i < curLen; i++) { Byte b0 = ((const Byte *)cur->FileId)[i * 2]; Byte b1 = ((const Byte *)cur->FileId)[i * 2 + 1]; @@ -163,23 +163,19 @@ struct CBootInitialEntry return SectorCount * 512; } - UString GetName() const + AString GetName() const { - UString s; - if (Bootable) - s += L"Bootable"; + AString s = (Bootable ? "Bootable" : "NotBootable"); + s += '_'; + if (BootMediaType < kNumBootMediaTypes) + s += kMediaTypes[BootMediaType]; else - s += L"NotBootable"; - s += L"_"; - if (BootMediaType >= kNumBootMediaTypes) { - wchar_t name[16]; + char name[16]; ConvertUInt32ToString(BootMediaType, name); s += name; } - else - s += kMediaTypes[BootMediaType]; - s += L".img"; + s += ".img"; return s; } }; @@ -228,18 +224,19 @@ struct CVolumeDescriptor struct CRef { - CDir *Dir; + const CDir *Dir; UInt32 Index; + UInt32 NumExtents; + UInt64 TotalSize; }; const UInt32 kBlockSize = 1 << 11; class CInArchive { - CMyComPtr<IInStream> _stream; + IInStream *_stream; UInt64 _position; - Byte m_Buffer[kBlockSize]; UInt32 m_BufferPos; CDir _rootDir; @@ -275,15 +272,32 @@ public: HRESULT Open(IInStream *inStream); void Clear(); - UInt64 _archiveSize; + UInt64 _fileSize; + UInt64 PhySize; CRecordVector<CRef> Refs; CObjectVector<CVolumeDescriptor> VolDescs; int MainVolDescIndex; UInt32 BlockSize; CObjectVector<CBootInitialEntry> BootEntries; + + bool IsArc; + bool UnexpectedEnd; + bool HeadersError; bool IncorrectBigEndian; + bool TooDeepDirs; + bool SelfLinkedDirs; + CRecordVector<UInt32> UniqStartLocations; + + Byte m_Buffer[kBlockSize]; + void UpdatePhySize(UInt32 blockIndex, UInt64 size) + { + UInt64 alignedSize = (size + BlockSize - 1) & ~((UInt64)BlockSize - 1); + UInt64 end = blockIndex * BlockSize + alignedSize; + if (PhySize < end) + PhySize = end; + } bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); } @@ -297,17 +311,17 @@ public: size = (1440 << 10); else if (be.BootMediaType == NBootMediaType::k2d88Floppy) size = (2880 << 10); - UInt64 startPos = be.LoadRBA * BlockSize; - if (startPos < _archiveSize) + UInt64 startPos = (UInt64)be.LoadRBA * BlockSize; + if (startPos < _fileSize) { - if (_archiveSize - startPos < size) - size = _archiveSize - startPos; + if (_fileSize - startPos < size) + size = _fileSize - startPos; } return size; } bool IsSusp; - int SuspSkipSize; + unsigned SuspSkipSize; }; }} diff --git a/CPP/7zip/Archive/Iso/IsoItem.h b/CPP/7zip/Archive/Iso/IsoItem.h index f39c2f5d..b6ae21b7 100755..100644 --- a/CPP/7zip/Archive/Iso/IsoItem.h +++ b/CPP/7zip/Archive/Iso/IsoItem.h @@ -3,11 +3,10 @@ #ifndef __ARCHIVE_ISO_ITEM_H #define __ARCHIVE_ISO_ITEM_H -#include "Common/Types.h" -#include "Common/MyString.h" -#include "Common/Buffer.h" +#include "../../../Common/MyString.h" +#include "../../../Common/MyBuffer.h" -#include "Windows/Time.h" +#include "../../../Windows/TimeUtils.h" #include "IsoHeader.h" @@ -41,62 +40,77 @@ struct CRecordingDateTime struct CDirRecord { - Byte ExtendedAttributeRecordLen; UInt32 ExtentLocation; - UInt32 DataLength; + UInt32 Size; CRecordingDateTime DateTime; Byte FileFlags; Byte FileUnitSize; Byte InterleaveGapSize; + Byte ExtendedAttributeRecordLen; UInt16 VolSequenceNumber; CByteBuffer FileId; CByteBuffer SystemUse; - bool IsDir() const { return (FileFlags & NFileFlags::kDirectory) != 0; } + bool AreMultiPartEqualWith(const CDirRecord &a) const + { + return FileId == a.FileId + && (FileFlags & (~NFileFlags::kNonFinalExtent)) == + (a.FileFlags & (~NFileFlags::kNonFinalExtent)); + } + + bool IsDir() const { return (FileFlags & NFileFlags::kDirectory) != 0; } + bool IsNonFinalExtent() const { return (FileFlags & NFileFlags::kNonFinalExtent) != 0; } + bool IsSystemItem() const { - if (FileId.GetCapacity() != 1) + if (FileId.Size() != 1) return false; Byte b = *(const Byte *)FileId; return (b == 0 || b == 1); } - const Byte* FindSuspName(int skipSize, int &lenRes) const + const Byte* FindSuspName(unsigned skipSize, unsigned &lenRes) const { lenRes = 0; + if (SystemUse.Size() < skipSize) + return 0; const Byte *p = (const Byte *)SystemUse + skipSize; - int length = (int)(SystemUse.GetCapacity() - skipSize); - while (length >= 5) + unsigned rem = (unsigned)(SystemUse.Size() - skipSize); + while (rem >= 5) { - int len = p[2]; + unsigned len = p[2]; + if (len > rem) + return 0; if (p[0] == 'N' && p[1] == 'M' && p[3] == 1) { + if (len < 5) + return 0; // Check it lenRes = len - 5; return p + 5; } p += len; - length -= len; + rem -= len; } return 0; } - int GetLengthCur(bool checkSusp, int skipSize) const + unsigned GetLenCur(bool checkSusp, int skipSize) const { if (checkSusp) { - int len; + unsigned len; const Byte *res = FindSuspName(skipSize, len); if (res != 0) return len; } - return (int)FileId.GetCapacity(); + return (unsigned)FileId.Size(); } const Byte* GetNameCur(bool checkSusp, int skipSize) const { if (checkSusp) { - int len; + unsigned len; const Byte *res = FindSuspName(skipSize, len); if (res != 0) return res; @@ -105,7 +119,7 @@ struct CDirRecord } - bool CheckSusp(const Byte *p, int &startPos) const + bool CheckSusp(const Byte *p, unsigned &startPos) const { if (p[0] == 'S' && p[1] == 'P' && @@ -120,17 +134,17 @@ struct CDirRecord return false; } - bool CheckSusp(int &startPos) const + bool CheckSusp(unsigned &startPos) const { const Byte *p = (const Byte *)SystemUse; - int length = (int)SystemUse.GetCapacity(); - const int kMinLen = 7; - if (length < kMinLen) + unsigned len = (int)SystemUse.Size(); + const unsigned kMinLen = 7; + if (len < kMinLen) return false; if (CheckSusp(p, startPos)) return true; - const int kOffset2 = 14; - if (length < kOffset2 + kMinLen) + const unsigned kOffset2 = 14; + if (len < kOffset2 + kMinLen) return false; return CheckSusp(p + kOffset2, startPos); } diff --git a/CPP/7zip/Archive/Iso/IsoRegister.cpp b/CPP/7zip/Archive/Iso/IsoRegister.cpp index 67a09c76..c6f4a521 100755..100644 --- a/CPP/7zip/Archive/Iso/IsoRegister.cpp +++ b/CPP/7zip/Archive/Iso/IsoRegister.cpp @@ -5,9 +5,19 @@ #include "../../Common/RegisterArc.h" #include "IsoHandler.h" -static IInArchive *CreateArc() { return new NArchive::NIso::CHandler; } + +namespace NArchive { +namespace NIso { + +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"Iso", L"iso img", 0, 0xE7, { 'C', 'D', '0', '0', '1', 0x1 }, 7, false, CreateArc, 0 }; + { "Iso", "iso img", 0, 0xE7, + 5, { 'C', 'D', '0', '0', '1' }, + NArchive::NIso::kStartPos + 1, + 0, + CreateArc }; REGISTER_ARC(Iso) + +}} diff --git a/CPP/7zip/Archive/Iso/StdAfx.h b/CPP/7zip/Archive/Iso/StdAfx.h index 2e4be10b..2854ff3e 100755..100644 --- a/CPP/7zip/Archive/Iso/StdAfx.h +++ b/CPP/7zip/Archive/Iso/StdAfx.h @@ -3,7 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" -#include "../../../Common/NewHandler.h" +#include "../../../Common/Common.h" #endif diff --git a/CPP/7zip/Archive/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp index 194de47e..74f713f6 100755..100644 --- a/CPP/7zip/Archive/LzhHandler.cpp +++ b/CPP/7zip/Archive/LzhHandler.cpp @@ -4,12 +4,12 @@ #include "../../../C/CpuArch.h" -#include "Common/Buffer.h" -#include "Common/ComTry.h" -#include "Common/StringConvert.h" +#include "../../Common/ComTry.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/StringConvert.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" #include "../ICoder.h" @@ -44,10 +44,11 @@ struct CExtension { Byte Type; CByteBuffer Data; + AString GetString() const { AString s; - for (size_t i = 0; i < Data.GetCapacity(); i++) + for (size_t i = 0; i < Data.Size(); i++) { char c = (char)Data[i]; if (c == 0) @@ -58,6 +59,21 @@ struct CExtension } }; +const UInt32 kBasicPartSize = 22; + +API_FUNC_static_IsArc IsArc_Lzh(const Byte *p, size_t size) +{ + if (size < 2 + kBasicPartSize) + return k_IsArc_Res_NEED_MORE; + if (p[2] != '-' || p[3] != 'l' || p[4] != 'h' || p[6] != '-') + return k_IsArc_Res_NO; + Byte n = p[5]; + if (n != 'd') + if (n < '0' || n > '7') + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} + struct CItem { AString Name; @@ -85,7 +101,7 @@ struct CItem { if (!IsLhMethod()) return false; - switch(Method[3]) + switch (Method[3]) { case '1': return true; @@ -97,7 +113,7 @@ struct CItem { if (!IsLhMethod()) return false; - switch(Method[3]) + switch (Method[3]) { case '4': case '5': @@ -112,7 +128,7 @@ struct CItem { if (!IsLhMethod()) return 0; - switch(Method[3]) + switch (Method[3]) { case '1': return 12; case '2': return 13; @@ -127,13 +143,14 @@ struct CItem int FindExt(Byte type) const { - for (int i = 0; i < Extensions.Size(); i++) + FOR_VECTOR (i, Extensions) if (Extensions[i].Type == type) return i; return -1; } bool GetUnixTime(UInt32 &value) const { + value = 0; int index = FindExt(kExtIdUnixTime); if (index < 0) { @@ -219,7 +236,6 @@ static HRESULT GetNextItem(ISequentialInStream *stream, bool &filled, CItem &ite return S_OK; Byte header[256]; - const UInt32 kBasicPartSize = 22; processedSize = kBasicPartSize; RINOK(ReadStream(stream, header, &processedSize)); if (processedSize != kBasicPartSize) @@ -281,7 +297,7 @@ static HRESULT GetNextItem(ISequentialInStream *stream, bool &filled, CItem &ite CExtension ext; RINOK(ReadStream_FALSE(stream, &ext.Type, 1)) nextSize -= 3; - ext.Data.SetCapacity(nextSize); + ext.Data.Alloc(nextSize); RINOK(ReadStream_FALSE(stream, (Byte *)ext.Data, nextSize)) item.Extensions.Add(ext); Byte hdr2[2]; @@ -324,28 +340,23 @@ static const char *kUnknownOS = "Unknown"; static const char *GetOS(Byte osId) { - for (int i = 0; i < sizeof(g_OsPairs) / sizeof(g_OsPairs[0]); i++) + 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 STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - // { NULL, kpidAttrib, VT_UI4}, - { NULL, kpidCRC, VT_UI4}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidHostOS, VT_BSTR} -}; - -static const STATPROPSTG kArcProps[] = -{ - { NULL, kpidPhySize, VT_UI8} + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + // kpidAttrib, + kpidCRC, + kpidMethod, + kpidHostOS }; class CCRC @@ -446,7 +457,8 @@ class CHandler: CObjectVector<CItemEx> _items; CMyComPtr<IInStream> _stream; UInt64 _phySize; - AString _errorMessage; + UInt32 _errorFlags; + bool _isArc; public: MY_UNKNOWN_IMP1(IInArchive) INTERFACE_IInArchive(;) @@ -454,7 +466,7 @@ public: }; IMP_IInArchive_Props -IMP_IInArchive_ArcProps +IMP_IInArchive_ArcProps_NO_Table CHandler::CHandler() {} @@ -467,21 +479,26 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidPhySize: prop = _phySize; break; - case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + + case kpidErrorFlags: + UInt32 v = _errorFlags; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + prop = v; + break; } prop.Detach(value); return S_OK; } -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; const CItemEx &item = _items[index]; - switch(propID) + switch (propID) { case kpidPath: { @@ -538,6 +555,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback) { COM_TRY_BEGIN + Close(); try { _items.Clear(); @@ -548,7 +566,6 @@ STDMETHODIMP CHandler::Open(IInStream *stream, RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); - _phySize = 0; for (;;) { CItemEx item; @@ -557,7 +574,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, RINOK(stream->Seek(0, STREAM_SEEK_CUR, &item.DataPosition)); if (result == S_FALSE) { - _errorMessage = "Incorrect header"; + _errorFlags = kpv_ErrorFlags_HeadersError; break; } @@ -568,12 +585,14 @@ STDMETHODIMP CHandler::Open(IInStream *stream, break; _items.Add(item); + _isArc = true; + UInt64 newPostion; RINOK(stream->Seek(item.PackSize, STREAM_SEEK_CUR, &newPostion)); if (newPostion > endPos) { _phySize = endPos; - _errorMessage = "Unexpected end of archive"; + _errorFlags = kpv_ErrorFlags_UnexpectedEnd; break; } _phySize = newPostion; @@ -607,7 +626,9 @@ STDMETHODIMP CHandler::Open(IInStream *stream, STDMETHODIMP CHandler::Close() { - _errorMessage.Empty(); + _isArc = false; + _phySize = 0; + _errorFlags = 0; _items.Clear(); _stream.Release(); return S_OK; @@ -619,7 +640,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_BEGIN bool testMode = (testModeSpec != 0); UInt64 totalUnPacked = 0, totalPacked = 0; - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (numItems == 0) @@ -730,7 +751,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } */ else - opRes = NExtract::NOperationResult::kUnSupportedMethod; + opRes = NExtract::NOperationResult::kUnsupportedMethod; if (opRes == NExtract::NOperationResult::kOK) { @@ -751,10 +772,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"Lzh", L"lzh lha", 0, 6, { '-', 'l' }, 2, false, CreateArc, 0 }; + { "Lzh", "lzh lha", 0, 6, + 3, { '-', 'l', 'h' }, + 2, + 0, + CreateArc, NULL, IsArc_Lzh }; REGISTER_ARC(Lzh) diff --git a/CPP/7zip/Archive/LzmaHandler.cpp b/CPP/7zip/Archive/LzmaHandler.cpp index 778c2fd8..d1e19677 100755..100644 --- a/CPP/7zip/Archive/LzmaHandler.cpp +++ b/CPP/7zip/Archive/LzmaHandler.cpp @@ -4,10 +4,10 @@ #include "../../../C/CpuArch.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" #include "../Common/CreateCoder.h" #include "../Common/ProgressUtils.h" @@ -26,17 +26,24 @@ namespace NLzma { static bool CheckDicSize(const Byte *p) { UInt32 dicSize = GetUi32(p); - for (int i = 1; i <= 30; i++) + if (dicSize == 1) + return true; + for (unsigned i = 0; i <= 30; i++) if (dicSize == ((UInt32)2 << i) || dicSize == ((UInt32)3 << i)) return true; return (dicSize == 0xFFFFFFFF); } -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMethod, VT_BSTR} + kpidSize, + kpidPackSize, + kpidMethod +}; + +static const Byte kArcProps[] = +{ + kpidNumStreams }; struct CHeader @@ -62,16 +69,17 @@ bool CHeader::Parse(const Byte *buf, bool isThereFilter) return LzmaProps[0] < 5 * 5 * 9 && FilterID < 2 && - (!HasSize() || Size < ((UInt64)1 << 56)) && - CheckDicSize(LzmaProps + 1); + (!HasSize() || Size < ((UInt64)1 << 56)) + && CheckDicSize(LzmaProps + 1); } class CDecoder { - NCompress::NLzma::CDecoder *_lzmaDecoderSpec; CMyComPtr<ICompressCoder> _lzmaDecoder; CMyComPtr<ISequentialOutStream> _bcjStream; public: + NCompress::NLzma::CDecoder *_lzmaDecoderSpec; + ~CDecoder(); HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS bool filtered, ISequentialInStream *inStream); @@ -86,7 +94,7 @@ public: { return _lzmaDecoderSpec->ReadFromInputStream(data, size, processedSize); } }; -static const UInt64 k_BCJ = 0x03030103; +static const UInt32 k_BCJ = 0x03030103; HRESULT CDecoder::Create( DECL_EXTERNAL_CODECS_LOC_VARS @@ -95,6 +103,7 @@ HRESULT CDecoder::Create( if (!_lzmaDecoder) { _lzmaDecoderSpec = new NCompress::NLzma::CDecoder; + _lzmaDecoderSpec->FinishStream = true; _lzmaDecoder = _lzmaDecoderSpec; } @@ -166,6 +175,10 @@ HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream, } RINOK(res); + if (header.HasSize()) + if (_lzmaDecoderSpec->GetOutputProcessedSize() != header.Size) + return S_FALSE; + return S_OK; } @@ -178,11 +191,24 @@ class CHandler: { CHeader _header; bool _lzma86; - UInt64 _startPosition; - UInt64 _packSize; - bool _packSizeDefined; CMyComPtr<IInStream> _stream; CMyComPtr<ISequentialInStream> _seqStream; + + bool _isArc; + bool _needSeekToStart; + bool _dataAfterEnd; + bool _needMoreInput; + + bool _packSize_Defined; + bool _unpackSize_Defined; + bool _numStreams_Defined; + + bool _unsupported; + bool _dataError; + + UInt64 _packSize; + UInt64 _unpackSize; + UInt64 _numStreams; DECL_EXTERNAL_CODECS_VARS DECL_ISetCompressCodecsInfo @@ -204,14 +230,26 @@ public: }; IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table +IMP_IInArchive_ArcProps STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; - switch(propID) + switch (propID) { - case kpidPhySize: if (_packSizeDefined) prop = _packSize; break; + case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; + case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break; + case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; + if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; + if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; + if (_dataError) v |= kpv_ErrorFlags_DataError; + prop = v; + } } prop.Detach(value); return S_OK; @@ -226,50 +264,37 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) static void DictSizeToString(UInt32 value, char *s) { for (int i = 0; i <= 31; i++) - if ((UInt32(1) << i) == value) + if (((UInt32)1 << i) == value) { ::ConvertUInt32ToString(i, s); return; } char c = 'b'; - if ((value & ((1 << 20) - 1)) == 0) - { - value >>= 20; - c = 'm'; - } - else if ((value & ((1 << 10) - 1)) == 0) - { - value >>= 10; - c = 'k'; - } + if ((value & ((1 << 20) - 1)) == 0) { value >>= 20; c = 'm'; } + else if ((value & ((1 << 10) - 1)) == 0) { value >>= 10; c = 'k'; } ::ConvertUInt32ToString(value, s); - int p = MyStringLen(s); - s[p++] = c; - s[p++] = '\0'; + s += MyStringLen(s); + *s++ = c; + *s = 0; } -static void MyStrCat(char *d, const char *s) -{ - MyStringCopy(d + MyStringLen(d), s); -} - -STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidSize: if (_stream && _header.HasSize()) prop = _header.Size; break; - case kpidPackSize: if (_packSizeDefined) prop = _packSize; break; + case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; case kpidMethod: if (_stream) { - char s[64]; - s[0] = '\0'; + char sz[64]; + char *s = sz; if (_header.FilterID != 0) - MyStrCat(s, "BCJ "); - MyStrCat(s, "LZMA:"); - DictSizeToString(_header.GetDicSize(), s + MyStringLen(s)); - prop = s; + s = MyStpCpy(s, "BCJ "); + s = MyStpCpy(s, "LZMA:"); + DictSizeToString(_header.GetDicSize(), s); + prop = sz; } break; } @@ -277,11 +302,52 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIA return S_OK; } +API_FUNC_static_IsArc IsArc_Lzma(const Byte *p, size_t size) +{ + const UInt32 kHeaderSize = 1 + 4 + 8; + if (size < kHeaderSize) + return k_IsArc_Res_NEED_MORE; + if (p[0] >= 5 * 5 * 9) + return k_IsArc_Res_NO; + UInt64 unpackSize = GetUi64(p + 1 + 4); + if (unpackSize != (UInt64)(Int64)-1) + { + if (size >= ((UInt64)1 << 56)) + return k_IsArc_Res_NO; + } + if (unpackSize != 0) + { + if (size < kHeaderSize + 2) + return k_IsArc_Res_NEED_MORE; + if (p[kHeaderSize] != 0) + return k_IsArc_Res_NO; + if (unpackSize != (UInt64)(Int64)-1) + { + if ((p[kHeaderSize + 1] & 0x80) != 0) + return k_IsArc_Res_NO; + } + } + if (!CheckDicSize(p + 1)) + // return k_IsArc_Res_YES_LOW_PROB; + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} + +API_FUNC_static_IsArc IsArc_Lzma86(const Byte *p, size_t size) +{ + if (size < 1) + return k_IsArc_Res_NEED_MORE; + Byte filterID = p[0]; + if (filterID != 0 && filterID != 1) + return k_IsArc_Res_NO; + return IsArc_Lzma(p + 1, size - 1); +} + STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *) { - RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_startPosition)); + Close(); - const UInt32 kBufSize = 1 + 5 + 8 + 1; + const UInt32 kBufSize = 1 + 5 + 8 + 2; Byte buf[kBufSize]; RINOK(ReadStream_FALSE(inStream, buf, kBufSize)); @@ -289,35 +355,71 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal if (!_header.Parse(buf, _lzma86)) return S_FALSE; const Byte *start = buf + GetHeaderSize(); - if (start[0] != 0) + if (start[0] != 0 /* || (start[1] & 0x80) != 0 */ ) // empty stream with EOS is not 0x80 return S_FALSE; - UInt64 endPos; - RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); - _packSize = endPos - _startPosition; - _packSizeDefined = true; + RINOK(inStream->Seek(0, STREAM_SEEK_END, &_packSize)); if (_packSize >= 24 && _header.Size == 0 && _header.FilterID == 0 && _header.LzmaProps[0] == 0) return S_FALSE; + _isArc = true; _stream = inStream; _seqStream = inStream; + _needSeekToStart = true; return S_OK; } STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) { Close(); + _isArc = true; _seqStream = stream; return S_OK; } STDMETHODIMP CHandler::Close() { - _packSizeDefined = false; + _isArc = false; + _packSize_Defined = false; + _unpackSize_Defined = false; + _numStreams_Defined = false; + + _dataAfterEnd = false; + _needMoreInput = false; + _unsupported = false; + _dataError = false; + + _packSize = 0; + + _needSeekToStart = false; + _stream.Release(); _seqStream.Release(); return S_OK; } +class CCompressProgressInfoImp: + public ICompressProgressInfo, + public CMyUnknownImp +{ + CMyComPtr<IArchiveOpenCallback> Callback; +public: + UInt64 Offset; + + MY_UNKNOWN_IMP1(ICompressProgressInfo) + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); + void Init(IArchiveOpenCallback *callback) { Callback = callback; } +}; + +STDMETHODIMP CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */) +{ + if (Callback) + { + UInt64 files = 0; + UInt64 value = Offset + *inSize; + return Callback->SetCompleted(&files, &value); + } + return S_OK; +} STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) @@ -325,10 +427,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_BEGIN if (numItems == 0) return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; - if (_stream) + if (_packSize_Defined) extractCallback->SetTotal(_packSize); @@ -352,10 +454,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, true); - if (_stream) + if (_needSeekToStart) { - RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL)); + if (!_stream) + return E_FAIL; + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); } + else + _needSeekToStart = true; CDecoder decoder; HRESULT result = decoder.Create( @@ -363,67 +469,132 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, _lzma86, _seqStream); RINOK(result); - Int32 opRes = NExtract::NOperationResult::kOK; bool firstItem = true; + UInt64 packSize = 0; + UInt64 unpackSize = 0; + UInt64 numStreams = 0; + + bool dataAfterEnd = false; + for (;;) { - lps->OutSize = outStreamSpec->GetSize(); - lps->InSize = _packSize = decoder.GetInputProcessedSize(); - _packSizeDefined = true; + lps->InSize = packSize; + lps->OutSize = unpackSize; RINOK(lps->SetCur()); - CHeader st; - const UInt32 kBufSize = 1 + 5 + 8; Byte buf[kBufSize]; const UInt32 headerSize = GetHeaderSize(); UInt32 processed; RINOK(decoder.ReadInput(buf, headerSize, &processed)); if (processed != headerSize) + { + if (processed != 0) + dataAfterEnd = true; break; + } + CHeader st; if (!st.Parse(buf, _lzma86)) + { + dataAfterEnd = true; break; + } + numStreams++; firstItem = false; result = decoder.Code(st, outStream, progress); + + packSize = decoder.GetInputProcessedSize(); + unpackSize = outStreamSpec->GetSize(); + if (result == E_NOTIMPL) { - opRes = NExtract::NOperationResult::kUnSupportedMethod; + _unsupported = true; + result = S_FALSE; break; } if (result == S_FALSE) - { - opRes = NExtract::NOperationResult::kDataError; break; - } RINOK(result); } + if (firstItem) - return E_FAIL; + { + _isArc = false; + result = S_FALSE; + } + else if (result == S_OK || result == S_FALSE) + { + if (dataAfterEnd) + _dataAfterEnd = true; + else if (decoder._lzmaDecoderSpec->NeedMoreInput) + _needMoreInput = true; + + _packSize = packSize; + _unpackSize = unpackSize; + _numStreams = numStreams; + + _packSize_Defined = true; + _unpackSize_Defined = true; + _numStreams_Defined = true; + } + + Int32 opResult = NExtract::NOperationResult::kOK; + + if (!_isArc) + opResult = NExtract::NOperationResult::kIsNotArc; + else if (_needMoreInput) + opResult = NExtract::NOperationResult::kUnexpectedEnd; + else if (_unsupported) + opResult = NExtract::NOperationResult::kUnsupportedMethod; + else if (_dataAfterEnd) + opResult = NExtract::NOperationResult::kDataAfterEnd; + else if (result == S_FALSE) + opResult = NExtract::NOperationResult::kDataError; + else if (result == S_OK) + opResult = NExtract::NOperationResult::kOK; + else + return result; + outStream.Release(); - return extractCallback->SetOperationResult(opRes); + return extractCallback->SetOperationResult(opResult); COM_TRY_END } IMPL_ISetCompressCodecsInfo -static IInArchive *CreateArc() { return new CHandler(false); } -static IInArchive *CreateArc86() { return new CHandler(true); } - namespace NLzmaAr { - + +IMP_CreateArcIn_2(CHandler(false)) + static CArcInfo g_ArcInfo = - { L"lzma", L"lzma", 0, 0xA, { 0 }, 0, true, CreateArc, NULL }; + { "lzma", "lzma", 0, 0xA, + 0, { 0 }, + // 2, { 0x5D, 0x00 }, + 0, + NArcInfoFlags::kStartOpen | + NArcInfoFlags::kKeepName, + CreateArc, NULL, + IsArc_Lzma }; + REGISTER_ARC(Lzma) } namespace NLzma86Ar { +IMP_CreateArcIn_2(CHandler(true)) + static CArcInfo g_ArcInfo = - { L"lzma86", L"lzma86", 0, 0xB, { 0 }, 0, true, CreateArc86, NULL }; + { "lzma86", "lzma86", 0, 0xB, + 0, { 0 }, + 0, + NArcInfoFlags::kKeepName, + CreateArc, NULL, + IsArc_Lzma86 }; + REGISTER_ARC(Lzma86) } diff --git a/CPP/7zip/Archive/MachoHandler.cpp b/CPP/7zip/Archive/MachoHandler.cpp index a6261f34..11ff9703 100755..100644 --- a/CPP/7zip/Archive/MachoHandler.cpp +++ b/CPP/7zip/Archive/MachoHandler.cpp @@ -4,10 +4,12 @@ #include "../../../C/CpuArch.h" -#include "Common/Buffer.h" -#include "Common/ComTry.h" +#include "../../Common/ComTry.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/StringConvert.h" +#include "../../Common/IntToString.h" -#include "Windows/PropVariantUtils.h" +#include "../../Windows/PropVariantUtils.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -16,65 +18,142 @@ #include "../Compress/CopyCoder.h" -static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); } -static UInt64 Get64(const Byte *p, int be) { if (be) return GetBe64(p); return GetUi64(p); } +static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); } +static UInt64 Get64(const Byte *p, bool be) { if (be) return GetBe64(p); return GetUi64(p); } using namespace NWindows; +using namespace NCOM; namespace NArchive { namespace NMacho { -#define MACH_ARCH_ABI64 (1 << 24) -#define MACH_MACHINE_386 7 -#define MACH_MACHINE_ARM 12 -#define MACH_MACHINE_SPARC 14 -#define MACH_MACHINE_PPC 18 +#define CPU_ARCH_ABI64 (1 << 24) +#define CPU_TYPE_386 7 +#define CPU_TYPE_ARM 12 +#define CPU_TYPE_SPARC 14 +#define CPU_TYPE_PPC 18 -#define MACH_MACHINE_PPC64 (MACH_ARCH_ABI64 | MACH_MACHINE_PPC) -#define MACH_MACHINE_AMD64 (MACH_ARCH_ABI64 | MACH_MACHINE_386) +#define CPU_SUBTYPE_I386_ALL 3 -#define MACH_CMD_SEGMENT_32 1 -#define MACH_CMD_SEGMENT_64 0x19 +#define CPU_TYPE_PPC64 (CPU_ARCH_ABI64 | CPU_TYPE_PPC) +#define CPU_TYPE_AMD64 (CPU_ARCH_ABI64 | CPU_TYPE_386) -#define MACH_SECT_TYPE_MASK 0x000000FF -#define MACH_SECT_ATTR_MASK 0xFFFFFF00 +#define CPU_SUBTYPE_LIB64 (1 << 31) -#define MACH_SECT_ATTR_ZEROFILL 1 +#define CPU_SUBTYPE_POWERPC_970 100 + +static const char *k_PowerPc_SubTypes[] = +{ + NULL + , "601" + , "602" + , "603" + , "603e" + , "603ev" + , "604" + , "604e" + , "620" + , "750" + , "7400" + , "7450" +}; + +static const CUInt32PCharPair g_CpuPairs[] = +{ + { CPU_TYPE_386, "x86" }, + { CPU_TYPE_ARM, "ARM" }, + { CPU_TYPE_SPARC, "SPARC" }, + { CPU_TYPE_PPC, "PowerPC" } +}; + + +#define CMD_SEGMENT_32 1 +#define CMD_SEGMENT_64 0x19 + +#define SECT_TYPE_MASK 0x000000FF +#define SECT_ATTR_MASK 0xFFFFFF00 + +#define SECT_ATTR_ZEROFILL 1 static const char *g_SectTypes[] = { - "REGULAR", - "ZEROFILL", - "CSTRINGS", - "4BYTE_LITERALS", - "8BYTE_LITERALS", - "LITERAL_POINTERS", - "NON_LAZY_SYMBOL_POINTERS", - "LAZY_SYMBOL_POINTERS", - "SYMBOL_STUBS", - "MOD_INIT_FUNC_POINTERS", - "MOD_TERM_FUNC_POINTERS", - "COALESCED", - "GB_ZEROFILL", - "INTERPOSING", - "16BYTE_LITERALS" + "REGULAR" + , "ZEROFILL" + , "CSTRINGS" + , "4BYTE_LITERALS" + , "8BYTE_LITERALS" + , "LITERAL_POINTERS" + , "NON_LAZY_SYMBOL_POINTERS" + , "LAZY_SYMBOL_POINTERS" + , "SYMBOL_STUBS" + , "MOD_INIT_FUNC_POINTERS" + , "MOD_TERM_FUNC_POINTERS" + , "COALESCED" + , "GB_ZEROFILL" + , "INTERPOSING" + , "16BYTE_LITERALS" +}; + +enum EFileType +{ + kType_OBJECT = 1, + kType_EXECUTE, + kType_FVMLIB, + kType_CORE, + kType_PRELOAD, + kType_DYLIB, + kType_DYLINKER, + kType_BUNDLE, + kType_DYLIB_STUB, + kType_DSYM }; static const char *g_FileTypes[] = { - "0", - "OBJECT", - "EXECUTE", - "FVMLIB", - "CORE", - "PRELOAD", - "DYLIB", - "DYLINKER", - "BUNDLE", - "DYLIB_STUB", - "DSYM" + "0" + , "OBJECT" + , "EXECUTE" + , "FVMLIB" + , "CORE" + , "PRELOAD" + , "DYLIB" + , "DYLINKER" + , "BUNDLE" + , "DYLIB_STUB" + , "DSYM" }; + +static const char *g_ArcFlags[] = +{ + "NOUNDEFS" + , "INCRLINK" + , "DYLDLINK" + , "BINDATLOAD" + , "PREBOUND" + , "SPLIT_SEGS" + , "LAZY_INIT" + , "TWOLEVEL" + , "FORCE_FLAT" + , "NOMULTIDEFS" + , "NOFIXPREBINDING" + , "PREBINDABLE" + , "ALLMODSBOUND" + , "SUBSECTIONS_VIA_SYMBOLS" + , "CANONICAL" + , "WEAK_DEFINES" + , "BINDS_TO_WEAK" + , "ALLOW_STACK_EXECUTION" + , "ROOT_SAFE" + , "SETUID_SAFE" + , "NO_REEXPORTED_DYLIBS" + , "PIE" + , "DEAD_STRIPPABLE_DYLIB" + , "HAS_TLV_DESCRIPTORS" + , "NO_HEAP_EXECUTION" +}; + + static const CUInt32PCharPair g_Flags[] = { { 31, "PURE_INSTRUCTIONS" }, @@ -89,16 +168,6 @@ static const CUInt32PCharPair g_Flags[] = { 8, "LOC_RELOC" } }; -static const CUInt32PCharPair g_MachinePairs[] = -{ - { MACH_MACHINE_386, "x86" }, - { MACH_MACHINE_ARM, "ARM" }, - { MACH_MACHINE_SPARC, "SPARC" }, - { MACH_MACHINE_PPC, "PowerPC" }, - { MACH_MACHINE_PPC64, "PowerPC 64-bit" }, - { MACH_MACHINE_AMD64, "x64" } -}; - static const int kNameSize = 16; struct CSegment @@ -121,209 +190,150 @@ struct CSection bool IsDummy; CSection(): IsDummy(false) {} - // UInt64 GetPackSize() const { return Flags == MACH_SECT_ATTR_ZEROFILL ? 0 : Size; } + // UInt64 GetPackSize() const { return Flags == SECT_ATTR_ZEROFILL ? 0 : Size; } UInt64 GetPackSize() const { return PSize; } }; class CHandler: public IInArchive, + public IArchiveAllowTail, public CMyUnknownImp { CMyComPtr<IInStream> _inStream; CObjectVector<CSegment> _segments; CObjectVector<CSection> _sections; + bool _allowTail; bool _mode64; bool _be; - UInt32 _machine; + UInt32 _cpuType; + UInt32 _cpuSubType; UInt32 _type; + UInt32 _flags; UInt32 _headersSize; UInt64 _totalSize; + HRESULT Open2(ISequentialInStream *stream); - bool Parse(const Byte *buf, UInt32 size); public: - MY_UNKNOWN_IMP1(IInArchive) + MY_UNKNOWN_IMP2(IInArchive, IArchiveAllowTail) INTERFACE_IInArchive(;) + STDMETHOD(AllowTail)(Int32 allowTail); + CHandler(): _allowTail(false) {} }; -bool CHandler::Parse(const Byte *buf, UInt32 size) +static const Byte kArcProps[] = { - bool mode64 = _mode64; - bool be = _be; - - const Byte *bufStart = buf; - bool reduceCommands = false; - if (size < 512) - return false; - - _machine = Get32(buf + 4, be); - _type = Get32(buf + 0xC, be); - - UInt32 numCommands = Get32(buf + 0x10, be); - UInt32 commandsSize = Get32(buf + 0x14, be); - if (commandsSize > size) - return false; - - if (commandsSize > (1 << 24) || numCommands > (1 << 18)) - return false; - - if (numCommands > 16) - { - reduceCommands = true; - numCommands = 16; - } - - _headersSize = 0; - - buf += 0x1C; - size -= 0x1C; + kpidCpu, + kpidBit64, + kpidBigEndian, + kpidCharacts, + kpidHeadersSize +}; - if (mode64) - { - buf += 4; - size -= 4; - } +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidCharacts, + kpidOffset, + kpidVa +}; - _totalSize = (UInt32)(buf - bufStart); - if (commandsSize < size) - size = commandsSize; +IMP_IInArchive_Props +IMP_IInArchive_ArcProps - for (UInt32 cmdIndex = 0; cmdIndex < numCommands; cmdIndex++) +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + CPropVariant prop; + switch (propID) { - if (size < 8) - return false; - UInt32 cmd = Get32(buf, be); - UInt32 cmdSize = Get32(buf + 4, be); - if (size < cmdSize) - return false; - if (cmd == MACH_CMD_SEGMENT_32 || cmd == MACH_CMD_SEGMENT_64) + case kpidShortComment: + case kpidCpu: { - UInt32 offs = (cmd == MACH_CMD_SEGMENT_64) ? 0x48 : 0x38; - if (cmdSize < offs) - break; - - UInt64 vmAddr, vmSize, phAddr, phSize; - + AString s; + char temp[16]; + UInt32 cpu = _cpuType & ~(UInt32)CPU_ARCH_ABI64; + if (_cpuType == CPU_TYPE_AMD64) + s = "x64"; + else { - if (cmd == MACH_CMD_SEGMENT_64) - { - vmAddr = Get64(buf + 0x18, be); - vmSize = Get64(buf + 0x20, be); - phAddr = Get64(buf + 0x28, be); - phSize = Get64(buf + 0x30, be); - } - else + const char *n = NULL; + for (unsigned i = 0; i < ARRAY_SIZE(g_CpuPairs); i++) { - vmAddr = Get32(buf + 0x18, be); - vmSize = Get32(buf + 0x1C, be); - phAddr = Get32(buf + 0x20, be); - phSize = Get32(buf + 0x24, be); + const CUInt32PCharPair &pair = g_CpuPairs[i]; + if (pair.Value == cpu) + { + n = pair.Name; + break; + } } + if (!n) { - UInt64 totalSize = phAddr + phSize; - if (totalSize > _totalSize) - _totalSize = totalSize; + ConvertUInt32ToString(cpu, temp); + n = temp; } + s = n; + + if (_cpuType & CPU_ARCH_ABI64) + s += " 64-bit"; + else if (_cpuSubType & CPU_SUBTYPE_LIB64) + s += " 64-bit lib"; } - - CSegment seg; - memcpy(seg.Name, buf + 8, kNameSize); - _segments.Add(seg); - - UInt32 numSections = Get32(buf + offs - 8, be); - if (numSections > (1 << 8)) - return false; - - if (numSections == 0) - { - CSection section; - section.IsDummy = true; - section.SegmentIndex = _segments.Size() - 1; - section.Va = vmAddr; - section.PSize = phSize; - section.VSize = vmSize; - section.Pa = phAddr; - section.Flags = 0; - _sections.Add(section); - } - else do + UInt32 t = _cpuSubType & ~(UInt32)CPU_SUBTYPE_LIB64; + if (t != 0 && (t != CPU_SUBTYPE_I386_ALL || cpu != CPU_TYPE_386)) { - CSection section; - UInt32 headerSize = (cmd == MACH_CMD_SEGMENT_64) ? 0x50 : 0x44; - const Byte *p = buf + offs; - if (cmdSize - offs < headerSize) - break; - if (cmd == MACH_CMD_SEGMENT_64) + const char *n = NULL; + if (cpu == CPU_TYPE_PPC) { - section.Va = Get64(p + 0x20, be); - section.VSize = Get64(p + 0x28, be); - section.Pa = Get32(p + 0x30, be); - section.Flags = Get32(p + 0x40, be); + if (t == CPU_SUBTYPE_POWERPC_970) + n = "970"; + else if (t < ARRAY_SIZE(k_PowerPc_SubTypes)) + n = k_PowerPc_SubTypes[t]; } - else + if (!n) { - section.Va = Get32(p + 0x20, be); - section.VSize = Get32(p + 0x24, be); - section.Pa = Get32(p + 0x28, be); - section.Flags = Get32(p + 0x38, be); + ConvertUInt32ToString(t, temp); + n = temp; } - if (section.Flags == MACH_SECT_ATTR_ZEROFILL) - section.PSize = 0; - else - section.PSize = section.VSize; - memcpy(section.Name, p, kNameSize); - memcpy(section.SegName, p + kNameSize, kNameSize); - section.SegmentIndex = _segments.Size() - 1; - _sections.Add(section); - offs += headerSize; + s += ' '; + s += n; } - while (--numSections); - - if (offs != cmdSize) - return false; + prop = s; + break; + } + 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); + if (!s.IsEmpty()) + { + res += ' '; + res += s; + } + prop = res; + break; } - buf += cmdSize; - size -= cmdSize; - } - _headersSize = (UInt32)(buf - bufStart); - return reduceCommands || (size == 0); -} - -static STATPROPSTG kArcProps[] = -{ - { NULL, kpidCpu, VT_BSTR}, - { NULL, kpidBit64, VT_BOOL}, - { NULL, kpidBigEndian, VT_BOOL}, - { NULL, kpidCharacts, VT_BSTR}, - { NULL, kpidPhySize, VT_UI8}, - { NULL, kpidHeadersSize, VT_UI4} -}; - -static STATPROPSTG kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidCharacts, VT_BSTR}, - { NULL, kpidOffset, VT_UI8}, - { NULL, kpidVa, VT_UI8} -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch(propID) - { - case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _machine, prop); break; - case kpidCharacts: TYPE_TO_PROP(g_FileTypes, _type, prop); break; case kpidPhySize: prop = _totalSize; break; case kpidHeadersSize: prop = _headersSize; break; case kpidBit64: if (_mode64) prop = _mode64; break; case kpidBigEndian: if (_be) prop = _be; break; + case kpidExtension: + { + const char *ext = NULL; + if (_type == kType_OBJECT) + ext = "o"; + else if (_type == kType_BUNDLE) + ext = "bundle"; + else if (_type == kType_DYLIB) + ext = "dylib"; // main shared library usually does not have extension + if (ext) + prop = ext; + break; + } + // case kpidIsSelfExe: prop = (_type == kType_EXECUTE); break; } prop.Detach(value); return S_OK; @@ -340,10 +350,8 @@ static AString GetName(const char *name) static AString SectFlagsToString(UInt32 flags) { - AString res = TypeToString(g_SectTypes, sizeof(g_SectTypes) / sizeof(g_SectTypes[0]), - flags & MACH_SECT_TYPE_MASK); - AString s = FlagsToString(g_Flags, sizeof(g_Flags) / sizeof(g_Flags[0]), - flags & MACH_SECT_ATTR_MASK); + 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 += ' '; @@ -355,21 +363,21 @@ static AString SectFlagsToString(UInt32 flags) STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NCOM::CPropVariant prop; + CPropVariant prop; const CSection &item = _sections[index]; - switch(propID) + switch (propID) { case kpidPath: { AString s = GetName(_segments[item.SegmentIndex].Name); if (!item.IsDummy) s += GetName(item.Name); - StringToProp(s, prop); + prop = MultiByteToUnicodeString(s); break; } case kpidSize: /* prop = (UInt64)item.VSize; break; */ case kpidPackSize: prop = (UInt64)item.GetPackSize(); break; - case kpidCharacts: if (!item.IsDummy) StringToProp(SectFlagsToString(item.Flags), prop); break; + case kpidCharacts: if (!item.IsDummy) prop = SectFlagsToString(item.Flags); break; case kpidOffset: prop = item.Pa; break; case kpidVa: prop = item.Va; break; } @@ -380,18 +388,12 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val HRESULT CHandler::Open2(ISequentialInStream *stream) { - const UInt32 kBufSize = 1 << 18; - const UInt32 kSigSize = 4; + const UInt32 kStartHeaderSize = 7 * 4; - CByteBuffer buffer; - buffer.SetCapacity(kBufSize); - Byte *buf = buffer; - - size_t processed = kSigSize; - RINOK(ReadStream_FALSE(stream, buf, processed)); - UInt32 sig = GetUi32(buf); + Byte header[kStartHeaderSize]; + RINOK(ReadStream_FALSE(stream, header, kStartHeaderSize)); bool be, mode64; - switch(sig) + switch (GetUi32(header)) { case 0xCEFAEDFE: be = true; mode64 = false; break; case 0xCFFAEDFE: be = true; mode64 = true; break; @@ -399,11 +401,148 @@ HRESULT CHandler::Open2(ISequentialInStream *stream) case 0xFEEDFACF: be = false; mode64 = true; break; default: return S_FALSE; } - processed = kBufSize - kSigSize; - RINOK(ReadStream(stream, buf + kSigSize, &processed)); - _mode64 = mode64; - _be = be; - return Parse(buf, (UInt32)processed + kSigSize) ? S_OK : S_FALSE; + + UInt32 numCommands = Get32(header + 0x10, be); + UInt32 commandsSize = Get32(header + 0x14, be); + + if (numCommands == 0) + return S_FALSE; + + if (commandsSize > (1 << 24) || + numCommands > (1 << 21) || + numCommands * 8 > commandsSize) + return S_FALSE; + + _cpuType = Get32(header + 4, be); + _cpuSubType = Get32(header + 8, be); + _type = Get32(header + 0xC, be); + _flags = Get32(header + 0x18, be); + + /* + // Probably the sections are in first commands. So we can reduce the number of commands. + bool reduceCommands = false; + const UInt32 kNumReduceCommands = 16; + if (numCommands > kNumReduceCommands) + { + reduceCommands = true; + numCommands = kNumReduceCommands; + } + */ + + UInt32 startHeaderSize = kStartHeaderSize; + if (mode64) + startHeaderSize += 4; + _headersSize = startHeaderSize + commandsSize; + _totalSize = _headersSize; + CByteArr buffer(_headersSize); + RINOK(ReadStream_FALSE(stream, buffer + kStartHeaderSize, _headersSize - kStartHeaderSize)); + const Byte *buf = buffer + startHeaderSize; + size_t size = _headersSize - startHeaderSize; + for (UInt32 cmdIndex = 0; cmdIndex < numCommands; cmdIndex++) + { + if (size < 8) + return S_FALSE; + UInt32 cmd = Get32(buf, be); + UInt32 cmdSize = Get32(buf + 4, be); + if (cmdSize < 8) + return S_FALSE; + if (size < cmdSize) + return S_FALSE; + if (cmd == CMD_SEGMENT_32 || cmd == CMD_SEGMENT_64) + { + UInt32 offs = (cmd == CMD_SEGMENT_64) ? 0x48 : 0x38; + if (cmdSize < offs) + break; + + UInt64 vmAddr, vmSize, phAddr, phSize; + + { + if (cmd == CMD_SEGMENT_64) + { + vmAddr = Get64(buf + 0x18, be); + vmSize = Get64(buf + 0x20, be); + phAddr = Get64(buf + 0x28, be); + phSize = Get64(buf + 0x30, be); + } + else + { + vmAddr = Get32(buf + 0x18, be); + vmSize = Get32(buf + 0x1C, be); + phAddr = Get32(buf + 0x20, be); + phSize = Get32(buf + 0x24, be); + } + { + UInt64 totalSize = phAddr + phSize; + if (totalSize < phAddr) + return S_FALSE; + if (_totalSize < totalSize) + _totalSize = totalSize; + } + } + + CSegment seg; + memcpy(seg.Name, buf + 8, kNameSize); + _segments.Add(seg); + + UInt32 numSections = Get32(buf + offs - 8, be); + if (numSections > (1 << 8)) + return S_FALSE; + + if (numSections == 0) + { + CSection § = _sections.AddNew(); + sect.IsDummy = true; + sect.SegmentIndex = _segments.Size() - 1; + sect.Va = vmAddr; + sect.PSize = phSize; + sect.VSize = vmSize; + sect.Pa = phAddr; + sect.Flags = 0; + } + else do + { + UInt32 headSize = (cmd == CMD_SEGMENT_64) ? 0x50 : 0x44; + const Byte *p = buf + offs; + if (cmdSize - offs < headSize) + break; + CSection § = _sections.AddNew(); + unsigned f32Offset; + if (cmd == CMD_SEGMENT_64) + { + sect.Va = Get64(p + 0x20, be); + sect.VSize = Get64(p + 0x28, be); + f32Offset = 0x30; + } + else + { + sect.Va = Get32(p + 0x20, be); + sect.VSize = Get32(p + 0x24, be); + f32Offset = 0x28; + } + sect.Pa = Get32(p + f32Offset, be); + sect.Flags = Get32(p + f32Offset + 10, be); + if (sect.Flags == SECT_ATTR_ZEROFILL) + sect.PSize = 0; + else + sect.PSize = sect.VSize; + memcpy(sect.Name, p, kNameSize); + memcpy(sect.SegName, p + kNameSize, kNameSize); + sect.SegmentIndex = _segments.Size() - 1; + offs += headSize; + } + while (--numSections); + + if (offs != cmdSize) + return S_FALSE; + } + buf += cmdSize; + size -= cmdSize; + } + // return (reduceCommands || (size == 0)) ? S_OK : S_FALSE; + if (size != 0) + return S_FALSE; + + return S_OK; } STDMETHODIMP CHandler::Open(IInStream *inStream, @@ -413,6 +552,13 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, COM_TRY_BEGIN Close(); RINOK(Open2(inStream)); + if (!_allowTail) + { + UInt64 fileSize; + RINOK(inStream->Seek(0, STREAM_SEEK_END, &fileSize)); + if (fileSize > _totalSize) + return S_FALSE; + } _inStream = inStream; return S_OK; COM_TRY_END @@ -420,6 +566,7 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, STDMETHODIMP CHandler::Close() { + _totalSize = 0; _inStream.Release(); _sections.Clear(); _segments.Clear(); @@ -436,7 +583,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _sections.Size(); if (numItems == 0) @@ -490,10 +637,27 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +STDMETHODIMP CHandler::AllowTail(Int32 allowTail) +{ + _allowTail = IntToBool(allowTail); + return S_OK; +} + +IMP_CreateArcIn + +#define k_Signature { \ + 4, 0xCE, 0xFA, 0xED, 0xFE, \ + 4, 0xCF, 0xFA, 0xED, 0xFE, \ + 4, 0xFE, 0xED, 0xFA, 0xCE, \ + 4, 0xFE, 0xED, 0xFA, 0xCF } static CArcInfo g_ArcInfo = - { L"MachO", L"", 0, 0xDF, { 0 }, 0, false, CreateArc, 0 }; + { "MachO", "macho", 0, 0xDF, + 4 * 5, k_Signature, + 0, + NArcInfoFlags::kMultiSignature | + NArcInfoFlags::kPreArc, + CreateArc }; REGISTER_ARC(Macho) diff --git a/CPP/7zip/Archive/MbrHandler.cpp b/CPP/7zip/Archive/MbrHandler.cpp index b6d79182..309bc286 100755..100644 --- a/CPP/7zip/Archive/MbrHandler.cpp +++ b/CPP/7zip/Archive/MbrHandler.cpp @@ -10,12 +10,12 @@ #include "../../../C/CpuArch.h" -#include "Common/Buffer.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/MyString.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/MyString.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -169,7 +169,7 @@ static const CPartType kPartTypes[] = static int FindPartType(UInt32 type) { - for (int i = 0; i < sizeof(kPartTypes) / sizeof(kPartTypes[0]); i++) + for (int i = 0; i < ARRAY_SIZE(kPartTypes); i++) if (kPartTypes[i].Id == type) return i; return -1; @@ -210,7 +210,7 @@ HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, int { const UInt32 kSectorSize = 512; - _buffer.SetCapacity(kSectorSize); + _buffer.Alloc(kSectorSize); Byte *buf = _buffer; UInt64 newPos = (UInt64)lba << 9; if (newPos + 512 > _totalSize) @@ -243,7 +243,7 @@ HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, int part.Print(); #endif - int numItems = _items.Size(); + unsigned numItems = _items.Size(); UInt32 newLba = lba + part.Lba; if (part.IsExtended()) @@ -323,6 +323,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, STDMETHODIMP CHandler::Close() { + _totalSize = 0; _items.Clear(); _stream.Release(); return S_OK; @@ -335,7 +336,7 @@ enum kpidEndChs }; -STATPROPSTG kProps[] = +static const STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, { NULL, kpidSize, VT_UI8}, @@ -352,12 +353,12 @@ IMP_IInArchive_ArcProps_NO_Table STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidMainSubfile: { int mainIndex = -1; - for (int i = 0; i < _items.Size(); i++) + FOR_VECTOR (i, _items) if (_items[i].IsReal) { if (mainIndex >= 0) @@ -371,6 +372,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) prop = (UInt32)mainIndex; break; } + case kpidPhySize: prop = _totalSize; break; } prop.Detach(value); return S_OK; @@ -435,7 +437,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (numItems == 0) @@ -497,10 +499,16 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"MBR", L"mbr", 0, 0xDB, { 1, 1, 0 }, 3, false, CreateArc, 0 }; + { "MBR", "mbr", 0, 0xDB, + // 3, { 1, 1, 0 }, + // 2, { 0x55, 0x1FF }, + 0, { 0 }, + 0, + NArcInfoFlags::kPureStartOpen, + CreateArc }; REGISTER_ARC(Mbr) diff --git a/CPP/7zip/Archive/MslzHandler.cpp b/CPP/7zip/Archive/MslzHandler.cpp index 67495e76..cb124c40 100755..100644 --- a/CPP/7zip/Archive/MslzHandler.cpp +++ b/CPP/7zip/Archive/MslzHandler.cpp @@ -4,10 +4,10 @@ #include "../../../C/CpuArch.h" -#include "Common/ComTry.h" -#include "Common/MyString.h" +#include "../../Common/ComTry.h" +#include "../../Common/MyString.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" #include "../Common/InBuffer.h" #include "../Common/ProgressUtils.h" @@ -19,28 +19,45 @@ namespace NArchive { namespace NMslz { +static const UInt32 kUnpackSizeMax = 0xFFFFFFE0; + class CHandler: public IInArchive, + public IArchiveOpenSeq, public CMyUnknownImp { - CMyComPtr<IInStream> _stream; - UInt32 _size; + CMyComPtr<IInStream> _inStream; + CMyComPtr<ISequentialInStream> _seqStream; + + bool _isArc; + bool _needSeekToStart; + bool _dataAfterEnd; + bool _needMoreInput; + + bool _packSize_Defined; + bool _unpackSize_Defined; + + UInt32 _unpackSize; UInt64 _packSize; + UInt64 _originalFileSize; UString _name; + + void ParseName(Byte replaceByte, IArchiveOpenCallback *callback); public: - MY_UNKNOWN_IMP1(IInArchive) + MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq) INTERFACE_IInArchive(;) + STDMETHOD(OpenSeq)(ISequentialInStream *stream); }; -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, + kpidPath, + kpidSize, + kpidPackSize, }; IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO +IMP_IInArchive_ArcProps_NO_Table STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { @@ -48,15 +65,39 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidExtension: prop = "mslz"; break; + case kpidIsNotArcType: prop = true; break; + case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; + if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; + prop = v; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NWindows::NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidPath: if (!_name.IsEmpty()) prop = _name; break; - case kpidSize: prop = _size; break; - case kpidPackSize: prop = _packSize; break; + case kpidSize: if (_unpackSize_Defined || _inStream) prop = _unpackSize; break; + case kpidPackSize: if (_packSize_Defined || _inStream) prop = _packSize; break; } prop.Detach(value); return S_OK; @@ -67,69 +108,80 @@ static const unsigned kSignatureSize = 9; static const unsigned kHeaderSize = kSignatureSize + 1 + 4; #define MSLZ_SIGNATURE { 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33, 0x41 } // old signature: 53 5A 20 88 F0 27 33 -static const Byte signature[kSignatureSize] = MSLZ_SIGNATURE; +static const Byte kSignature[kSignatureSize] = MSLZ_SIGNATURE; -static const wchar_t *g_Exts[] = +// we support only 3 chars strings here +static const char *g_Exts[] = { - L"dll", - L"exe", - L"kmd", - L"sys" + "dll" + , "exe" + , "kmd" + , "sys" }; +void CHandler::ParseName(Byte replaceByte, IArchiveOpenCallback *callback) +{ + if (!callback) + return; + CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback; + callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback); + if (!volumeCallback) + return; + + NWindows::NCOM::CPropVariant prop; + if (volumeCallback->GetProperty(kpidName, &prop) != S_OK || prop.vt != VT_BSTR) + return; + + UString s = prop.bstrVal; + if (s.IsEmpty() || + s.Back() != L'_') + return; + + s.DeleteBack(); + _name = s; + + if (replaceByte == 0) + { + if (s.Len() < 3 || s[s.Len() - 3] != '.') + return; + for (unsigned i = 0; i < ARRAY_SIZE(g_Exts); i++) + { + const char *ext = g_Exts[i]; + if (s[s.Len() - 2] == ext[0] && + s[s.Len() - 1] == ext[1]) + { + replaceByte = ext[2]; + break; + } + } + } + if (replaceByte >= 0x20 && replaceByte < 0x80) + _name += (wchar_t)replaceByte; +} + STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback) { COM_TRY_BEGIN { Close(); + _needSeekToStart = true; Byte buffer[kHeaderSize]; RINOK(ReadStream_FALSE(stream, buffer, kHeaderSize)); - if (memcmp(buffer, signature, kSignatureSize) != 0) + if (memcmp(buffer, kSignature, kSignatureSize) != 0) return S_FALSE; - _size = GetUi32(buffer + 10); - if (_size > 0xFFFFFFE0) + _unpackSize = GetUi32(buffer + 10); + if (_unpackSize > kUnpackSizeMax) return S_FALSE; - RINOK(stream->Seek(0, STREAM_SEEK_END, &_packSize)); + RINOK(stream->Seek(0, STREAM_SEEK_END, &_originalFileSize)); + _packSize = _originalFileSize; - if (callback) - { - CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; - callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); - if (openVolumeCallback) - { - NWindows::NCOM::CPropVariant prop; - if (openVolumeCallback->GetProperty(kpidName, &prop) == S_OK && prop.vt == VT_BSTR) - { - UString baseName = prop.bstrVal; - if (!baseName.IsEmpty() && baseName.Back() == L'_') - { - baseName.DeleteBack(); - Byte replaceByte = buffer[kSignatureSize]; - if (replaceByte == 0) - { - for (int i = 0; i < sizeof(g_Exts) / sizeof(g_Exts[0]); i++) - { - UString s = g_Exts[i]; - int len = s.Length(); - Byte b = (Byte)s.Back(); - s.DeleteBack(); - if (baseName.Length() >= len && - baseName[baseName.Length() - len] == '.' && - s.CompareNoCase(baseName.Right(len - 1)) == 0) - { - replaceByte = b; - break; - } - } - } - if (replaceByte >= 0x20 && replaceByte < 0x80) - _name = baseName + (wchar_t)replaceByte; - } - } - } - } - _stream = stream; + ParseName(buffer[kSignatureSize], callback); + + _isArc = true; + _unpackSize_Defined = true; + _inStream = stream; + _seqStream = stream; } return S_OK; COM_TRY_END @@ -137,7 +189,20 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPo STDMETHODIMP CHandler::Close() { - _stream.Release(); + _originalFileSize = 0; + _packSize = 0; + _unpackSize = 0; + + _isArc = false; + _needSeekToStart = false; + _dataAfterEnd = false; + _needMoreInput = false; + + _packSize_Defined = false; + _unpackSize_Defined = false; + + _seqStream.Release(); + _inStream.Release(); _name.Empty(); return S_OK; } @@ -147,12 +212,13 @@ STDMETHODIMP CHandler::Close() // maxLen = 16; MS #define PROGRESS_AND_WRITE \ - if ((dest & kMask) == 0) { RINOK(WriteStream(outStream, buf, kBufSize)); \ + if ((dest & kMask) == 0) { if (outStream) RINOK(WriteStream(outStream, buf, kBufSize)); \ if ((dest & ((1 << 20) - 1)) == 0) \ - { UInt64 inSize = inStream.GetProcessedSize(); UInt64 outSize = dest; \ - RINOK(progress->SetRatioInfo(&inSize, &outSize)); }} + if (progress) \ + { UInt64 inSize = inStream.GetProcessedSize(); UInt64 outSize = dest; \ + RINOK(progress->SetRatioInfo(&inSize, &outSize)); }} -static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UInt32 unpackSize, ICompressProgressInfo *progress) +static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UInt32 unpackSize, bool &needMoreData, ICompressProgressInfo *progress) { const unsigned kBufSize = (1 << 12); const unsigned kMask = kBufSize - 1; @@ -163,11 +229,17 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn { Byte b; if (!inStream.ReadByte(b)) + { + needMoreData = true; return S_FALSE; + } for (unsigned mask = (unsigned)b | 0x100; mask > 1 && dest < unpackSize; mask >>= 1) { if (!inStream.ReadByte(b)) + { + needMoreData = true; return S_FALSE; + } if (mask & 1) { buf[dest++ & kMask] = b; @@ -177,7 +249,10 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn { Byte b1; if (!inStream.ReadByte(b1)) + { + needMoreData = true; return S_FALSE; + } const unsigned kMaxLen = 16; // 18 in Okumura's code. unsigned src = (((((unsigned)b1 & 0xF0) << 4) | b) + kMaxLen) & kMask; unsigned len = (b1 & 0xF) + 3; @@ -192,7 +267,19 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn } } } - return WriteStream(outStream, buf, dest & kMask); + if (outStream) + RINOK(WriteStream(outStream, buf, dest & kMask)); + return S_OK; +} + +STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) +{ + COM_TRY_BEGIN + Close(); + _isArc = true; + _seqStream = stream; + return S_OK; + COM_TRY_END } STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, @@ -201,10 +288,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_BEGIN if (numItems == 0) return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; - extractCallback->SetTotal(_size); + // extractCallback->SetTotal(_unpackSize); CMyComPtr<ISequentialOutStream> realOutStream; Int32 askMode = testMode ? @@ -225,32 +312,81 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); - - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - CInBuffer s; - if (!s.Create(1 << 20)) - return E_OUTOFMEMORY; - s.SetStream(_stream); - s.Init(); - Byte buffer[kHeaderSize]; + + if (_needSeekToStart) + { + if (!_inStream) + return E_FAIL; + RINOK(_inStream->Seek(0, STREAM_SEEK_SET, NULL)); + } + else + _needSeekToStart = true; + Int32 opRes = NExtract::NOperationResult::kDataError; - if (s.ReadBytes(buffer, kHeaderSize) == kHeaderSize) + + bool isArc = false; + bool needMoreInput = false; + try { - HRESULT result = MslzDec(s, outStream, _size, progress); - if (result == S_OK) - opRes = NExtract::NOperationResult::kOK; - else if (result != S_FALSE) - return result; + CInBuffer s; + if (!s.Create(1 << 20)) + return E_OUTOFMEMORY; + s.SetStream(_seqStream); + s.Init(); + + Byte buffer[kHeaderSize]; + if (s.ReadBytes(buffer, kHeaderSize) == kHeaderSize) + { + UInt32 unpackSize; + if (memcmp(buffer, kSignature, kSignatureSize) == 0) + { + unpackSize = GetUi32(buffer + 10); + if (unpackSize <= kUnpackSizeMax) + { + HRESULT result = MslzDec(s, outStream, unpackSize, needMoreInput, progress); + if (result == S_OK) + opRes = NExtract::NOperationResult::kOK; + else if (result != S_FALSE) + return result; + _unpackSize = unpackSize; + _unpackSize_Defined = true; + + _packSize = s.GetProcessedSize(); + _packSize_Defined = true; + + if (_inStream && _packSize < _originalFileSize) + _dataAfterEnd = true; + + isArc = true; + } + } + } } + catch (CInBufferException &e) { return e.ErrorCode; } + + _isArc = isArc; + if (isArc) + _needMoreInput = needMoreInput; + if (!_isArc) + opRes = NExtract::NOperationResult::kIsNotArc; + else if (_needMoreInput) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + else if (_dataAfterEnd) + opRes = NExtract::NOperationResult::kDataAfterEnd; + outStream.Release(); return extractCallback->SetOperationResult(opRes); COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"MsLZ", L"", 0, 0xD5, MSLZ_SIGNATURE, kSignatureSize, false, CreateArc, 0 }; + { "MsLZ", "mslz", 0, 0xD5, + kSignatureSize, MSLZ_SIGNATURE, + 0, + 0, + CreateArc }; REGISTER_ARC(Mslz) diff --git a/CPP/7zip/Archive/MubHandler.cpp b/CPP/7zip/Archive/MubHandler.cpp index 5ebda099..39f8de27 100755..100644 --- a/CPP/7zip/Archive/MubHandler.cpp +++ b/CPP/7zip/Archive/MubHandler.cpp @@ -4,9 +4,11 @@ #include "../../../C/CpuArch.h" -#include "Common/ComTry.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyString.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -15,32 +17,50 @@ #include "../Compress/CopyCoder.h" -static UInt32 Get32(const Byte *p, int be) { if (be) return GetBe32(p); return GetUi32(p); } +static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); } + +using namespace NWindows; +using namespace NCOM; namespace NArchive { namespace NMub { +#define MACH_CPU_ARCH_ABI64 (1 << 24) +#define MACH_CPU_TYPE_386 7 +#define MACH_CPU_TYPE_ARM 12 +#define MACH_CPU_TYPE_SPARC 14 +#define MACH_CPU_TYPE_PPC 18 + +#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_SUBTYPE_LIB64 (1 << 31) + +#define MACH_CPU_SUBTYPE_I386_ALL 3 + struct CItem { UInt32 Type; UInt32 SubType; - UInt64 Offset; - UInt64 Size; - UInt32 Align; - bool IsTail; + UInt32 Offset; + UInt32 Size; + // UInt32 Align; }; -const UInt32 kNumFilesMax = 10; +static const UInt32 kNumFilesMax = 10; class CHandler: public IInArchive, public IInArchiveGetStream, public CMyUnknownImp { - UInt64 _startPos; CMyComPtr<IInStream> _stream; + // UInt64 _startPos; + UInt64 _phySize; UInt32 _numItems; - CItem _items[kNumFilesMax + 1]; + bool _bigEndian; + CItem _items[kNumFilesMax]; + HRESULT Open2(IInStream *stream); public: MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) @@ -48,65 +68,79 @@ public: STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; -STATPROPSTG kProps[] = +static const Byte kArcProps[] = { - { NULL, kpidSize, VT_UI8} + kpidBigEndian }; -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO +static const Byte kProps[] = +{ + kpidSize +}; -#define MACH_ARCH_ABI64 0x1000000 -#define MACH_MACHINE_386 7 -#define MACH_MACHINE_ARM 12 -#define MACH_MACHINE_SPARC 14 -#define MACH_MACHINE_PPC 18 +IMP_IInArchive_Props +IMP_IInArchive_ArcProps -#define MACH_MACHINE_PPC64 (MACH_MACHINE_PPC | MACH_ARCH_ABI64) -#define MACH_MACHINE_AMD64 (MACH_MACHINE_386 | MACH_ARCH_ABI64) +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + PropVariant_Clear(value); + switch (propID) + { + case kpidBigEndian: PropVarEm_Set_Bool(value, _bigEndian); break; + case kpidPhySize: PropVarEm_Set_UInt64(value, _phySize); break; + } + return S_OK; +} STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { - NWindows::NCOM::CPropVariant prop; + PropVariant_Clear(value); const CItem &item = _items[index]; - switch(propID) + switch (propID) { case kpidExtension: { - const wchar_t *ext; - if (item.IsTail) - ext = L"tail"; - else + char temp[32]; + const char *ext = 0; + switch (item.Type) { - switch(item.Type) - { - case MACH_MACHINE_386: ext = L"86"; break; - case MACH_MACHINE_ARM: ext = L"arm"; break; - case MACH_MACHINE_SPARC: ext = L"sparc"; break; - case MACH_MACHINE_PPC: ext = L"ppc"; break; - case MACH_MACHINE_PPC64: ext = L"ppc64"; break; - case MACH_MACHINE_AMD64: ext = L"x64"; break; - default: ext = L"unknown"; 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; + default: + temp[0] = 'c'; + temp[1] = 'p'; + temp[2] = 'u'; + ConvertUInt32ToString(item.Type, temp + 3); + break; } - prop = ext; - break; + if (ext) + strcpy(temp, ext); + if (item.SubType != 0 && ( + item.Type != MACH_CPU_TYPE_386 && + item.Type != MACH_CPU_TYPE_AMD64 || + (item.SubType & ~(UInt32)MACH_CPU_SUBTYPE_LIB64) != MACH_CPU_SUBTYPE_I386_ALL)) + { + unsigned pos = MyStringLen(temp); + temp[pos++] = '-'; + ConvertUInt32ToString(item.SubType, temp + pos); + } + return PropVarEm_Set_Str(value, temp); } case kpidSize: case kpidPackSize: - prop = (UInt64)item.Size; + PropVarEm_Set_UInt64(value, item.Size); break; } - prop.Detach(value); return S_OK; } -#define MACH_TYPE_ABI64 (1 << 24) -#define MACH_SUBTYPE_ABI64 (1 << 31) - HRESULT CHandler::Open2(IInStream *stream) { - RINOK(stream->Seek(0, STREAM_SEEK_SET, &_startPos)); + // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPos)); const UInt32 kHeaderSize = 8; const UInt32 kRecordSize = 5 * 4; @@ -124,44 +158,37 @@ HRESULT CHandler::Open2(IInStream *stream) case 0xB9FAF10E: be = false; break; default: return S_FALSE; } + _bigEndian = be; UInt32 num = Get32(buf + 4, be); if (num > kNumFilesMax || processed < kHeaderSize + num * kRecordSize) return S_FALSE; + if (num == 0) + return S_FALSE; UInt64 endPosMax = kHeaderSize; + for (UInt32 i = 0; i < num; i++) { const Byte *p = buf + kHeaderSize + i * kRecordSize; CItem &sb = _items[i]; - sb.IsTail = false; sb.Type = Get32(p, be); sb.SubType = Get32(p + 4, be); sb.Offset = Get32(p + 8, be); sb.Size = Get32(p + 12, be); - sb.Align = Get32(p + 16, be); - - if ((sb.Type & ~MACH_TYPE_ABI64) >= 0x100 || - (sb.SubType & ~MACH_SUBTYPE_ABI64) >= 0x100 || - sb.Align > 31) + UInt32 align = Get32(p + 16, be); + if (align > 31) + return S_FALSE; + if (sb.Offset < kHeaderSize + num * kRecordSize) + return S_FALSE; + if ((sb.Type & ~MACH_CPU_ARCH_ABI64) >= 0x100 || + (sb.SubType & ~MACH_CPU_SUBTYPE_LIB64) >= 0x100) return S_FALSE; UInt64 endPos = (UInt64)sb.Offset + sb.Size; - if (endPos > endPosMax) + if (endPosMax < endPos) endPosMax = endPos; } - UInt64 fileSize; - RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); - fileSize -= _startPos; _numItems = num; - if (fileSize > endPosMax) - { - CItem &sb = _items[_numItems++]; - sb.IsTail = true; - sb.Type = 0; - sb.SubType = 0; - sb.Offset = endPosMax; - sb.Size = fileSize - endPosMax; - sb.Align = 0; - } + _phySize = endPosMax; return S_OK; } @@ -186,6 +213,7 @@ STDMETHODIMP CHandler::Close() { _stream.Release(); _numItems = 0; + _phySize = 0; return S_OK; } @@ -199,7 +227,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _numItems; if (numItems == 0) @@ -244,7 +272,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); continue; } - RINOK(_stream->Seek(_startPos + item.Offset, STREAM_SEEK_SET, NULL)); + RINOK(_stream->Seek(/* _startPos + */ item.Offset, STREAM_SEEK_SET, NULL)); streamSpec->Init(item.Size); RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); realOutStream.Release(); @@ -260,15 +288,27 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) { COM_TRY_BEGIN const CItem &item = _items[index]; - return CreateLimitedInStream(_stream, _startPos + item.Offset, item.Size, stream); + return CreateLimitedInStream(_stream, /* _startPos + */ item.Offset, item.Size, stream); COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn + +namespace NBe { static CArcInfo g_ArcInfo = - { L"Mub", L"", 0, 0xE2, { 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0 }, 7, false, CreateArc, 0 }; + { "Mub", "mub", 0, 0xE2, + 2 + 7 + 4, + { + 7, 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0, + 4, 0xB9, 0xFA, 0xF1, 0x0E + }, + 0, + NArcInfoFlags::kMultiSignature, + CreateArc }; REGISTER_ARC(Mub) +} + }} diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.cpp b/CPP/7zip/Archive/Nsis/NsisDecode.cpp index 0845f965..bb73d273 100755..100644 --- a/CPP/7zip/Archive/Nsis/NsisDecode.cpp +++ b/CPP/7zip/Archive/Nsis/NsisDecode.cpp @@ -2,66 +2,65 @@ #include "StdAfx.h" -#include "NsisDecode.h" +#include "../../../../C/CpuArch.h" -#include "../../Common/StreamUtils.h" +#include "NsisDecode.h" +#include "../../Common/CreateCoder.h" +#include "../../Common/FilterCoder.h" +#include "../../Common/LimitedStreams.h" #include "../../Common/MethodId.h" +#include "../../Compress/BcjCoder.h" #include "../../Compress/BZip2Decoder.h" #include "../../Compress/DeflateDecoder.h" -#include "../../Compress/LzmaDecoder.h" + +#define Get32(p) GetUi32(p) namespace NArchive { namespace NNsis { -static const CMethodId k_BCJ_X86 = 0x03030103; - -HRESULT CDecoder::Init( - DECL_EXTERNAL_CODECS_LOC_VARS - IInStream *inStream, NMethodType::EEnum method, bool thereIsFilterFlag, bool &useFilter) +HRESULT CDecoder::Init(ISequentialInStream *inStream, bool &useFilter) { useFilter = false; - CObjectVector< CMyComPtr<ISequentialInStream> > inStreams; if (_decoderInStream) - if (method != _method) + if (Method != _curMethod) Release(); - _method = method; + _curMethod = Method; if (!_codecInStream) { - switch (method) + switch (Method) { // case NMethodType::kCopy: return E_NOTIMPL; case NMethodType::kDeflate: _codecInStream = new NCompress::NDeflate::NDecoder::CNsisCOMCoder(); break; case NMethodType::kBZip2: _codecInStream = new NCompress::NBZip2::CNsisDecoder(); break; - case NMethodType::kLZMA: _codecInStream = new NCompress::NLzma::CDecoder(); break; + case NMethodType::kLZMA: + _lzmaDecoder = new NCompress::NLzma::CDecoder(); + _codecInStream = _lzmaDecoder; + break; default: return E_NOTIMPL; } } - if (thereIsFilterFlag) + if (FilterFlag) { - UInt32 processedSize; - BYTE flag; - RINOK(inStream->Read(&flag, 1, &processedSize)); - if (processedSize != 1) - return E_FAIL; + Byte flag; + RINOK(ReadStream_FALSE(inStream, &flag, 1)); if (flag > 1) return E_NOTIMPL; useFilter = (flag != 0); } - if (useFilter) + if (!useFilter) + _decoderInStream = _codecInStream; + else { if (!_filterInStream) { - CMyComPtr<ICompressCoder> coder; - RINOK(CreateCoder( - EXTERNAL_CODECS_LOC_VARS - k_BCJ_X86, coder, false)); - if (!coder) - return E_NOTIMPL; + CFilterCoder *coderSpec = new CFilterCoder; + CMyComPtr<ICompressCoder> coder = coderSpec; + coderSpec->Filter = new CBCJ_x86_Decoder(); coder.QueryInterface(IID_ISequentialInStream, &_filterInStream); if (!_filterInStream) return E_NOTIMPL; @@ -73,23 +72,13 @@ HRESULT CDecoder::Init( RINOK(setInStream->SetInStream(_codecInStream)); _decoderInStream = _filterInStream; } - else - _decoderInStream = _codecInStream; - if (method == NMethodType::kLZMA) + if (Method == NMethodType::kLZMA) { - CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties; - _codecInStream.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); - if (setDecoderProperties) - { - static const UInt32 kPropertiesSize = 5; - BYTE properties[kPropertiesSize]; - UInt32 processedSize; - RINOK(inStream->Read(properties, kPropertiesSize, &processedSize)); - if (processedSize != kPropertiesSize) - return E_FAIL; - RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)properties, kPropertiesSize)); - } + const unsigned kPropsSize = LZMA_PROPS_SIZE; + Byte props[kPropsSize]; + RINOK(ReadStream_FALSE(inStream, props, kPropsSize)); + RINOK(_lzmaDecoder->SetDecoderProperties2((const Byte *)props, kPropsSize)); } { @@ -122,9 +111,155 @@ HRESULT CDecoder::Init( return S_OK; } -HRESULT CDecoder::Read(void *data, size_t *processedSize) +static const UInt32 kMask_IsCompressed = (UInt32)1 << 31; + +HRESULT CDecoder::SetToPos(UInt64 pos, ICompressProgressInfo *progress) { - return ReadStream(_decoderInStream, data, processedSize);; + if (StreamPos > pos) + return E_FAIL; + UInt64 inSizeStart = 0; + if (_lzmaDecoder) + inSizeStart = _lzmaDecoder->GetInputProcessedSize(); + UInt64 offset = 0; + while (StreamPos < pos) + { + size_t size = (size_t)MyMin(pos - StreamPos, (UInt64)Buffer.Size()); + RINOK(Read(Buffer, &size)); + if (size == 0) + return S_FALSE; + StreamPos += size; + offset += size; + + UInt64 inSize = 0; + if (_lzmaDecoder) + inSize = _lzmaDecoder->GetInputProcessedSize() - inSizeStart; + RINOK(progress->SetRatioInfo(&inSize, &offset)); + } + return S_OK; +} + +HRESULT CDecoder::Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize, + ISequentialOutStream *realOutStream, ICompressProgressInfo *progress, + UInt32 &packSizeRes, UInt32 &unpackSizeRes) +{ + CLimitedSequentialInStream *limitedStreamSpec = NULL; + CMyComPtr<ISequentialInStream> limitedStream; + packSizeRes = 0; + unpackSizeRes = 0; + + if (Solid) + { + Byte temp[4]; + size_t processedSize = 4; + RINOK(Read(temp, &processedSize)); + if (processedSize != 4) + return S_FALSE; + StreamPos += processedSize; + UInt32 size = Get32(temp); + if (unpackSizeDefined && size != unpackSize) + return S_FALSE; + unpackSize = size; + unpackSizeDefined = true; + } + else + { + Byte temp[4]; + RINOK(ReadStream_FALSE(InputStream, temp, 4)); + StreamPos += 4; + UInt32 size = Get32(temp); + + if ((size & kMask_IsCompressed) == 0) + { + if (unpackSizeDefined && size != unpackSize) + return S_FALSE; + packSizeRes = size; + if (outBuf) + outBuf->Alloc(size); + + UInt64 offset = 0; + + while (size > 0) + { + UInt32 curSize = (UInt32)MyMin((size_t)size, Buffer.Size()); + UInt32 processedSize; + RINOK(InputStream->Read(Buffer, curSize, &processedSize)); + if (processedSize == 0) + return S_FALSE; + if (outBuf) + memcpy((Byte *)*outBuf + (size_t)offset, Buffer, processedSize); + offset += processedSize; + size -= processedSize; + StreamPos += processedSize; + unpackSizeRes += processedSize; + if (realOutStream) + RINOK(WriteStream(realOutStream, Buffer, processedSize)); + RINOK(progress->SetRatioInfo(&offset, &offset)); + } + + return S_OK; + } + + size &= ~kMask_IsCompressed; + packSizeRes = size; + limitedStreamSpec = new CLimitedSequentialInStream; + limitedStream = limitedStreamSpec; + limitedStreamSpec->SetStream(InputStream); + limitedStreamSpec->Init(size); + { + bool useFilter; + RINOK(Init(limitedStream, useFilter)); + } + } + + if (outBuf) + { + if (!unpackSizeDefined) + return S_FALSE; + outBuf->Alloc(unpackSize); + } + + UInt64 inSizeStart = 0; + if (_lzmaDecoder) + inSizeStart = _lzmaDecoder->GetInputProcessedSize(); + + // we don't allow files larger than 4 GB; + if (!unpackSizeDefined) + unpackSize = 0xFFFFFFFF; + UInt32 offset = 0; + + for (;;) + { + size_t rem = unpackSize - offset; + if (rem == 0) + break; + size_t size = Buffer.Size(); + if (size > rem) + size = rem; + RINOK(Read(Buffer, &size)); + if (size == 0) + { + if (unpackSizeDefined) + return S_FALSE; + break; + } + if (outBuf) + memcpy((Byte *)*outBuf + (size_t)offset, Buffer, size); + StreamPos += size; + offset += (UInt32)size; + + UInt64 inSize = 0; // it can be improved: we need inSize for Deflate and BZip2 too. + if (_lzmaDecoder) + inSize = _lzmaDecoder->GetInputProcessedSize() - inSizeStart; + if (Solid) + packSizeRes = (UInt32)inSize; + unpackSizeRes += (UInt32)size; + + UInt64 outSize = offset; + RINOK(progress->SetRatioInfo(&inSize, &outSize)); + if (realOutStream) + RINOK(WriteStream(realOutStream, Buffer, size)); + } + return S_OK; } }} diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.h b/CPP/7zip/Archive/Nsis/NsisDecode.h index 36aeb2b1..2ccaaf65 100755..100644 --- a/CPP/7zip/Archive/Nsis/NsisDecode.h +++ b/CPP/7zip/Archive/Nsis/NsisDecode.h @@ -3,9 +3,11 @@ #ifndef __NSIS_DECODE_H #define __NSIS_DECODE_H -#include "../../IStream.h" +#include "../../../Common/MyBuffer.h" -#include "../../Common/CreateCoder.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/LzmaDecoder.h" namespace NArchive { namespace NNsis { @@ -21,25 +23,50 @@ namespace NMethodType }; } +/* 7-Zip installers 4.38 - 9.08 used modified version of NSIS that + supported BCJ filter for better compression ratio. + We support such modified NSIS archives. */ + class CDecoder { - NMethodType::EEnum _method; + NMethodType::EEnum _curMethod; // method of created decoder CMyComPtr<ISequentialInStream> _filterInStream; CMyComPtr<ISequentialInStream> _codecInStream; CMyComPtr<ISequentialInStream> _decoderInStream; + NCompress::NLzma::CDecoder *_lzmaDecoder; + public: + CMyComPtr<IInStream> InputStream; // for non-solid + UInt64 StreamPos; // the pos in unpacked for solid, the pos in Packed for non-solid + + NMethodType::EEnum Method; + bool FilterFlag; + bool Solid; + + CByteBuffer Buffer; // temp buf. + void Release() { _filterInStream.Release(); _codecInStream.Release(); _decoderInStream.Release(); + InputStream.Release(); + _lzmaDecoder = NULL; } - HRESULT Init( - DECL_EXTERNAL_CODECS_LOC_VARS - IInStream *inStream, NMethodType::EEnum method, bool thereIsFilterFlag, bool &useFilter); - HRESULT Read(void *data, size_t *processedSize); + + HRESULT Init(ISequentialInStream *inStream, bool &useFilter); + HRESULT Read(void *data, size_t *processedSize) + { + return ReadStream(_decoderInStream, data, processedSize);; + } + + + HRESULT CDecoder::SetToPos(UInt64 pos, ICompressProgressInfo *progress); // for solid + HRESULT Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize, + ISequentialOutStream *realOutStream, ICompressProgressInfo *progress, + UInt32 &packSizeRes, UInt32 &unpackSizeRes); }; }} diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.cpp b/CPP/7zip/Archive/Nsis/NsisHandler.cpp index 4058bd2a..868ca6cb 100755..100644 --- a/CPP/7zip/Archive/Nsis/NsisHandler.cpp +++ b/CPP/7zip/Archive/Nsis/NsisHandler.cpp @@ -4,11 +4,12 @@ #include "../../../../C/CpuArch.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" -#include "Windows/PropVariant.h" +#include "../../../Windows/PropVariant.h" +#include "../../Common/ProgressUtils.h" #include "../../Common/StreamUtils.h" #include "../Common/ItemNameUtils.h" @@ -27,54 +28,160 @@ static const char *kUnknownMethod = "Unknown"; static const char *kMethods[] = { - "Copy", - "Deflate", - "BZip2", - "LZMA" + "Copy" + , "Deflate" + , "BZip2" + , "LZMA" }; -static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]); - -static STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidSolid, VT_BOOL} + kpidPath, + kpidSize, + kpidPackSize, + kpidMTime, + kpidAttrib, + kpidMethod, + kpidSolid, + kpidOffset }; -static STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidSolid, VT_BOOL} + kpidMethod, + kpidSolid, + kpidHeadersSize, + kpidEmbeddedStubSize, + kpidSubType + // kpidCodePage }; IMP_IInArchive_Props IMP_IInArchive_ArcProps + +static AString UInt32ToString(UInt32 val) +{ + char s[16]; + ConvertUInt32ToString(val, s); + return s; +} + +static AString GetStringForSizeValue(UInt32 val) +{ + for (int i = 31; i >= 0; i--) + if (((UInt32)1 << i) == val) + return UInt32ToString(i); + char c = 'b'; + if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } + else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } + return UInt32ToString(val) + c; +} + +static AString GetMethod(bool useFilter, NMethodType::EEnum method, UInt32 dict) +{ + AString s; + if (useFilter) + { + s += kBcjMethod; + s += ' '; + } + s += (method < ARRAY_SIZE(kMethods)) ? kMethods[method] : kUnknownMethod; + if (method == NMethodType::kLZMA) + { + s += ':'; + s += GetStringForSizeValue(dict); + } + return s; +} + +/* +AString CHandler::GetMethod(NMethodType::EEnum method, bool useItemFilter, UInt32 dictionary) const +{ + AString s; + if (_archive.IsSolid && _archive.UseFilter || !_archive.IsSolid && useItemFilter) + { + s += kBcjMethod; + s += ' '; + } + s += (method < ARRAY_SIZE(kMethods)) ? kMethods[method] : kUnknownMethod; + if (method == NMethodType::kLZMA) + { + s += ':'; + s += GetStringForSizeValue(_archive.IsSolid ? _archive.DictionarySize: dictionary); + } + return s; +} +*/ + STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) + NCOM::CPropVariant prop; + switch (propID) { - case kpidMethod: + // case kpidCodePage: if (_archive.IsUnicode) prop = "UTF-16"; break; + case kpidSubType: { - UInt32 dict = 1; - bool filter = false; - for (int i = 0; i < _archive.Items.Size(); i++) + AString s = _archive.GetFormatDescription(); + if (!_archive.IsInstaller) { - const CItem &item = _archive.Items[i]; - filter |= item.UseFilter; - if (item.DictionarySize > dict) - dict = item.DictionarySize; + if (!s.IsEmpty()) + s += ' '; + s += "(Uninstall)"; } - prop = GetMethod(filter, dict); + if (!s.IsEmpty()) + prop = s; break; } + + case kpidMethod: prop = _methodString; break; case kpidSolid: prop = _archive.IsSolid; break; + case kpidOffset: prop = _archive.StartOffset; break; + case kpidPhySize: prop = _archive.ExeStub.Size() + _archive.FirstHeader.ArcSize; break; + case kpidEmbeddedStubSize: prop = _archive.ExeStub.Size(); break; + case kpidHeadersSize: prop = _archive.FirstHeader.HeaderSize; break; + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; + if (_archive.IsTruncated()) v |= kpv_ErrorFlags_UnexpectedEnd; + prop = v; + break; + } + + case kpidName: + { + AString s; + + #ifdef NSIS_SCRIPT + if (!_archive.Name.IsEmpty()) + s = _archive.Name; + if (!_archive.IsInstaller) + { + if (!s.IsEmpty()) + s += '.'; + s += "Uninstall"; + } + #endif + + if (s.IsEmpty()) + s = _archive.IsInstaller ? "Install" : "Uninstall"; + s += (_archive.ExeStub.Size() == 0) ? ".nsis" : ".exe"; + + prop = _archive.ConvertToUnicode(s); + break; + } + + #ifdef NSIS_SCRIPT + case kpidShortComment: + { + if (!_archive.BrandingText.IsEmpty()) + prop = _archive.ConvertToUnicode(_archive.BrandingText); + break; + } + #endif } prop.Detach(value); return S_OK; @@ -82,16 +189,26 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } -STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * maxCheckStartPosition, IArchiveOpenCallback * /* openArchiveCallback */) +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback * /* openArchiveCallback */) { COM_TRY_BEGIN Close(); { - if (_archive.Open( - EXTERNAL_CODECS_VARS - stream, maxCheckStartPosition) != S_OK) + if (_archive.Open(stream, maxCheckStartPosition) != S_OK) return S_FALSE; - _inStream = stream; + { + UInt32 dict = _archive.DictionarySize; + if (!_archive.IsSolid) + { + FOR_VECTOR (i, _archive.Items) + { + const CItem &item = _archive.Items[i]; + if (item.DictionarySize > dict) + dict = item.DictionarySize; + } + } + _methodString = GetMethod(_archive.UseFilter, _archive.Method, dict); + } } return S_OK; COM_TRY_END @@ -101,7 +218,6 @@ STDMETHODIMP CHandler::Close() { _archive.Clear(); _archive.Release(); - _inStream.Release(); return S_OK; } @@ -109,74 +225,30 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { *numItems = _archive.Items.Size() #ifdef NSIS_SCRIPT - + 1 + + 1 + _archive.LicenseFiles.Size(); #endif ; return S_OK; } -static AString UInt32ToString(UInt32 value) -{ - char buffer[16]; - ConvertUInt32ToString(value, buffer); - return buffer; -} - -static AString GetStringForSizeValue(UInt32 value) -{ - for (int i = 31; i >= 0; i--) - if (((UInt32)1 << i) == value) - return UInt32ToString(i); - char c = 'b'; - if (value % (1 << 20) == 0) - { - value >>= 20; - c = 'm'; - } - else if (value % (1 << 10) == 0) - { - value >>= 10; - c = 'k'; - } - return UInt32ToString(value) + c; -} - -AString CHandler::GetMethod(bool useItemFilter, UInt32 dictionary) const -{ - NMethodType::EEnum methodIndex = _archive.Method; - AString method; - if (_archive.IsSolid && _archive.UseFilter || !_archive.IsSolid && useItemFilter) - { - method += kBcjMethod; - method += ' '; - } - method += (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod; - if (methodIndex == NMethodType::kLZMA) - { - method += ':'; - method += GetStringForSizeValue(_archive.IsSolid ? _archive.DictionarySize: dictionary); - } - return method; -} - -bool CHandler::GetUncompressedSize(int index, UInt32 &size) +bool CHandler::GetUncompressedSize(unsigned index, UInt32 &size) const { size = 0; const CItem &item = _archive.Items[index]; - if (item.SizeIsDefined) - size = item.Size; - else if (_archive.IsSolid && item.EstimatedSizeIsDefined) - size = item.EstimatedSize; + if (item.Size_Defined) + size = item.Size; + else if (_archive.IsSolid && item.EstimatedSize_Defined) + size = item.EstimatedSize; else return false; return true; } -bool CHandler::GetCompressedSize(int index, UInt32 &size) +bool CHandler::GetCompressedSize(unsigned index, UInt32 &size) const { size = 0; const CItem &item = _archive.Items[index]; - if (item.CompressedSizeIsDefined) + if (item.CompressedSize_Defined) size = item.CompressedSize; else { @@ -202,27 +274,42 @@ bool CHandler::GetCompressedSize(int index, UInt32 &size) STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; #ifdef NSIS_SCRIPT if (index >= (UInt32)_archive.Items.Size()) { - switch(propID) + if (index == (UInt32)_archive.Items.Size()) { - case kpidPath: prop = L"[NSIS].nsi"; break; - case kpidSize: - case kpidPackSize: prop = (UInt64)_archive.Script.Length(); break; - case kpidSolid: prop = false; break; + switch (propID) + { + case kpidPath: prop = "[NSIS].nsi"; break; + case kpidSize: + case kpidPackSize: prop = (UInt64)_archive.Script.Len(); break; + case kpidSolid: prop = false; break; + } + } + else + { + const CLicenseFile &lic = _archive.LicenseFiles[index - (_archive.Items.Size() + 1)]; + switch (propID) + { + case kpidPath: prop = lic.Name; break; + case kpidSize: + case kpidPackSize: prop = (UInt64)lic.Size; break; + case kpidSolid: prop = false; break; + } } } else #endif { const CItem &item = _archive.Items[index]; - switch(propID) + switch (propID) { + case kpidOffset: prop = item.Pos; break; case kpidPath: { - UString s = NItemName::WinNameToOSName(item.GetReducedName(_archive.IsUnicode)); + UString s = NItemName::WinNameToOSName(_archive.GetReducedName(index)); if (!s.IsEmpty()) prop = (const wchar_t *)s; break; @@ -248,7 +335,21 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = item.MTime; break; } - case kpidMethod: prop = GetMethod(item.UseFilter, item.DictionarySize); break; + case kpidAttrib: + { + if (item.Attrib_Defined) + prop = item.Attrib; + break; + } + + case kpidMethod: + if (_archive.IsSolid) + prop = _methodString; + else + prop = GetMethod(_archive.UseFilter, item.IsCompressed ? _archive.Method : + NMethodType::kCopy, item.DictionarySize); + break; + case kpidSolid: prop = _archive.IsSolid; break; } } @@ -257,24 +358,56 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_END } + +static bool UninstallerPatch(const Byte *p, size_t size, CByteBuffer &dest) +{ + for (;;) + { + if (size < 4) + return false; + UInt32 len = Get32(p); + if (len == 0) + return size == 4; + if (size < 8) + return false; + UInt32 offs = Get32(p + 4); + p += 8; + size -= 8; + if (size < len || offs > dest.Size() || len > dest.Size() - offs) + return false; + memcpy(dest + offs, p, len); + p += len; + size -= len; + } +} + + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) GetNumberOfItems(&numItems); if (numItems == 0) return S_OK; + UInt64 totalSize = 0; + UInt64 solidPosMax = 0; UInt32 i; for (i = 0; i < numItems; i++) { UInt32 index = (allFilesMode ? i : indices[i]); + #ifdef NSIS_SCRIPT - if (index >= (UInt32)_archive.Items.Size()) - totalSize += _archive.Script.Length(); + if (index >= _archive.Items.Size()) + { + if (index == _archive.Items.Size()) + totalSize += _archive.Script.Len(); + else + totalSize += _archive.LicenseFiles[index - (_archive.Items.Size() + 1)].Size; + } else #endif { @@ -282,9 +415,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (_archive.IsSolid) { GetUncompressedSize(index, size); - UInt64 pos = _archive.GetPosOfSolidItem(index); - if (pos > totalSize) - totalSize = pos + size; + UInt64 pos = (UInt64)_archive.GetPosOfSolidItem(index) + size; + if (solidPosMax < pos) + solidPosMax = pos; } else { @@ -293,33 +426,58 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } } } - extractCallback->SetTotal(totalSize); - UInt64 currentTotalSize = 0; - UInt32 currentItemSize = 0; + extractCallback->SetTotal(totalSize + solidPosMax); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, !_archive.IsSolid); - UInt64 streamPos = 0; if (_archive.IsSolid) { - RINOK(_inStream->Seek(_archive.StreamOffset, STREAM_SEEK_SET, NULL)); - bool useFilter; - RINOK(_archive.Decoder.Init( - EXTERNAL_CODECS_VARS - _inStream, _archive.Method, _archive.FilterFlag, useFilter)); + RINOK(_archive.SeekTo_DataStreamOffset()); + RINOK(_archive.InitDecoder()); + _archive.Decoder.StreamPos = 0; } - CByteBuffer byteBuf; - const UInt32 kBufferLength = 1 << 16; - byteBuf.SetCapacity(kBufferLength); - Byte *buffer = byteBuf; + /* We use tempBuf for solid archives, if there is duplicate item. + We don't know uncompressed size for non-solid archives, so we can't + allocate exact buffer. + We use tempBuf also for first part (EXE stub) of unistall.exe + and tempBuf2 is used for second part (NSIS script). */ CByteBuffer tempBuf; - - bool dataError = false; - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + CByteBuffer tempBuf2; + + /* tempPos is pos in uncompressed stream of previous item for solid archive, that + was written to tempBuf */ + UInt64 tempPos = (UInt64)(Int64)-1; + + /* prevPos is pos in uncompressed stream of previous item for solid archive. + It's used for test mode (where we don't need to test same file second time */ + UInt64 prevPos = (UInt64)(Int64)-1; + + // if there is error in solid archive, we show error for all subsequent files + bool solidDataError = false; + + UInt64 curTotalPacked = 0, curTotalUnpacked = 0; + UInt32 curPacked = 0; + UInt64 curUnpacked = 0; + + for (i = 0; i < numItems; i++, + curTotalPacked += curPacked, + curTotalUnpacked += curUnpacked) { - currentItemSize = 0; - RINOK(extractCallback->SetCompleted(¤tTotalSize)); + lps->InSize = curTotalPacked; + lps->OutSize = curTotalUnpacked; + if (_archive.IsSolid) + lps->OutSize += _archive.Decoder.StreamPos; + + curPacked = 0; + curUnpacked = 0; + RINOK(lps->SetCur()); + + // RINOK(extractCallback->SetCompleted(¤tTotalSize)); CMyComPtr<ISequentialOutStream> realOutStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : @@ -328,169 +486,184 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + bool dataError = false; + #ifdef NSIS_SCRIPT if (index >= (UInt32)_archive.Items.Size()) { - currentItemSize = _archive.Script.Length(); + const void *data; + size_t size; + if (index == (UInt32)_archive.Items.Size()) + { + data = (const Byte *)_archive.Script; + size = _archive.Script.Len(); + } + else + { + CLicenseFile &lic = _archive.LicenseFiles[index - (_archive.Items.Size() + 1)]; + if (lic.Text.Size() != 0) + data = lic.Text; + else + data = _archive._data + lic.Offset; + size = lic.Size; + } + curUnpacked = size; if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); - if (!testMode) - RINOK(WriteStream(realOutStream, (const char *)_archive.Script, (UInt32)_archive.Script.Length())); + if (realOutStream) + RINOK(WriteStream(realOutStream, data, size)); } else #endif { const CItem &item = _archive.Items[index]; - if (_archive.IsSolid) - GetUncompressedSize(index, currentItemSize); - else - GetCompressedSize(index, currentItemSize); + if (!_archive.IsSolid) + GetCompressedSize(index, curPacked); if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); - if (!dataError) + dataError = solidDataError; + + bool needDecompress = !solidDataError; + if (needDecompress) { - bool needDecompress = false; - bool sizeIsKnown = false; - UInt32 fullSize = 0; + if (testMode && _archive.IsSolid && _archive.GetPosOfSolidItem(index) == prevPos) + needDecompress = false; + } + if (needDecompress) + { bool writeToTemp = false; bool readFromTemp = false; - if (_archive.IsSolid) + if (!_archive.IsSolid) + { + RINOK(_archive.SeekToNonSolidItem(index)); + } + else { UInt64 pos = _archive.GetPosOfSolidItem(index); - while (streamPos < pos) + if (pos < _archive.Decoder.StreamPos) + { + if (pos != tempPos) + solidDataError = dataError = true; + readFromTemp = true; + } + else { - size_t processedSize = (UInt32)MyMin(pos - streamPos, (UInt64)kBufferLength); - HRESULT res = _archive.Decoder.Read(buffer, &processedSize); + HRESULT res = _archive.Decoder.SetToPos(pos, progress); if (res != S_OK) { if (res != S_FALSE) return res; - dataError = true; - break; + solidDataError = dataError = true; } - if (processedSize == 0) + else if (!testMode && i + 1 < numItems) { - dataError = true; - break; + UInt32 next = allFilesMode ? i + 1 : indices[i + 1]; + if (next < _archive.Items.Size()) + { + UInt64 nextPos = _archive.GetPosOfSolidItem(next); + if (nextPos == pos) + { + writeToTemp = true; + tempPos = pos; + } + } } - streamPos += processedSize; } - if (streamPos == pos) + prevPos = pos; + } + + if (!dataError) + { + UInt32 unpackSize = 0; + bool unpackSize_Defined = false; + bool writeToTemp1 = writeToTemp; + if (item.IsUninstaller) { - Byte buffer2[4]; - size_t processedSize = 4; - RINOK(_archive.Decoder.Read(buffer2, &processedSize)); - if (processedSize != 4) - return E_FAIL; - streamPos += processedSize; - fullSize = Get32(buffer2); - sizeIsKnown = true; - needDecompress = true; - - if (!testMode && i + 1 < numItems) + unpackSize = item.PatchSize; + unpackSize_Defined = true; + if (!readFromTemp) + writeToTemp = true; + writeToTemp1 = writeToTemp; + if (_archive.ExeStub.Size() == 0) { - UInt64 nextPos = _archive.GetPosOfSolidItem(allFilesMode ? i : indices[i + 1]); - if (nextPos < streamPos + fullSize) - { + if (writeToTemp1 && !readFromTemp) tempBuf.Free(); - tempBuf.SetCapacity(fullSize); - writeToTemp = true; - } + writeToTemp1 = false; } } - else - readFromTemp = true; - } - else - { - RINOK(_inStream->Seek(_archive.GetPosOfNonSolidItem(index) + 4, STREAM_SEEK_SET, NULL)); - if (item.IsCompressed) + + if (readFromTemp) { - needDecompress = true; - bool useFilter; - RINOK(_archive.Decoder.Init( - EXTERNAL_CODECS_VARS - _inStream, _archive.Method, _archive.FilterFlag, useFilter)); - // fullSize = Get32(buffer); // It's bug !!! - // Test it: what is exact fullSize? - fullSize = 0xFFFFFFFF; + if (realOutStream && !item.IsUninstaller) + RINOK(WriteStream(realOutStream, tempBuf, tempBuf.Size())); } else - fullSize = item.Size; - } - if (!dataError) - { - if (needDecompress) { - UInt64 offset = 0; - while (!sizeIsKnown || fullSize > 0) + UInt32 curUnpacked32 = 0; + HRESULT res = _archive.Decoder.Decode( + writeToTemp1 ? &tempBuf : NULL, + item.IsUninstaller, item.PatchSize, + item.IsUninstaller ? NULL : realOutStream, + progress, + curPacked, curUnpacked32); + curUnpacked = curUnpacked32; + if (_archive.IsSolid) + curUnpacked = 0; + if (res != S_OK) { - UInt32 curSize = kBufferLength; - if (sizeIsKnown && curSize > fullSize) - curSize = fullSize; - size_t processedSize = curSize; - HRESULT res = _archive.Decoder.Read(buffer, &processedSize); - if (res != S_OK) - { - if (res != S_FALSE) - return res; - dataError = true; - break; - } - if (processedSize == 0) - { - if (sizeIsKnown) - dataError = true; - break; - } - - if (writeToTemp) - memcpy((Byte *)tempBuf + (size_t)offset, buffer, processedSize); - - fullSize -= (UInt32)processedSize; - streamPos += processedSize; - offset += processedSize; - - UInt64 completed; + if (res != S_FALSE) + return res; + dataError = true; if (_archive.IsSolid) - completed = currentTotalSize + offset; - else - completed = streamPos; - RINOK(extractCallback->SetCompleted(&completed)); - if (!testMode) - RINOK(WriteStream(realOutStream, buffer, processedSize)); + solidDataError = true; } } + } + + if (!dataError && item.IsUninstaller) + { + if (_archive.ExeStub.Size() != 0) + { + CByteBuffer destBuf = _archive.ExeStub; + dataError = !UninstallerPatch(tempBuf, tempBuf.Size(), destBuf); + + if (realOutStream) + RINOK(WriteStream(realOutStream, destBuf, destBuf.Size())); + } + + if (readFromTemp) + { + if (realOutStream) + RINOK(WriteStream(realOutStream, tempBuf2, tempBuf2.Size())); + } else { - if (readFromTemp) - { - if (!testMode) - RINOK(WriteStream(realOutStream, tempBuf, tempBuf.GetCapacity())); - } - else - while (fullSize > 0) + UInt32 curPacked2 = 0; + UInt32 curUnpacked2 = 0; + HRESULT res = _archive.Decoder.Decode( + writeToTemp ? &tempBuf2 : NULL, + false, 0, + realOutStream, + progress, + curPacked2, curUnpacked2); + curPacked += curPacked2; + if (!_archive.IsSolid) + curUnpacked += curUnpacked2; + if (res != S_OK) { - UInt32 curSize = MyMin(fullSize, kBufferLength); - UInt32 processedSize; - RINOK(_inStream->Read(buffer, curSize, &processedSize)); - if (processedSize == 0) - { - dataError = true; - break; - } - fullSize -= processedSize; - streamPos += processedSize; - if (!testMode) - RINOK(WriteStream(realOutStream, buffer, processedSize)); + if (res != S_FALSE) + return res; + dataError = true; + if (_archive.IsSolid) + solidDataError = true; } } } @@ -505,6 +678,4 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -IMPL_ISetCompressCodecsInfo - }} diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.h b/CPP/7zip/Archive/Nsis/NsisHandler.h index 6de493df..1eb8b731 100755..100644 --- a/CPP/7zip/Archive/Nsis/NsisHandler.h +++ b/CPP/7zip/Archive/Nsis/NsisHandler.h @@ -3,39 +3,32 @@ #ifndef __NSIS_HANDLER_H #define __NSIS_HANDLER_H -#include "Common/MyCom.h" +#include "../../../Common/MyCom.h" + +#include "../../Common/CreateCoder.h" + #include "../IArchive.h" #include "NsisIn.h" -#include "../../Common/CreateCoder.h" - namespace NArchive { namespace NNsis { class CHandler: public IInArchive, - PUBLIC_ISetCompressCodecsInfo public CMyUnknownImp { - CMyComPtr<IInStream> _inStream; CInArchive _archive; + AString _methodString; - DECL_EXTERNAL_CODECS_VARS - - bool GetUncompressedSize(int index, UInt32 &size); - bool GetCompressedSize(int index, UInt32 &size); + bool GetUncompressedSize(unsigned index, UInt32 &size) const; + bool GetCompressedSize(unsigned index, UInt32 &size) const; - AString GetMethod(bool useItemFilter, UInt32 dictionary) const; + // AString GetMethod(NMethodType::EEnum method, bool useItemFilter, UInt32 dictionary) const; public: - MY_QUERYINTERFACE_BEGIN2(IInArchive) - QUERY_ENTRY_ISetCompressCodecsInfo - MY_QUERYINTERFACE_END - MY_ADDREF_RELEASE + MY_UNKNOWN_IMP1(IInArchive) INTERFACE_IInArchive(;) - - DECL_ISetCompressCodecsInfo }; }} diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp index 40756008..71791c03 100755..100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.cpp +++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp @@ -2,1271 +2,5540 @@ #include "StdAfx.h" -#include "../../../../C/CpuArch.h" - -#include "Common/IntToString.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringToInt.h" +#include "../../Common/LimitedStreams.h" #include "../../Common/StreamUtils.h" #include "NsisIn.h" +#define Get16(p) GetUi16(p) #define Get32(p) GetUi32(p) +// #define NUM_SPEED_TESTS 1000 + namespace NArchive { namespace NNsis { -Byte kSignature[kSignatureSize] = NSIS_SIGNATURE; +static const size_t kInputBufSize = 1 << 20; + +static const Byte kSignature[kSignatureSize] = NSIS_SIGNATURE; +static const UInt32 kMask_IsCompressed = (UInt32)1 << 31; + +static const unsigned kNumCommandParams = 6; +static const unsigned kCmdSize = 4 + kNumCommandParams * 4; #ifdef NSIS_SCRIPT -static const char *kCrLf = "\x0D\x0A"; +#define CR_LF "\x0D\x0A" #endif -#define NS_UN_SKIP_CODE 0xE000 -#define NS_UN_VAR_CODE 0xE001 -#define NS_UN_SHELL_CODE 0xE002 -#define NS_UN_LANG_CODE 0xE003 -#define NS_UN_CODES_START NS_UN_SKIP_CODE -#define NS_UN_CODES_END NS_UN_LANG_CODE +static const char *kErrorStr = "$_ERROR_STR_"; + +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + + +/* There are several versions of NSIS: + 1) Original NSIS: + NSIS-2 ANSI + NSIS-3 ANSI + NSIS-3 Unicode + 2) NSIS from Jim Park that extends old NSIS-2 to Unicode support: + NSIS-Park-(1,2,3) ANSI + NSIS-Park-(1,2,3) Unicode -Byte CInArchive::ReadByte() + The command IDs layout is slightly different for different versions. + Also there are additional "log" versions of NSIS that support EW_LOG. + We use the layout of "NSIS-3 Unicode" without "log" as main layout. + And we transfer the command IDs to main layout, if another layout is detected. */ + + +enum { - if (_posInData >= _size) - throw 1; - return _data[_posInData++]; + EW_INVALID_OPCODE, + EW_RET, // Return + EW_NOP, // Nop, Goto + EW_ABORT, // Abort + EW_QUIT, // Quit + EW_CALL, // Call, InitPluginsDir + EW_UPDATETEXT, // DetailPrint + EW_SLEEP, // Sleep + EW_BRINGTOFRONT, // BringToFront + EW_CHDETAILSVIEW, // SetDetailsView + EW_SETFILEATTRIBUTES, // SetFileAttributes + EW_CREATEDIR, // CreateDirectory, SetOutPath + EW_IFFILEEXISTS, // IfFileExists + EW_SETFLAG, // SetRebootFlag, ... + EW_IFFLAG, // IfAbort, IfSilent, IfErrors, IfRebootFlag + EW_GETFLAG, // GetInstDirError, GetErrorLevel + EW_RENAME, // Rename + EW_GETFULLPATHNAME, // GetFullPathName + EW_SEARCHPATH, // SearchPath + EW_GETTEMPFILENAME, // GetTempFileName + EW_EXTRACTFILE, // File + EW_DELETEFILE, // Delete + EW_MESSAGEBOX, // MessageBox + EW_RMDIR, // RMDir + EW_STRLEN, // StrLen + EW_ASSIGNVAR, // StrCpy + EW_STRCMP, // StrCmp + EW_READENVSTR, // ReadEnvStr, ExpandEnvStrings + EW_INTCMP, // IntCmp, IntCmpU + EW_INTOP, // IntOp + EW_INTFMT, // IntFmt + EW_PUSHPOP, // Push/Pop/Exchange + EW_FINDWINDOW, // FindWindow + EW_SENDMESSAGE, // SendMessage + EW_ISWINDOW, // IsWindow + EW_GETDLGITEM, // GetDlgItem + EW_SETCTLCOLORS, // SerCtlColors + EW_SETBRANDINGIMAGE, // SetBrandingImage + EW_CREATEFONT, // CreateFont + EW_SHOWWINDOW, // ShowWindow, EnableWindow, HideWindow + EW_SHELLEXEC, // ExecShell + EW_EXECUTE, // Exec, ExecWait + EW_GETFILETIME, // GetFileTime + EW_GETDLLVERSION, // GetDLLVersion + + // EW_GETFONTVERSION, // Park : 2.46.2 + // EW_GETFONTNAME, // Park : 2.46.3 + + EW_REGISTERDLL, // RegDLL, UnRegDLL, CallInstDLL + EW_CREATESHORTCUT, // CreateShortCut + EW_COPYFILES, // CopyFiles + EW_REBOOT, // Reboot + EW_WRITEINI, // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI + EW_READINISTR, // ReadINIStr + EW_DELREG, // DeleteRegValue, DeleteRegKey + EW_WRITEREG, // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD + EW_READREGSTR, // ReadRegStr, ReadRegDWORD + EW_REGENUM, // EnumRegKey, EnumRegValue + EW_FCLOSE, // FileClose + EW_FOPEN, // FileOpen + EW_FPUTS, // FileWrite, FileWriteByte + EW_FGETS, // FileRead, FileReadByte + + // Park + // EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord + // EW_FGETWS, // FileReadUTF16LE, FileReadWord + + EW_FSEEK, // FileSeek + EW_FINDCLOSE, // FindClose + EW_FINDNEXT, // FindNext + EW_FINDFIRST, // FindFirst + EW_WRITEUNINSTALLER, // WriteUninstaller + + // Park : since 2.46.3 the log is enabled in main Park version + // EW_LOG, // LogSet, LogText + + EW_SECTIONSET, // Get*, Set* + EW_INSTTYPESET, // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType + + // instructions not actually implemented in exehead, but used in compiler. + EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR + EW_GETFUNCTIONADDR, + + EW_LOCKWINDOW, // LockWindow + + // 2 unicode commands available only in Unicode archive + EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord + EW_FGETWS, // FileReadUTF16LE, FileReadWord + + // The following IDs are not IDs in real order. + // We just need some IDs to translate eny extended layout to main layout. + + EW_LOG, // LogSet, LogText + + // Park + EW_FINDPROC, // FindProc + + EW_GETFONTVERSION, // GetFontVersion + EW_GETFONTNAME, // GetFontName + + kNumCmds +}; + +static const unsigned kNumAdditionalParkCmds = 3; + +struct CCommandInfo +{ + Byte NumParams; +}; + +static const CCommandInfo k_Commands[kNumCmds] = +{ + { 0 }, // "Invalid" }, + { 0 }, // Return + { 1 }, // Nop, Goto + { 1 }, // "Abort" }, + { 0 }, // "Quit" }, + { 2 }, // Call + { 6 }, // "DetailPrint" }, // 1 param in new versions, 6 in old NSIS versions + { 1 }, // "Sleep" }, + { 0 }, // "BringToFront" }, + { 2 }, // "SetDetailsView" }, + { 2 }, // "SetFileAttributes" }, + { 2 }, // CreateDirectory, SetOutPath + { 3 }, // "IfFileExists" }, + { 3 }, // SetRebootFlag, ... + { 4 }, // "If" }, // IfAbort, IfSilent, IfErrors, IfRebootFlag + { 2 }, // "Get" }, // GetInstDirError, GetErrorLevel + { 4 }, // "Rename" }, + { 3 }, // "GetFullPathName" }, + { 2 }, // "SearchPath" }, + { 2 }, // "GetTempFileName" }, + { 6 }, // "File" + { 2 }, // "Delete" }, + { 6 }, // "MessageBox" }, + { 2 }, // "RMDir" }, + { 2 }, // "StrLen" }, + { 4 }, // StrCpy, GetCurrentAddress + { 5 }, // "StrCmp" }, + { 3 }, // ReadEnvStr, ExpandEnvStrings + { 6 }, // "IntCmp" }, + { 4 }, // "IntOp" }, + { 3 }, // "IntFmt" }, + { 6 }, // Push, Pop, Exch // it must be 3 params. But some multi-command write garbage. + { 5 }, // "FindWindow" }, + { 6 }, // "SendMessage" }, + { 3 }, // "IsWindow" }, + { 3 }, // "GetDlgItem" }, + { 2 }, // "SetCtlColors" }, + { 3 }, // "SetBrandingImage" }, + { 5 }, // "CreateFont" }, + { 4 }, // ShowWindow, EnableWindow, HideWindow + { 6 }, // "ExecShell" }, + { 3 }, // "Exec" }, // Exec, ExecWait + { 3 }, // "GetFileTime" }, + { 3 }, // "GetDLLVersion" }, + { 6 }, // RegDLL, UnRegDLL, CallInstDLL // it must be 5 params. But some multi-command write garbage. + { 6 }, // "CreateShortCut" }, + { 4 }, // "CopyFiles" }, + { 1 }, // "Reboot" }, + { 5 }, // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI + { 4 }, // "ReadINIStr" }, + { 5 }, // "DeleteReg" }, // DeleteRegKey, DeleteRegValue + { 6 }, // "WriteReg" }, // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD + { 5 }, // "ReadReg" }, // ReadRegStr, ReadRegDWORD + { 5 }, // "EnumReg" }, // EnumRegKey, EnumRegValue + { 1 }, // "FileClose" }, + { 4 }, // "FileOpen" }, + { 3 }, // "FileWrite" }, // FileWrite, FileWriteByte + { 4 }, // "FileRead" }, // FileRead, FileReadByte + { 4 }, // "FileSeek" }, + { 1 }, // "FindClose" }, + { 2 }, // "FindNext" }, + { 3 }, // "FindFirst" }, + { 4 }, // "WriteUninstaller" }, + { 5 }, // "Section" }, // *** + { 4 }, // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType + { 6 }, // "GetLabelAddr" }, + { 2 }, // "GetFunctionAddress" }, + { 1 }, // "LockWindow" }, + { 3 }, // "FileWrite" }, // FileWriteUTF16LE, FileWriteWord + { 4 }, // "FileRead" }, // FileReadUTF16LE, FileReadWord + + { 2 }, // "Log" }, // LogSet, LogText + // Park + { 2 }, // "FindProc" }, + { 2 }, // "GetFontVersion" }, + { 2 }, // "GetFontName" } +}; + +#ifdef NSIS_SCRIPT + +static const char *k_CommandNames[kNumCmds] = +{ + "Invalid" + , NULL // Return + , NULL // Nop, Goto + , "Abort" + , "Quit" + , NULL // Call + , "DetailPrint" // 1 param in new versions, 6 in old NSIS versions + , "Sleep" + , "BringToFront" + , "SetDetailsView" + , "SetFileAttributes" + , NULL // CreateDirectory, SetOutPath + , "IfFileExists" + , NULL // SetRebootFlag, ... + , "If" // IfAbort, IfSilent, IfErrors, IfRebootFlag + , "Get" // GetInstDirError, GetErrorLevel + , "Rename" + , "GetFullPathName" + , "SearchPath" + , "GetTempFileName" + , NULL // File + , "Delete" + , "MessageBox" + , "RMDir" + , "StrLen" + , NULL // StrCpy, GetCurrentAddress + , "StrCmp" + , NULL // ReadEnvStr, ExpandEnvStrings + , "IntCmp" + , "IntOp" + , "IntFmt" + , NULL // Push, Pop, Exch // it must be 3 params. But some multi-command write garbage. + , "FindWindow" + , "SendMessage" + , "IsWindow" + , "GetDlgItem" + , "SetCtlColors" + , "SetBrandingImage" + , "CreateFont" + , NULL // ShowWindow, EnableWindow, HideWindow + , "ExecShell" + , "Exec" // Exec, ExecWait + , "GetFileTime" + , "GetDLLVersion" + , NULL // RegDLL, UnRegDLL, CallInstDLL // it must be 5 params. But some multi-command write garbage. + , "CreateShortCut" + , "CopyFiles" + , "Reboot" + , NULL // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI + , "ReadINIStr" + , "DeleteReg" // DeleteRegKey, DeleteRegValue + , "WriteReg" // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD + , "ReadReg" // ReadRegStr, ReadRegDWORD + , "EnumReg" // EnumRegKey, EnumRegValue + , "FileClose" + , "FileOpen" + , "FileWrite" // FileWrite, FileWriteByte + , "FileRead" // FileRead, FileReadByte + , "FileSeek" + , "FindClose" + , "FindNext" + , "FindFirst" + , "WriteUninstaller" + , "Section" // *** + , NULL // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType + , "GetLabelAddr" + , "GetFunctionAddress" + , "LockWindow" + , "FileWrite" // FileWriteUTF16LE, FileWriteWord + , "FileRead" // FileReadUTF16LE, FileReadWord + + , "Log" // LogSet, LogText + + // Park + , "FindProc" + , "GetFontVersion" + , "GetFontName" +}; + +#endif + +/* NSIS can use one name for two CSIDL_*** and CSIDL_COMMON_*** items (CurrentUser / AllUsers) + Some NSIS shell names are not identical to WIN32 CSIDL_* names. + NSIS doesn't use some CSIDL_* values. But we add name for all CSIDL_ (marked with '+'). */ + +static const char *kShellStrings[] = +{ + "DESKTOP" // + + , "INTERNET" // + + , "SMPROGRAMS" // CSIDL_PROGRAMS + , "CONTROLS" // + + , "PRINTERS" // + + , "DOCUMENTS" // CSIDL_PERSONAL + , "FAVORITES" // CSIDL_FAVORITES + , "SMSTARTUP" // CSIDL_STARTUP + , "RECENT" // CSIDL_RECENT + , "SENDTO" // CSIDL_SENDTO + , "BITBUCKET" // + + , "STARTMENU" + , NULL // CSIDL_MYDOCUMENTS = CSIDL_PERSONAL + , "MUSIC" // CSIDL_MYMUSIC + , "VIDEOS" // CSIDL_MYVIDEO + , NULL + , "DESKTOP" // CSIDL_DESKTOPDIRECTORY + , "DRIVES" // + + , "NETWORK" // + + , "NETHOOD" + , "FONTS" + , "TEMPLATES" + , "STARTMENU" // CSIDL_COMMON_STARTMENU + , "SMPROGRAMS" // CSIDL_COMMON_PROGRAMS + , "SMSTARTUP" // CSIDL_COMMON_STARTUP + , "DESKTOP" // CSIDL_COMMON_DESKTOPDIRECTORY + , "APPDATA" // CSIDL_APPDATA !!! "QUICKLAUNCH" + , "PRINTHOOD" + , "LOCALAPPDATA" + , "ALTSTARTUP" + , "ALTSTARTUP" // CSIDL_COMMON_ALTSTARTUP + , "FAVORITES" // CSIDL_COMMON_FAVORITES + , "INTERNET_CACHE" + , "COOKIES" + , "HISTORY" + , "APPDATA" // CSIDL_COMMON_APPDATA + , "WINDIR" + , "SYSDIR" + , "PROGRAM_FILES" // + + , "PICTURES" // CSIDL_MYPICTURES + , "PROFILE" + , "SYSTEMX86" // + + , "PROGRAM_FILESX86" // + + , "PROGRAM_FILES_COMMON" // + + , "PROGRAM_FILES_COMMONX8" // + CSIDL_PROGRAM_FILES_COMMONX86 + , "TEMPLATES" // CSIDL_COMMON_TEMPLATES + , "DOCUMENTS" // CSIDL_COMMON_DOCUMENTS + , "ADMINTOOLS" // CSIDL_COMMON_ADMINTOOLS + , "ADMINTOOLS" // CSIDL_ADMINTOOLS + , "CONNECTIONS" // + + , NULL + , NULL + , NULL + , "MUSIC" // CSIDL_COMMON_MUSIC + , "PICTURES" // CSIDL_COMMON_PICTURES + , "VIDEOS" // CSIDL_COMMON_VIDEO + , "RESOURCES" + , "RESOURCES_LOCALIZED" + , "COMMON_OEM_LINKS" // + + , "CDBURN_AREA" + , NULL // unused + , "COMPUTERSNEARME" // + +}; + + +static void UIntToString(AString &s, UInt32 v) +{ + char sz[16]; + ConvertUInt32ToString(v, sz); + s += sz; } -UInt32 CInArchive::ReadUInt32() +#ifdef NSIS_SCRIPT + +void CInArchive::Add_UInt(UInt32 v) { - UInt32 value = 0; - for (int i = 0; i < 4; i++) - value |= ((UInt32)(ReadByte()) << (8 * i)); - return value; + char sz[16]; + ConvertUInt32ToString(v, sz); + Script += sz; } -void CInArchive::ReadBlockHeader(CBlockHeader &bh) +static void Add_SignedInt(CDynLimBuf &s, Int32 v) { - bh.Offset = ReadUInt32(); - bh.Num = ReadUInt32(); + char sz[32]; + ConvertInt64ToString(v, sz); + s += sz; } -#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } +static void Add_Hex(CDynLimBuf &s, UInt32 v) +{ + char sz[16]; + sz[0] = '0'; + sz[1] = 'x'; + ConvertUInt32ToHex(v, sz + 2); + s += sz; +} -static int CompareItems(void *const *p1, void *const *p2, void * /* param */) +static UInt32 GetUi16Str_Len(const Byte *p) { - const CItem &i1 = **(CItem **)p1; - const CItem &i2 = **(CItem **)p2; - RINOZ(MyCompare(i1.Pos, i2.Pos)); - if (i1.IsUnicode) + const Byte *pp = p; + for (; *pp != 0 || *(pp + 1) != 0; pp += 2); + return (UInt32)((pp - p) >> 1); +} + +void CInArchive::AddLicense(UInt32 param, Int32 langID) +{ + Space(); + if (param >= NumStringChars || + param + 1 >= NumStringChars) + { + Script += kErrorStr; + return; + } + strUsed[param] = 1; + + UInt32 start = _stringsPos + (IsUnicode ? param * 2 : param); + UInt32 offset = start + (IsUnicode ? 2 : 1); + { + FOR_VECTOR (i, LicenseFiles) + { + const CLicenseFile &lic = LicenseFiles[i]; + if (offset == lic.Offset) + { + Script += lic.Name; + return; + } + } + } + AString fileName = "[LICENSE]"; + if (langID >= 0) + { + fileName += "\\license-"; + // LangId_To_String(fileName, langID); + UIntToString(fileName, langID); + } + else if (++_numRootLicenses > 1) { - RINOZ(i1.PrefixU.Compare(i2.PrefixU)); - RINOZ(i1.NameU.Compare(i2.NameU)); + fileName += '-'; + UIntToString(fileName, _numRootLicenses); } + const Byte *sz = (_data + start); + unsigned marker = IsUnicode ? Get16(sz) : *sz; + bool isRTF = (marker == 2); + fileName += isRTF ? ".rtf" : ".txt"; // if (*sz == 1) it's text; + Script += fileName; + + CLicenseFile &lic = LicenseFiles.AddNew(); + lic.Name = fileName; + lic.Offset = offset; + if (!IsUnicode) + lic.Size = (UInt32)strlen((const char *)sz + 1); else { - RINOZ(i1.PrefixA.Compare(i2.PrefixA)); - RINOZ(i1.NameA.Compare(i2.NameA)); + sz += 2; + UInt32 len = GetUi16Str_Len(sz); + lic.Size = len * 2; + if (isRTF) + { + lic.Text.Alloc((size_t)len); + for (UInt32 i = 0; i < len; i++, sz += 2) + { + unsigned c = Get16(sz); + if (c >= 256) + c = '?'; + lic.Text[i] = (Byte)(c); + } + lic.Size = len; + lic.Offset = 0; + } } - return 0; } -static AString UIntToString(UInt32 v) +#endif + + +#define kVar_CMDLINE 20 +#define kVar_INSTDIR 21 +#define kVar_OUTDIR 22 +#define kVar_EXEDIR 23 +#define kVar_LANGUAGE 24 +#define kVar_TEMP 25 +#define kVar_PLUGINSDIR 26 +#define kVar_EXEPATH 27 // NSIS 2.26+ +#define kVar_EXEFILE 28 // NSIS 2.26+ + +#define kVar_HWNDPARENT_225 27 +#define kVar_HWNDPARENT 29 + +// #define kVar__CLICK 30 +#define kVar_Spec_OUTDIR_225 29 // NSIS 2.04 - 2.25 +#define kVar_Spec_OUTDIR 31 // NSIS 2.26+ + + +static const char *kVarStrings[] = { - char sz[32]; - ConvertUInt64ToString(v, sz); - return sz; + "CMDLINE" + , "INSTDIR" + , "OUTDIR" + , "EXEDIR" + , "LANGUAGE" + , "TEMP" + , "PLUGINSDIR" + , "EXEPATH" // NSIS 2.26+ + , "EXEFILE" // NSIS 2.26+ + , "HWNDPARENT" + , "_CLICK" // is set from page->clicknext + , "_OUTDIR" // NSIS 2.04+ +}; + +static const unsigned kNumInternalVars = 20 + ARRAY_SIZE(kVarStrings); + +#define GET_NUM_INTERNAL_VARS (IsNsis200 ? kNumInternalVars - 3 : IsNsis225 ? kNumInternalVars - 2 : kNumInternalVars); + +void CInArchive::GetVar2(AString &res, UInt32 index) +{ + if (index < 20) + { + if (index >= 10) + { + res += 'R'; + index -= 10; + } + UIntToString(res, index); + } + else + { + unsigned numInternalVars = GET_NUM_INTERNAL_VARS; + if (index < numInternalVars) + { + if (IsNsis225 && index >= kVar_EXEPATH) + index += 2; + res += kVarStrings[index - 20]; + } + else + { + res += '_'; + UIntToString(res, index - numInternalVars); + res += '_'; + } + } } -static AString IntToString(Int32 v) +void CInArchive::GetVar(AString &res, UInt32 index) { - char sz[32]; - ConvertInt64ToString(v, sz); - return sz; + res += '$'; + GetVar2(res, index); +} + +#ifdef NSIS_SCRIPT + +void CInArchive::Add_Var(UInt32 index) +{ + _tempString_for_GetVar.Empty(); + GetVar(_tempString_for_GetVar, index); + Script += _tempString_for_GetVar; +} + +void CInArchive::AddParam_Var(UInt32 index) +{ + Space(); + Add_Var(index); +} + +void CInArchive::AddParam_UInt(UInt32 value) +{ + Space(); + Add_UInt(value); +} + +#endif + + +#define NS_CODE_SKIP 252 +#define NS_CODE_VAR 253 +#define NS_CODE_SHELL 254 +#define NS_CODE_LANG 255 + +#define NS_3_CODE_LANG 1 +#define NS_3_CODE_SHELL 2 +#define NS_3_CODE_VAR 3 +#define NS_3_CODE_SKIP 4 + +#define PARK_CODE_SKIP 0xE000 +#define PARK_CODE_VAR 0xE001 +#define PARK_CODE_SHELL 0xE002 +#define PARK_CODE_LANG 0xE003 + +#define IS_NS_SPEC_CHAR(c) ((c) >= NS_CODE_SKIP) +#define IS_PARK_SPEC_CHAR(c) ((c) >= PARK_CODE_SKIP && (c) <= PARK_CODE_LANG) + +#define DECODE_NUMBER_FROM_2_CHARS(c0, c1) (((c0) & 0x7F) | (((unsigned)((c1) & 0x7F)) << 7)) +#define CONVERT_NUMBER_NS_3_UNICODE(n) n = ((n & 0x7F) | (((n >> 8) & 0x7F) << 7)) +#define CONVERT_NUMBER_PARK(n) n &= 0x7FFF + + +static bool AreStringsEqual_16and8(const Byte *p16, const char *p8) +{ + for (;;) + { + unsigned c16 = Get16(p16); p16 += 2; + unsigned c = (Byte)(*p8++); + if (c16 != c) + return false; + if (c == 0) + return true; + } +} + +void CInArchive::GetShellString(AString &s, unsigned index1, unsigned index2) +{ + // zeros are not allowed here. + // if (index1 == 0 || index2 == 0) throw 333; + + if ((index1 & 0x80) != 0) + { + unsigned offset = (index1 & 0x3F); + + /* NSIS reads registry string: + keyName = HKLM Software\\Microsoft\\Windows\\CurrentVersion + mask = KEY_WOW64_64KEY, If 64-bit flag in index1 is set + valueName = string(offset) + If registry reading is failed, NSIS uses second parameter (index2) + to read string. The recursion is possible in that case in NSIS. + We don't parse index2 string. We only set strUsed status for that + string (but without recursion). */ + + if (offset >= NumStringChars) + { + s += kErrorStr; + return; + } + + #ifdef NSIS_SCRIPT + strUsed[offset] = 1; + if (index2 < NumStringChars) + strUsed[index2] = 1; + #endif + + const Byte *p = (const Byte *)(_data + _stringsPos); + int id = -1; + if (IsUnicode) + { + p += offset * 2; + if (AreStringsEqual_16and8(p, "ProgramFilesDir")) + id = 0; + else if (AreStringsEqual_16and8(p, "CommonFilesDir")) + id = 1; + } + else + { + p += offset; + if (strcmp((const char *)p, "ProgramFilesDir") == 0) + id = 0; + else if (strcmp((const char *)p, "CommonFilesDir") == 0) + id = 1; + } + + s += ((id >= 0) ? (id == 0 ? "$PROGRAMFILES" : "$COMMONFILES") : + "$_ERROR_UNSUPPORTED_VALUE_REGISTRY_"); + // s += ((index1 & 0x40) != 0) ? "64" : "32"; + if ((index1 & 0x40) != 0) + s += "64"; + + if (id < 0) + { + s += '('; + if (IsUnicode) + { + for (unsigned i = 0; i < 256; i++) + { + wchar_t c = Get16(p + i * 2); + if (c == 0) + break; + if (c < 0x80) + s += (char)c; + } + } + else + s += (const char *)p; + s += ')'; + } + return; + } + + s += '$'; + if (index1 < ARRAY_SIZE(kShellStrings)) + { + const char *sz = kShellStrings[index1]; + if (sz) + { + s += sz; + return; + } + } + if (index2 < ARRAY_SIZE(kShellStrings)) + { + const char *sz = kShellStrings[index2]; + if (sz) + { + s += sz; + return; + } + } + s += "_ERROR_UNSUPPORTED_SHELL_"; + s += '['; + UIntToString(s, index1); + s += ','; + UIntToString(s, index2); + s += ']'; +} + +#ifdef NSIS_SCRIPT + +void CInArchive::Add_LangStr_Simple(UInt32 id) +{ + Script += "LSTR_"; + Add_UInt(id); +} + +#endif + +void CInArchive::Add_LangStr(AString &res, UInt32 id) +{ + #ifdef NSIS_SCRIPT + langStrIDs.Add(id); + #endif + res += "$(LSTR_"; + UIntToString(res, id); + res += ')'; +} + +void CInArchive::GetNsisString_Raw(const Byte *s) +{ + Raw_AString.Empty(); + + if (NsisType != k_NsisType_Nsis3) + { + for (;;) + { + Byte c = *s++; + if (c == 0) + return; + if (IS_NS_SPEC_CHAR(c)) + { + Byte c0 = *s++; + if (c0 == 0) + return; + if (c != NS_CODE_SKIP) + { + Byte c1 = *s++; + if (c1 == 0) + return; + + if (c == NS_CODE_SHELL) + GetShellString(Raw_AString, c0, c1); + else + { + unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + if (c == NS_CODE_VAR) + GetVar(Raw_AString, n); + else // if (c == NS_CODE_LANG) + Add_LangStr(Raw_AString, n); + } + continue; + } + c = c0; + } + Raw_AString += (char)c; + } + } + + // NSIS-3 ANSI + for (;;) + { + Byte c = *s++; + if (c <= NS_3_CODE_SKIP) + { + if (c == 0) + return; + Byte c0 = *s++; + if (c0 == 0) + return; + if (c != NS_3_CODE_SKIP) + { + Byte c1 = *s++; + if (c1 == 0) + return; + + if (c == NS_3_CODE_SHELL) + GetShellString(Raw_AString, c0, c1); + else + { + unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + if (c == NS_3_CODE_VAR) + GetVar(Raw_AString, n); + else // if (c == NS_3_CODE_LANG) + Add_LangStr(Raw_AString, n); + } + continue; + } + c = c0; + } + Raw_AString += (char)c; + } +} + +#ifdef NSIS_SCRIPT + +void CInArchive::GetNsisString(AString &res, const Byte *s) +{ + for (;;) + { + Byte c = *s++; + if (c == 0) + return; + if (NsisType != k_NsisType_Nsis3) + { + if (IS_NS_SPEC_CHAR(c)) + { + Byte c0 = *s++; + if (c0 == 0) + return; + if (c != NS_CODE_SKIP) + { + Byte c1 = *s++; + if (c1 == 0) + return; + if (c == NS_CODE_SHELL) + GetShellString(res, c0, c1); + else + { + unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + if (c == NS_CODE_VAR) + GetVar(res, n); + else // if (c == NS_CODE_LANG) + Add_LangStr(res, n); + } + continue; + } + c = c0; + } + } + else + { + // NSIS-3 ANSI + if (c <= NS_3_CODE_SKIP) + { + Byte c0 = *s++; + if (c0 == 0) + return; + if (c0 == 0) + break; + if (c != NS_3_CODE_SKIP) + { + Byte c1 = *s++; + if (c1 == 0) + return; + if (c == NS_3_CODE_SHELL) + GetShellString(res, c0, c1); + else + { + unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + if (c == NS_3_CODE_VAR) + GetVar(res, n); + else // if (c == NS_3_CODE_LANG) + Add_LangStr(res, n); + } + continue; + } + c = c0; + } + } + + { + const char *e; + if (c == 9) e = "$\\t"; + else if (c == 10) e = "$\\n"; + else if (c == 13) e = "$\\r"; + else if (c == '"') e = "$\\\""; + else if (c == '$') e = "$$"; + else + { + res += (char)c; + continue; + } + res += e; + continue; + } + } } -AString CInArchive::ReadStringA(UInt32 pos) const +#endif + +void CInArchive::GetNsisString_Unicode_Raw(const Byte *p) { - AString s; - if (pos >= _size) - return IntToString((Int32)pos); - UInt32 offset = GetOffset() + _stringsPos + pos; + Raw_UString.Empty(); + + if (IsPark()) + { + for (;;) + { + unsigned c = Get16(p); + p += 2; + if (c == 0) + break; + if (c < 0x80) + { + Raw_UString += (wchar_t)c; + continue; + } + + if (IS_PARK_SPEC_CHAR(c)) + { + unsigned n = Get16(p); + p += 2; + if (n == 0) + break; + if (c != PARK_CODE_SKIP) + { + Raw_AString.Empty(); + if (c == PARK_CODE_SHELL) + GetShellString(Raw_AString, n & 0xFF, n >> 8); + else + { + CONVERT_NUMBER_PARK(n); + if (c == PARK_CODE_VAR) + GetVar(Raw_AString, n); + else // if (c == PARK_CODE_LANG) + Add_LangStr(Raw_AString, n); + } + for (const Byte *s = (const Byte *)(const char *)Raw_AString; *s != 0; s++) + Raw_UString += *s; + continue; + } + c = n; + } + + Raw_UString += (wchar_t)c; + } + + return; + } + + // NSIS-3 Unicode for (;;) { - if (offset >= _size) - break; // throw 1; - char c = _data[offset++]; + unsigned c = Get16(p); + p += 2; + if (c > NS_3_CODE_SKIP) + { + Raw_UString += (wchar_t)c; + continue; + } if (c == 0) break; - s += c; + + unsigned n = Get16(p); + p += 2; + if (n == 0) + break; + if (c == NS_3_CODE_SKIP) + { + Raw_UString += (wchar_t)n; + continue; + } + + Raw_AString.Empty(); + if (c == NS_3_CODE_SHELL) + GetShellString(Raw_AString, n & 0xFF, n >> 8); + else + { + CONVERT_NUMBER_NS_3_UNICODE(n); + if (c == NS_3_CODE_VAR) + GetVar(Raw_AString, n); + else // if (c == NS_3_CODE_LANG) + Add_LangStr(Raw_AString, n); + } + for (const Byte *s = (const Byte *)(const char *)Raw_AString; *s != 0; s++) + Raw_UString += (wchar_t)*s; } - return s; } -UString CInArchive::ReadStringU(UInt32 pos) const +#ifdef NSIS_SCRIPT + +static const Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +void CInArchive::GetNsisString_Unicode(AString &res, const Byte *p) { - UString s; - UInt32 offset = GetOffset() + _stringsPos + (pos * 2); for (;;) { - if (offset >= _size || offset + 1 >= _size) - return s; // throw 1; - char c0 = _data[offset++]; - char c1 = _data[offset++]; - wchar_t c = (c0 | ((wchar_t)c1 << 8)); + unsigned c = Get16(p); + p += 2; if (c == 0) break; - s += c; + if (IsPark()) + { + if (IS_PARK_SPEC_CHAR(c)) + { + unsigned n = Get16(p); + p += 2; + if (n == 0) + break; + if (c != PARK_CODE_SKIP) + { + if (c == PARK_CODE_SHELL) + GetShellString(res, n & 0xFF, n >> 8); + else + { + CONVERT_NUMBER_PARK(n); + if (c == PARK_CODE_VAR) + GetVar(res, n); + else // if (c == PARK_CODE_LANG) + Add_LangStr(res, n); + } + continue; + } + c = n; + } + } + else + { + // NSIS-3 Unicode + if (c <= NS_3_CODE_SKIP) + { + unsigned n = Get16(p); + p += 2; + if (n == 0) + break; + if (c != NS_3_CODE_SKIP) + { + if (c == NS_3_CODE_SHELL) + GetShellString(res, n & 0xFF, n >> 8); + else + { + CONVERT_NUMBER_NS_3_UNICODE(n); + if (c == NS_3_CODE_VAR) + GetVar(res, n); + else // if (c == NS_3_CODE_LANG) + Add_LangStr(res, n); + } + continue; + } + c = n; + } + } + + if (c < 0x80) + { + const char *e; + if (c == 9) e = "$\\t"; + else if (c == 10) e = "$\\n"; + else if (c == 13) e = "$\\r"; + else if (c == '"') e = "$\\\""; + else if (c == '$') e = "$$"; + else + { + res += (char)c; + continue; + } + res += e; + continue; + } + + UInt32 value = c; + /* + if (value >= 0xD800 && value < 0xE000) + { + UInt32 c2; + if (value >= 0xDC00 || srcPos == srcLen) + break; + c2 = src[srcPos++]; + if (c2 < 0xDC00 || c2 >= 0xE000) + break; + value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; + } + */ + unsigned numAdds; + for (numAdds = 1; numAdds < 5; numAdds++) + if (value < (((UInt32)1) << (numAdds * 5 + 6))) + break; + res += (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds))); + do + { + numAdds--; + res += (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F)); + // destPos++; + } + while (numAdds != 0); + + // AddToUtf8(res, c); } - return s; } -/* -static AString ParsePrefix(const AString &prefix) +#endif + +void CInArchive::ReadString2_Raw(UInt32 pos) { - AString res = prefix; - if (prefix.Length() >= 3) + Raw_AString.Empty(); + Raw_UString.Empty(); + if ((Int32)pos < 0) + Add_LangStr(Raw_AString, -((Int32)pos + 1)); + else if (pos >= NumStringChars) { - if ((Byte)prefix[0] == 0xFD && (Byte)prefix[1] == 0x95 && (Byte)prefix[2] == 0x80) - res = "$INSTDIR" + prefix.Mid(3); - else if ((Byte)prefix[0] == 0xFD && (Byte)prefix[1] == 0x96 && (Byte)prefix[2] == 0x80) - res = "$OUTDIR" + prefix.Mid(3); + Raw_AString += kErrorStr; + // UIntToString(Raw_AString, pos); } - return res; + else + { + if (IsUnicode) + GetNsisString_Unicode_Raw(_data + _stringsPos + pos * 2); + else + GetNsisString_Raw(_data + _stringsPos + pos); + return; + } + for (const char *s = (const char *)Raw_AString; *s != 0; s++) + Raw_UString += *s; } -*/ -#define SYSREGKEY "Software\\Microsoft\\Windows\\CurrentVersion" +bool CInArchive::IsGoodString(UInt32 param) const +{ + if (param >= NumStringChars) + return false; + if (param == 0) + return true; + const Byte *p = _data + _stringsPos; + if (IsUnicode) + return (Get16(p + param * 2 - 2)) == 0; + return p[param - 1] == 0; +} -/* -# define CSIDL_PROGRAMS 0x2 -# define CSIDL_PRINTERS 0x4 -# define CSIDL_PERSONAL 0x5 -# define CSIDL_FAVORITES 0x6 -# define CSIDL_STARTUP 0x7 -# define CSIDL_RECENT 0x8 -# define CSIDL_SENDTO 0x9 -# define CSIDL_STARTMENU 0xB -# define CSIDL_MYMUSIC 0xD -# define CSIDL_MYVIDEO 0xE - -# define CSIDL_DESKTOPDIRECTORY 0x10 -# define CSIDL_NETHOOD 0x13 -# define CSIDL_FONTS 0x14 -# define CSIDL_TEMPLATES 0x15 -# define CSIDL_COMMON_STARTMENU 0x16 -# define CSIDL_COMMON_PROGRAMS 0x17 -# define CSIDL_COMMON_STARTUP 0x18 -# define CSIDL_COMMON_DESKTOPDIRECTORY 0x19 -# define CSIDL_APPDATA 0x1A -# define CSIDL_PRINTHOOD 0x1B -# define CSIDL_LOCAL_APPDATA 0x1C -# define CSIDL_ALTSTARTUP 0x1D -# define CSIDL_COMMON_ALTSTARTUP 0x1E -# define CSIDL_COMMON_FAVORITES 0x1F - -# define CSIDL_INTERNET_CACHE 0x20 -# define CSIDL_COOKIES 0x21 -# define CSIDL_HISTORY 0x22 -# define CSIDL_COMMON_APPDATA 0x23 -# define CSIDL_WINDOWS 0x24 -# define CSIDL_SYSTEM 0x25 -# define CSIDL_PROGRAM_FILES 0x26 -# define CSIDL_MYPICTURES 0x27 -# define CSIDL_PROFILE 0x28 -# define CSIDL_PROGRAM_FILES_COMMON 0x2B -# define CSIDL_COMMON_TEMPLATES 0x2D -# define CSIDL_COMMON_DOCUMENTS 0x2E -# define CSIDL_COMMON_ADMINTOOLS 0x2F - -# define CSIDL_ADMINTOOLS 0x30 -# define CSIDL_COMMON_MUSIC 0x35 -# define CSIDL_COMMON_PICTURES 0x36 -# define CSIDL_COMMON_VIDEO 0x37 -# define CSIDL_RESOURCES 0x38 -# define CSIDL_RESOURCES_LOCALIZED 0x39 -# define CSIDL_CDBURN_AREA 0x3B -*/ +bool CInArchive::AreTwoParamStringsEqual(UInt32 param1, UInt32 param2) const +{ + if (param1 == param2) + return true; + + /* NSIS-3.0a1 probably contains bug, so it can use 2 different strings + with same content. So we check real string also. + Also it's possible to check identical postfix parts of strings. */ + + if (param1 >= NumStringChars || + param2 >= NumStringChars) + return false; + + const Byte *p = _data + _stringsPos; + + if (IsUnicode) + { + const Byte *p1 = p + param1 * 2; + const Byte *p2 = p + param2 * 2; + for (;;) + { + UInt16 c = Get16(p1); + if (c != Get16(p2)) + return false; + if (c == 0) + return true; + p1 += 2; + p2 += 2; + } + } + else + { + const Byte *p1 = p + param1; + const Byte *p2 = p + param2; + for (;;) + { + Byte c = *p1++; + if (c != *p2++) + return false; + if (c == 0) + return true; + } + } +} + +#ifdef NSIS_SCRIPT + +UInt32 CInArchive::GetNumUsedVars() const +{ + UInt32 numUsedVars = 0; + const Byte *data = (const Byte *)_data + _stringsPos; + unsigned npi = 0; + for (UInt32 i = 0; i < NumStringChars;) + { + bool process = true; + if (npi < noParseStringIndexes.Size() && noParseStringIndexes[npi] == i) + { + process = false; + npi++; + } + + if (IsUnicode) + { + if (IsPark()) + { + for (;;) + { + unsigned c = Get16(data + i * 2); + i++; + if (c == 0) + break; + if (IS_PARK_SPEC_CHAR(c)) + { + UInt32 n = Get16(data + i * 2); + i++; + if (n == 0) + break; + if (process && c == PARK_CODE_VAR) + { + CONVERT_NUMBER_PARK(n); + n++; + if (numUsedVars < n) + numUsedVars = n; + } + } + } + } + else // NSIS-3 Unicode + { + for (;;) + { + unsigned c = Get16(data + i * 2); + i++; + if (c == 0) + break; + if (c > NS_3_CODE_SKIP) + continue; + UInt32 n = Get16(data + i * 2); + i++; + if (n == 0) + break; + if (process && c == NS_3_CODE_VAR) + { + CONVERT_NUMBER_NS_3_UNICODE(n); + n++; + if (numUsedVars < n) + numUsedVars = n; + } + } + } + } + else // not Unicode (ANSI) + { + if (NsisType != k_NsisType_Nsis3) + { + for (;;) + { + Byte c = data[i++]; + if (c == 0) + break; + if (IS_NS_SPEC_CHAR(c)) + { + Byte c0 = data[i++]; + if (c0 == 0) + break; + if (c == NS_CODE_SKIP) + continue; + Byte c1 = data[i++]; + if (c1 == 0) + break; + if (process && c == NS_CODE_VAR) + { + UInt32 n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + n++; + if (numUsedVars < n) + numUsedVars = n; + } + } + } + } + else + { + // NSIS-3 ANSI + for (;;) + { + Byte c = data[i++]; + if (c == 0) + break; + if (c > NS_3_CODE_SKIP) + continue; + + Byte c0 = data[i++]; + if (c0 == 0) + break; + if (c == NS_3_CODE_SKIP) + continue; + Byte c1 = data[i++]; + if (c1 == 0) + break; + if (process && c == NS_3_CODE_VAR) + { + UInt32 n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + n++; + if (numUsedVars < n) + numUsedVars = n; + } + } + } + } + } + return numUsedVars; +} + +void CInArchive::ReadString2(AString &s, UInt32 pos) +{ + if ((Int32)pos < 0) + { + Add_LangStr(s, -((Int32)pos + 1)); + return; + } + + if (pos >= NumStringChars) + { + s += kErrorStr; + // UIntToString(s, pos); + return; + } + + #ifdef NSIS_SCRIPT + strUsed[pos] = 1; + #endif + + if (IsUnicode) + GetNsisString_Unicode(s, _data + _stringsPos + pos * 2); + else + GetNsisString(s, _data + _stringsPos + pos); +} + +#endif + +#ifdef NSIS_SCRIPT + +#define DEL_DIR 1 +#define DEL_RECURSE 2 +#define DEL_REBOOT 4 +// #define DEL_SIMPLE 8 + +void CInArchive::AddRegRoot(UInt32 val) +{ + Space(); + const char *s; + switch (val) + { + case 0: s = "SHCTX"; break; + case 0x80000000: s = "HKCR"; break; + case 0x80000001: s = "HKCU"; break; + case 0x80000002: s = "HKLM"; break; + case 0x80000003: s = "HKU"; break; + case 0x80000004: s = "HKPD"; break; + case 0x80000005: s = "HKCC"; break; + case 0x80000006: s = "HKDD"; break; + case 0x80000050: s = "HKPT"; break; + case 0x80000060: s = "HKPN"; break; + default: + // Script += " RRRRR "; + // throw 1; + Add_Hex(Script, val); return; + } + Script += s; +} -struct CCommandPair +static const char *g_WinAttrib[] = { - int NumParams; - const char *Name; + "READONLY" + , "HIDDEN" + , "SYSTEM" + , NULL + , "DIRECTORY" + , "ARCHIVE" + , "DEVICE" + , "NORMAL" + , "TEMPORARY" + , "SPARSE_FILE" + , "REPARSE_POINT" + , "COMPRESSED" + , "OFFLINE" + , "NOT_CONTENT_INDEXED" + , "ENCRYPTED" + , NULL + , "VIRTUAL" }; -enum +#define FLAGS_DELIMITER '|' + +static void FlagsToString2(CDynLimBuf &s, const char **table, unsigned num, UInt32 flags) { - // 0 - EW_INVALID_OPCODE, // zero is invalid. useful for catching errors. (otherwise an all zeroes instruction - // does nothing, which is easily ignored but means something is wrong. - EW_RET, // return from function call - EW_NOP, // Nop/Jump, do nothing: 1, [?new address+1:advance one] - EW_ABORT, // Abort: 1 [status] - EW_QUIT, // Quit: 0 - EW_CALL, // Call: 1 [new address+1] - EW_UPDATETEXT, // Update status text: 2 [update str, ui_st_updateflag=?ui_st_updateflag:this] - EW_SLEEP, // Sleep: 1 [sleep time in milliseconds] - EW_BRINGTOFRONT, // BringToFront: 0 - EW_CHDETAILSVIEW, // SetDetailsView: 2 [listaction,buttonaction] - - // 10 - EW_SETFILEATTRIBUTES, // SetFileAttributes: 2 [filename, attributes] - EW_CREATEDIR, // Create directory: 2, [path, ?update$INSTDIR] - EW_IFFILEEXISTS, // IfFileExists: 3, [file name, jump amount if exists, jump amount if not exists] - EW_SETFLAG, // Sets a flag: 2 [id, data] - EW_IFFLAG, // If a flag: 4 [on, off, id, new value mask] - EW_GETFLAG, // Gets a flag: 2 [output, id] - EW_RENAME, // Rename: 3 [old, new, rebootok] - EW_GETFULLPATHNAME, // GetFullPathName: 2 [output, input, ?lfn:sfn] - EW_SEARCHPATH, // SearchPath: 2 [output, filename] - EW_GETTEMPFILENAME, // GetTempFileName: 2 [output, base_dir] - - // 20 - EW_EXTRACTFILE, // File to extract: 6 [overwriteflag, output filename, compressed filedata, filedatetimelow, filedatetimehigh, allow ignore] - // overwriteflag: 0x1 = no. 0x0=force, 0x2=try, 0x3=if date is newer - EW_DELETEFILE, // Delete File: 2, [filename, rebootok] - EW_MESSAGEBOX, // MessageBox: 5,[MB_flags,text,retv1:retv2,moveonretv1:moveonretv2] - EW_RMDIR, // RMDir: 2 [path, recursiveflag] - EW_STRLEN, // StrLen: 2 [output, input] - EW_ASSIGNVAR, // Assign: 4 [variable (0-9) to assign, string to assign, maxlen, startpos] - EW_STRCMP, // StrCmp: 5 [str1, str2, jump_if_equal, jump_if_not_equal, case-sensitive?] - EW_READENVSTR, // ReadEnvStr/ExpandEnvStrings: 3 [output, string_with_env_variables, IsRead] - EW_INTCMP, // IntCmp: 6 [val1, val2, equal, val1<val2, val1>val2, unsigned?] - EW_INTOP, // IntOp: 4 [output, input1, input2, op] where op: 0=add, 1=sub, 2=mul, 3=div, 4=bor, 5=band, 6=bxor, 7=bnot input1, 8=lnot input1, 9=lor, 10=land], 11=1%2 - - // 30 - EW_INTFMT, // IntFmt: [output, format, input] - EW_PUSHPOP, // Push/Pop/Exchange: 3 [variable/string, ?pop:push, ?exch] - EW_FINDWINDOW, // FindWindow: 5, [outputvar, window class,window name, window_parent, window_after] - EW_SENDMESSAGE, // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2] - EW_ISWINDOW, // IsWindow: 3 [hwnd, jump_if_window, jump_if_notwindow] - EW_GETDLGITEM, // GetDlgItem: 3: [outputvar, dialog, item_id] - EW_SETCTLCOLORS, // SerCtlColors: 3: [hwnd, pointer to struct colors] - EW_SETBRANDINGIMAGE, // SetBrandingImage: 1: [Bitmap file] - EW_CREATEFONT, // CreateFont: 5: [handle output, face name, height, weight, flags] - EW_SHOWWINDOW, // ShowWindow: 2: [hwnd, show state] - - // 40 - EW_SHELLEXEC, // ShellExecute program: 4, [shell action, complete commandline, parameters, showwindow] - EW_EXECUTE, // Execute program: 3,[complete command line,waitflag,>=0?output errorcode] - EW_GETFILETIME, // GetFileTime; 3 [file highout lowout] - EW_GETDLLVERSION, // GetDLLVersion: 3 [file highout lowout] - EW_REGISTERDLL, // Register DLL: 3,[DLL file name, string ptr of function to call, text to put in display (<0 if none/pass parms), 1 - no unload, 0 - unload] - EW_CREATESHORTCUT, // Make Shortcut: 5, [link file, target file, parameters, icon file, iconindex|show mode<<8|hotkey<<16] - EW_COPYFILES, // CopyFiles: 3 [source mask, destination location, flags] - EW_REBOOT, // Reboot: 0 - EW_WRITEINI, // Write INI String: 4, [Section, Name, Value, INI File] - EW_READINISTR, // ReadINIStr: 4 [output, section, name, ini_file] - - // 50 - EW_DELREG, // DeleteRegValue/DeleteRegKey: 4, [root key(int), KeyName, ValueName, delkeyonlyifempty]. ValueName is -1 if delete key - EW_WRITEREG, // Write Registry value: 5, [RootKey(int),KeyName,ItemName,ItemData,typelen] - // typelen=1 for str, 2 for dword, 3 for binary, 0 for expanded str - EW_READREGSTR, // ReadRegStr: 5 [output, rootkey(int), keyname, itemname, ==1?int::str] - EW_REGENUM, // RegEnum: 5 [output, rootkey, keyname, index, ?key:value] - EW_FCLOSE, // FileClose: 1 [handle] - EW_FOPEN, // FileOpen: 4 [name, openmode, createmode, outputhandle] - EW_FPUTS, // FileWrite: 3 [handle, string, ?int:string] - EW_FGETS, // FileRead: 4 [handle, output, maxlen, ?getchar:gets] - EW_FSEEK, // FileSeek: 4 [handle, offset, mode, >=0?positionoutput] - EW_FINDCLOSE, // FindClose: 1 [handle] - - // 60 - EW_FINDNEXT, // FindNext: 2 [output, handle] - EW_FINDFIRST, // FindFirst: 2 [filespec, output, handleoutput] - EW_WRITEUNINSTALLER, // WriteUninstaller: 3 [name, offset, icon_size] - EW_LOG, // LogText: 2 [0, text] / LogSet: [1, logstate] - EW_SECTIONSET, // SectionSetText: 3: [idx, 0, text] - // SectionGetText: 3: [idx, 1, output] - // SectionSetFlags: 3: [idx, 2, flags] - // SectionGetFlags: 3: [idx, 3, output] - EW_INSTTYPESET, // InstTypeSetFlags: 3: [idx, 0, flags] - // InstTypeGetFlags: 3: [idx, 1, output] - // instructions not actually implemented in exehead, but used in compiler. - EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR - EW_GETFUNCTIONADDR, + bool filled = false; + for (unsigned i = 0; i < num; i++) + { + UInt32 f = (UInt32)1 << i; + if ((flags & f) != 0) + { + const char *name = table[i]; + if (name) + { + if (filled) + s += FLAGS_DELIMITER; + filled = true; + s += name; + flags &= ~f; + } + } + } + if (flags != 0) + { + if (filled) + s += FLAGS_DELIMITER; + Add_Hex(s, flags); + } +} + +static bool DoesNeedQuotes(const char *s) +{ + char c = s[0]; + if (c == 0 || c == '#' || c == ';' || (c == '/' && s[1] == '*')) + return true; + for (;;) + { + char c = *s++; + if (c == 0) + return false; + if (c == ' ') + return true; + } +} + +void CInArchive::Add_QuStr(const AString &s) +{ + bool needQuotes = DoesNeedQuotes(s); + if (needQuotes) + Script += '\"'; + Script += s; + if (needQuotes) + Script += '\"'; +} + +void CInArchive::SpaceQuStr(const AString &s) +{ + Space(); + Add_QuStr(s); +} + +void CInArchive::AddParam(UInt32 pos) +{ + _tempString.Empty(); + ReadString2(_tempString, pos); + SpaceQuStr(_tempString); +} + +void CInArchive::AddParams(const UInt32 *params, unsigned num) +{ + for (unsigned i = 0; i < num; i++) + AddParam(params[i]); +} + +void CInArchive::AddOptionalParam(UInt32 pos) +{ + if (pos != 0) + AddParam(pos); +} - EW_LOCKWINDOW +static unsigned GetNumParams(const UInt32 *params, unsigned num) +{ + for (; num > 0 && params[num - 1] == 0; num--); + return num; +} + +void CInArchive::AddOptionalParams(const UInt32 *params, unsigned num) +{ + AddParams(params, GetNumParams(params, num)); +} + + +static const UInt32 CMD_REF_Goto = (1 << 0); +static const UInt32 CMD_REF_Call = (1 << 1); +static const UInt32 CMD_REF_Pre = (1 << 2); +static const UInt32 CMD_REF_Show = (1 << 3); +static const UInt32 CMD_REF_Leave = (1 << 4); +static const UInt32 CMD_REF_OnFunc = (1 << 5); +static const UInt32 CMD_REF_Section = (1 << 6); +static const UInt32 CMD_REF_InitPluginDir = (1 << 7); +// static const UInt32 CMD_REF_Creator = (1 << 5); // _Pre is used instead +static const unsigned CMD_REF_OnFunc_NumShifts = 28; // it uses for onFunc too +static const unsigned CMD_REF_Page_NumShifts = 16; // it uses for onFunc too +static const UInt32 CMD_REF_Page_Mask = 0x0FFF0000; +static const UInt32 CMD_REF_OnFunc_Mask = 0xF0000000; + +inline bool IsPageFunc(UInt32 flag) +{ + return (flag & (CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave)) != 0; +} + +inline bool IsFunc(UInt32 flag) +{ + // return (flag & (CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave | CMD_REF_OnFunc)) != 0; + return (flag & (CMD_REF_Call | CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave | CMD_REF_OnFunc)) != 0; +} + +inline bool IsProbablyEndOfFunc(UInt32 flag) +{ + return (flag != 0 && flag != CMD_REF_Goto); +} + +static const char *kOnFunc[] = +{ + "Init" + , "InstSuccess" + , "InstFailed" + , "UserAbort" + , "GUIInit" + , "GUIEnd" + , "MouseOverSection" + , "VerifyInstDir" + , "SelChange" + , "RebootFailed" }; -#ifdef NSIS_SCRIPT -static CCommandPair kCommandPairs[] = -{ - { 0, "Invalid" }, - { 0, "Return" }, - { 1, "Goto" }, - { 0, "Abort" }, - { 0, "Quit" }, - { 1, "Call" }, - { 2, "UpdateSatusText" }, - { 1, "Sleep" }, - { 0, "BringToFront" }, - { 2, "SetDetailsView" }, - - { 2, "SetFileAttributes" }, - { 2, "SetOutPath" }, - { 3, "IfFileExists" }, - { 2, "SetFlag" }, - { 4, "IfFlag" }, - { 2, "GetFlag" }, - { 3, "Rename" }, - { 2, "GetFullPathName" }, - { 2, "SearchPath" }, - { 2, "GetTempFileName" }, - - { 6, "File" }, - { 2, "Delete" }, - { 5, "MessageBox" }, - { 2, "RMDir" }, - { 2, "StrLen" }, - { 4, "StrCpy" }, - { 5, "StrCmp" }, - { 3, "ReadEnvStr" }, - { 6, "IntCmp" }, - { 4, "IntOp" }, - - { 3, "IntFmt" }, - { 3, "PushPop" }, - { 5, "FindWindow" }, - { 6, "SendMessage" }, - { 3, "IsWindow" }, - { 3, "GetDlgItem" }, - { 3, "SerCtlColors" }, - { 1, "SetBrandingImage" }, - { 5, "CreateFont" }, - { 2, "ShowWindow" }, - - { 4, "ShellExecute" }, - { 3, "Execute" }, - { 3, "GetFileTime" }, - { 3, "GetDLLVersion" }, - { 3, "RegisterDLL" }, - { 5, "CreateShortCut" }, - { 3, "CopyFiles" }, - { 0, "Reboot" }, - { 4, "WriteINIStr" }, - { 4, "ReadINIStr" }, - - { 4, "DelReg" }, - { 5, "WriteReg" }, - { 5, "ReadRegStr" }, - { 5, "RegEnum" }, - { 1, "FileClose" }, - { 4, "FileOpen" }, - { 3, "FileWrite" }, - { 4, "FileRead" }, - { 4, "FileSeek" }, - { 1, "FindClose" }, - - { 2, "FindNext" }, - { 2, "FindFirst" }, - { 3, "WriteUninstaller" }, - { 2, "LogText" }, - { 3, "Section?etText" }, - { 3, "InstType?etFlags" }, - { 6, "GetLabelAddr" }, - { 2, "GetFunctionAddress" }, - { 6, "LockWindow" } +void CInArchive::Add_FuncName(const UInt32 *labels, UInt32 index) +{ + UInt32 mask = labels[index]; + if (mask & CMD_REF_OnFunc) + { + Script += ".on"; + Script += kOnFunc[labels[index] >> CMD_REF_OnFunc_NumShifts]; + } + else if (mask & CMD_REF_InitPluginDir) + { + /* + if (!IsInstaller) + Script += "un." + */ + Script += "Initialize_____Plugins"; + } + else + { + Script += "func_"; + Add_UInt(index); + } +} + +void CInArchive::AddParam_Func(const UInt32 *labels, UInt32 index) +{ + Space(); + if ((Int32)index >= 0) + Add_FuncName(labels, index); + else + AddQuotes(); +} + + +void CInArchive::Add_LabelName(UInt32 index) +{ + Script += "label_"; + Add_UInt(index); +} + +// param != 0 +void CInArchive::Add_GotoVar(UInt32 param) +{ + Space(); + if ((Int32)param < 0) + Add_Var(-((Int32)param + 1)); + else + Add_LabelName(param - 1); +} + +void CInArchive::Add_GotoVar1(UInt32 param) +{ + if (param == 0) + Script += " 0"; + else + Add_GotoVar(param); +} + +void CInArchive::Add_GotoVars2(const UInt32 *params) +{ + Add_GotoVar1(params[0]); + if (params[1] != 0) + Add_GotoVar(params[1]); +} + +static bool NoLabels(const UInt32 *labels, UInt32 num) +{ + for (UInt32 i = 0; i < num; i++) + if (labels[i] != 0) + return false; + return true; +} + +static const char *k_REBOOTOK = " /REBOOTOK"; + +#define MY__MB_ABORTRETRYIGNORE 2 +#define MY__MB_RETRYCANCEL 5 + +static const char *k_MB_Buttons[] = +{ + "OK" + , "OKCANCEL" + , "ABORTRETRYIGNORE" + , "YESNOCANCEL" + , "YESNO" + , "RETRYCANCEL" + , "CANCELTRYCONTINUE" }; -#endif +#define MY__MB_ICONSTOP (1 << 4) -static const char *kShellStrings[] = +static const char *k_MB_Icons[] = +{ + NULL + , "ICONSTOP" + , "ICONQUESTION" + , "ICONEXCLAMATION" + , "ICONINFORMATION" +}; + +static const char *k_MB_Flags[] = +{ + "HELP" + , "NOFOCUS" + , "SETFOREGROUND" + , "DEFAULT_DESKTOP_ONLY" + , "TOPMOST" + , "RIGHT" + , "RTLREADING" + // , "SERVICE_NOTIFICATION" // unsupported. That bit is used for NSIS purposes +}; + +#define MY__IDCANCEL 2 +#define MY__IDIGNORE 5 + +static const char *k_Button_IDs[] = +{ + "0" + , "IDOK" + , "IDCANCEL" + , "IDABORT" + , "IDRETRY" + , "IDIGNORE" + , "IDYES" + , "IDNO" + , "IDCLOSE" + , "IDHELP" + , "IDTRYAGAIN" + , "IDCONTINUE" +}; + +void CInArchive::Add_ButtonID(UInt32 buttonID) +{ + Space(); + if (buttonID < ARRAY_SIZE(k_Button_IDs)) + Script += k_Button_IDs[buttonID]; + else + { + Script += "Button_"; + Add_UInt(buttonID); + } +} + +bool CInArchive::IsDirectString_Equal(UInt32 offset, const char *s) const +{ + if (offset >= NumStringChars) + return false; + if (IsUnicode) + return AreStringsEqual_16and8(_data + _stringsPos + offset * 2, s); + else + return strcmp((const char *)(const Byte *)_data + _stringsPos + offset, s) == 0; +} + +static UInt32 ConvertHexStringToUInt32(const char *s, const char **end) +{ + UInt32 result = 0; + for (int i = 0; i < 8; i++) + { + char c = *s; + UInt32 v; + if (c >= '0' && c <= '9') v = (c - '0'); + else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A'); + else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a'); + else + { + if (end != NULL) + *end = s; + return result; + } + result <<= 4; + result |= v; + s++; + } + if (end != NULL) + *end = s; + return 0; +} + +static bool StringToUInt32(const char *s, UInt32 &res) +{ + const char *end; + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + res = ConvertHexStringToUInt32(s + 2, &end); + else + res = ConvertStringToUInt32(s, &end); + return (*end == 0); +} + +static const unsigned k_CtlColors_Size = 24; + +struct CNsis_CtlColors +{ + UInt32 text; // COLORREF + UInt32 bkc; // COLORREF + UInt32 lbStyle; + UInt32 bkb; // HBRUSH + Int32 bkmode; + Int32 flags; + + void Parse(const Byte *p); +}; + +void CNsis_CtlColors::Parse(const Byte *p) +{ + text = Get32(p); + bkc = Get32(p + 4); + lbStyle = Get32(p + 8); + bkb = Get32(p + 12); + bkmode = (Int32)Get32(p + 16); + flags = (Int32)Get32(p + 20); +} + +// Win32 constants +#define MY__TRANSPARENT 1 +#define MY__OPAQUE 2 + +#define MY__GENERIC_READ (1 << 31) +#define MY__GENERIC_WRITE (1 << 30) +#define MY__GENERIC_EXECUTE (1 << 29) +#define MY__GENERIC_ALL (1 << 28) + +#define MY__CREATE_NEW 1 +#define MY__CREATE_ALWAYS 2 +#define MY__OPEN_EXISTING 3 +#define MY__OPEN_ALWAYS 4 +#define MY__TRUNCATE_EXISTING 5 + +// text/bg colors +#define kColorsFlags_TEXT 1 +#define kColorsFlags_TEXT_SYS 2 +#define kColorsFlags_BK 4 +#define kColorsFlags_BK_SYS 8 +#define kColorsFlags_BKB 16 + +void CInArchive::Add_Color2(UInt32 v) +{ + v = ((v & 0xFF) << 16) | (v & 0xFF00) | ((v >> 16) & 0xFF); + char sz[32]; + for (int i = 5; i >= 0; i--) + { + unsigned t = v & 0xF; + v >>= 4; + sz[i] = (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); + } + sz[6] = 0; + Script += sz; +} + +void CInArchive::Add_ColorParam(UInt32 v) +{ + Space(); + Add_Color2(v); +} + +void CInArchive::Add_Color(UInt32 v) +{ + Script += "0x"; + Add_Color2(v); +} + +#define MY__SW_HIDE 0 +#define MY__SW_SHOWNORMAL 1 + +#define MY__SW_SHOWMINIMIZED 2 +#define MY__SW_SHOWMINNOACTIVE 7 +#define MY__SW_SHOWNA 8 + +static const char *kShowWindow_Commands[] = +{ + "HIDE" + , "SHOWNORMAL" // "NORMAL" + , "SHOWMINIMIZED" + , "SHOWMAXIMIZED" // "MAXIMIZE" + , "SHOWNOACTIVATE" + , "SHOW" + , "MINIMIZE" + , "SHOWMINNOACTIVE" + , "SHOWNA" + , "RESTORE" + , "SHOWDEFAULT" + , "FORCEMINIMIZE" // "MAX" +}; + +static void Add_ShowWindow_Cmd_2(AString &s, UInt32 cmd) { - "", - "", - - "SMPROGRAMS", - "", - "PRINTERS", - "DOCUMENTS", - "FAVORITES", - "SMSTARTUP", - "RECENT", - "SENDTO", - "", - "STARTMENU", - "", - "MUSIC", - "VIDEO", - "", - - "DESKTOP", - "", - "", - "NETHOOD", - "FONTS", - "TEMPLATES", - "COMMONSTARTMENU", - "COMMONFILES", - "COMMON_STARTUP", - "COMMON_DESKTOPDIRECTORY", - "QUICKLAUNCH", - "PRINTHOOD", - "LOCALAPPDATA", - "ALTSTARTUP", - "ALTSTARTUP", - "FAVORITES", - - "INTERNET_CACHE", - "COOKIES", - "HISTORY", - "APPDATA", - "WINDIR", - "SYSDIR", - "PROGRAMFILES", - "PICTURES", - "PROFILE", - "", - "", - "COMMONFILES", - "", - "TEMPLATES", - "DOCUMENTS", - "ADMINTOOLS", - - "ADMINTOOLS", - "", - "", - "", - "", - "MUSIC", - "PICTURES", - "VIDEO", - "RESOURCES", - "RESOURCES_LOCALIZED", - "", - "CDBURN_AREA" + if (cmd < ARRAY_SIZE(kShowWindow_Commands)) + { + s += "SW_"; + s += kShowWindow_Commands[cmd]; + } + else + UIntToString(s, cmd); +} + +void CInArchive::Add_ShowWindow_Cmd(UInt32 cmd) +{ + if (cmd < ARRAY_SIZE(kShowWindow_Commands)) + { + Script += "SW_"; + Script += kShowWindow_Commands[cmd]; + } + else + Add_UInt(cmd); +} + +void CInArchive::Add_TypeFromList(const char **table, unsigned tableSize, UInt32 type) +{ + if (type < tableSize) + Script += table[type]; + else + { + Script += '_'; + Add_UInt(type); + } +} + +#define ADD_TYPE_FROM_LIST(table, type) Add_TypeFromList(table, ARRAY_SIZE(table), type) + +enum +{ + k_ExecFlags_AutoClose, + k_ExecFlags_ShellVarContext, + k_ExecFlags_Errors, + k_ExecFlags_Abort, + k_ExecFlags_RebootFlag, + k_ExecFlags_reboot_called, + k_ExecFlags_cur_insttype, + k_ExecFlags_plugin_api_version, + k_ExecFlags_Silent, + k_ExecFlags_InstDirError, + k_ExecFlags_rtl, + k_ExecFlags_ErrorLevel, + k_ExecFlags_RegView, + k_ExecFlags_DetailsPrint = 13, }; -static const int kNumShellStrings = sizeof(kShellStrings) / sizeof(kShellStrings[0]); +// Names for NSIS exec_flags_t structure vars +static const char *kExecFlags_VarsNames[] = +{ + "AutoClose" // autoclose; + , "ShellVarContext" // all_user_var; + , "Errors" // exec_error; + , "Abort" // abort; + , "RebootFlag" // exec_reboot; // NSIS_SUPPORT_REBOOT + , "reboot_called" // reboot_called; // NSIS_SUPPORT_REBOOT + , "cur_insttype" // XXX_cur_insttype; // depreacted + , "plugin_api_version" // plugin_api_version; // see NSISPIAPIVER_CURR + // used to be XXX_insttype_changed + , "Silent" // silent; // NSIS_CONFIG_SILENT_SUPPORT + , "InstDirError" // instdir_error; + , "rtl" // rtl; + , "ErrorLevel" // errlvl; + , "RegView" // alter_reg_view; + , "DetailsPrint" // status_update; +}; +void CInArchive::Add_ExecFlags(UInt32 flagsType) +{ + ADD_TYPE_FROM_LIST(kExecFlags_VarsNames, flagsType); +} + + +// ---------- Page ---------- + +// page flags +#define PF_CANCEL_ENABLE 4 +#define PF_LICENSE_FORCE_SELECTION 32 +#define PF_LICENSE_NO_FORCE_SELECTION 64 +#define PF_PAGE_EX 512 +#define PF_DIR_NO_BTN_DISABLE 1024 /* -# define CMDLINE 20 // everything before here doesn't have trailing slash removal -# define INSTDIR 21 -# define OUTDIR 22 -# define EXEDIR 23 -# define LANGUAGE 24 -# define TEMP 25 -# define PLUGINSDIR 26 -# define HWNDPARENT 27 -# define _CLICK 28 -# define _OUTDIR 29 +#define PF_LICENSE_SELECTED 1 +#define PF_NEXT_ENABLE 2 +#define PF_BACK_SHOW 8 +#define PF_LICENSE_STREAM 16 +#define PF_NO_NEXT_FOCUS 128 +#define PF_BACK_ENABLE 256 */ -static const char *kVarStrings[] = +// page window proc +enum +{ + PWP_LICENSE, + PWP_SELCOM, + PWP_DIR, + PWP_INSTFILES, + PWP_UNINST, + PWP_COMPLETED, + PWP_CUSTOM +}; + +static const char *kPageTypes[] = +{ + "license" + , "components" + , "directory" + , "instfiles" + , "uninstConfirm" + , "COMPLETED" + , "custom" +}; + +#define SET_FUNC_REF(x, flag) if ((Int32)(x) >= 0 && (x) < bh.Num) \ + { labels[x] = (labels[x] & ~CMD_REF_Page_Mask) | ((flag) | (pageIndex << CMD_REF_Page_NumShifts)); } + +// #define IDD_LICENSE 102 +#define IDD_LICENSE_FSRB 108 +#define IDD_LICENSE_FSCB 109 + +void CInArchive::AddPageOption1(UInt32 param, const char *name) +{ + if (param == 0) + return; + TabString(name); + AddParam(param); + NewLine(); +} + +void CInArchive::AddPageOption(const UInt32 *params, unsigned num, const char *name) +{ + num = GetNumParams(params, num); + if (num == 0) + return; + TabString(name); + AddParams(params, num); + NewLine(); +} + +void CInArchive::Separator() +{ + AddLF(); + AddCommentAndString("--------------------"); + AddLF(); +} + +void CInArchive::Space() +{ + Script += ' '; +} + +void CInArchive::Tab() +{ + Script += " "; +} + +void CInArchive::Tab(bool commented) +{ + Script += commented ? " ; " : " "; +} + +void CInArchive::BigSpaceComment() +{ + Script += " ; "; +} + +void CInArchive::SmallSpaceComment() +{ + Script += " ; "; +} + +void CInArchive::AddCommentAndString(const char *s) +{ + Script += "; "; + Script += s; +} + +void CInArchive::AddError(const char *s) +{ + BigSpaceComment(); + Script += "!!! ERROR: "; + Script += s; +} + +void CInArchive::AddErrorLF(const char *s) +{ + AddError(s); + AddLF(); +} + +void CInArchive::CommentOpen() +{ + AddStringLF("/*"); +} + +void CInArchive::CommentClose() +{ + AddStringLF("*/"); +} + +void CInArchive::AddLF() +{ + Script += CR_LF; +} + +void CInArchive::AddQuotes() +{ + Script += "\"\""; +} + +void CInArchive::TabString(const char *s) +{ + Tab(); + Script += s; +} + +void CInArchive::AddStringLF(const char *s) +{ + Script += s; + AddLF(); +} + +// ---------- Section ---------- + +static const char *kSection_VarsNames[] = { - "CMDLINE", - "INSTDIR", - "OUTDIR", - "EXEDIR", - "LANGUAGE", - "TEMP", - "PLUGINSDIR", - "EXEPATH", // test it - "EXEFILE", // test it - "HWNDPARENT", - "_CLICK", - "_OUTDIR" + "Text" + , "InstTypes" + , "Flags" + , "Code" + , "CodeSize" + , "Size" // size in KB }; -static const int kNumVarStrings = sizeof(kVarStrings) / sizeof(kVarStrings[0]); +void CInArchive::Add_SectOp(UInt32 opType) +{ + ADD_TYPE_FROM_LIST(kSection_VarsNames, opType); +} + +void CSection::Parse(const Byte *p) +{ + Name = Get32(p); + InstallTypes = Get32(p + 4); + Flags = Get32(p + 8); + StartCmdIndex = Get32(p + 12); + NumCommands = Get32(p + 16); + SizeKB = Get32(p + 20); +}; +// used for section->flags +#define SF_SELECTED (1 << 0) +#define SF_SECGRP (1 << 1) +#define SF_SECGRPEND (1 << 2) +#define SF_BOLD (1 << 3) +#define SF_RO (1 << 4) +#define SF_EXPAND (1 << 5) +#define SF_PSELECTED (1 << 6) +#define SF_TOGGLED (1 << 7) +#define SF_NAMECHG (1 << 8) -static AString GetVar(UInt32 index) +bool CInArchive::PrintSectionBegin(const CSection §, unsigned index) { - AString res = "$"; - if (index < 10) - res += UIntToString(index); - else if (index < 20) + AString name; + if (sect.Flags & SF_BOLD) + name += '!'; + AString s2; + ReadString2(s2, sect.Name); + if (!IsInstaller) { - res += "R"; - res += UIntToString(index - 10); + if (!StringsAreEqualNoCase_Ascii(s2, "uninstall")) + name += "un."; } - else if (index < 20 + kNumVarStrings) - res += kVarStrings[index - 20]; + name += s2; + + if (sect.Flags & SF_SECGRPEND) + { + AddStringLF("SectionGroupEnd"); + return true; + } + + if (sect.Flags & SF_SECGRP) + { + Script += "SectionGroup"; + if (sect.Flags & SF_EXPAND) + Script += " /e"; + SpaceQuStr(name); + Script += " ; Section"; + AddParam_UInt(index); + NewLine(); + return true; + } + + Script += "Section"; + if ((sect.Flags & SF_SELECTED) == 0) + Script += " /o"; + if (!name.IsEmpty()) + SpaceQuStr(name); + + /* + if (!name.IsEmpty()) + Script += ' '; else + */ + SmallSpaceComment(); + Script += "Section_"; + Add_UInt(index); + + /* + Script += " ; flags = "; + Add_Hex(Script, sect.Flags); + */ + + NewLine(); + + if (sect.SizeKB != 0) { - res += "["; - res += UIntToString(index); - res += "]"; + // probably we must show AddSize, only if there is additional size. + Tab(); + AddCommentAndString("AddSize"); + AddParam_UInt(sect.SizeKB); + AddLF(); } - return res; + + bool needSectionIn = + (sect.Name != 0 && sect.InstallTypes != 0) || + (sect.Name == 0 && sect.InstallTypes != 0xFFFFFFFF); + if (needSectionIn || (sect.Flags & SF_RO) != 0) + { + TabString("SectionIn"); + UInt32 instTypes = sect.InstallTypes; + for (int i = 0; i < 32; i++, instTypes >>= 1) + if ((instTypes & 1) != 0) + { + AddParam_UInt(i + 1); + } + if ((sect.Flags & SF_RO) != 0) + Script += " RO"; + AddLF(); + } + return false; } -#define NS_SKIP_CODE 252 -#define NS_VAR_CODE 253 -#define NS_SHELL_CODE 254 -#define NS_LANG_CODE 255 -#define NS_CODES_START NS_SKIP_CODE +void CInArchive::PrintSectionEnd() +{ + AddStringLF("SectionEnd"); + AddLF(); +} + +// static const unsigned kOnFuncShift = 4; -static AString GetShellString(int index) +void CInArchive::ClearLangComment() { - AString res = "$"; - if (index < kNumShellStrings) + langStrIDs.Clear(); +} + +void CInArchive::PrintNumComment(const char *name, UInt32 value) +{ + // size_t len = Script.Len(); + AddCommentAndString(name); + Script += ": "; + Add_UInt(value); + AddLF(); + /* + len = Script.Len() - len; + char sz[16]; + ConvertUInt32ToString(value, sz); + len += MyStringLen(sz); + for (; len < 20; len++) + Space(); + AddStringLF(sz); + */ +} + + +void CInArchive::NewLine() +{ + if (!langStrIDs.IsEmpty()) { - const char *sz = kShellStrings[index]; - if (sz[0] != 0) - return res + sz; + BigSpaceComment(); + for (unsigned i = 0; i < langStrIDs.Size() && i < 20; i++) + { + /* + if (i != 0) + Script += ' '; + */ + UInt32 langStr = langStrIDs[i]; + if (langStr >= _numLangStrings) + { + AddError("langStr"); + break; + } + UInt32 param = Get32(_mainLang + langStr * 4); + if (param != 0) + AddParam(param); + } + ClearLangComment(); } - res += "SHELL["; - res += UIntToString(index); - res += "]"; - return res; + AddLF(); } -// Based on Dave Laundon's simplified process_string -AString GetNsisString(const AString &s) +static const UInt32 kPageSize = 16 * 4; + +static const char *k_SetOverwrite_Modes[] = +{ + "on" + , "off" + , "try" + , "ifnewer" + , "ifdiff" + // "lastused" +}; + + +void CInArchive::MessageBox_MB_Part(UInt32 param) { - AString res; - for (int i = 0; i < s.Length();) { - unsigned char nVarIdx = s[i++]; - if (nVarIdx > NS_CODES_START && i + 2 <= s.Length()) + UInt32 v = param & 0xF; + Script += " MB_"; + if (v < ARRAY_SIZE(k_MB_Buttons)) + Script += k_MB_Buttons[v]; + else { - int nData = s[i++] & 0x7F; - unsigned char c1 = s[i++]; - nData |= (((int)(c1 & 0x7F)) << 7); + Script += "Buttons_"; + Add_UInt(v); + } + } + { + UInt32 icon = (param >> 4) & 0x7; + if (icon != 0) + { + Script += "|MB_"; + if (icon < ARRAY_SIZE(k_MB_Icons) && k_MB_Icons[icon] != 0) + Script += k_MB_Icons[icon]; + else + { + Script += "Icon_"; + Add_UInt(icon); + } + } + } + if ((param & 0x80) != 0) + Script += "|MB_USERICON"; + { + UInt32 defButton = (param >> 8) & 0xF; + if (defButton != 0) + { + Script += "|MB_DEFBUTTON"; + Add_UInt(defButton + 1); + } + } + { + UInt32 modal = (param >> 12) & 0x3; + if (modal == 1) Script += "|MB_SYSTEMMODAL"; + else if (modal == 2) Script += "|MB_TASKMODAL"; + else if (modal == 3) Script += "|0x3000"; + UInt32 flags = (param >> 14); + for (int i = 0; i < ARRAY_SIZE(k_MB_Flags); i++) + if ((flags & (1 << i)) != 0) + { + Script += "|MB_"; + Script += k_MB_Flags[i]; + } + } +} + +#define GET_CMD_PARAM(ppp, index) Get32((ppp) + 4 + (index) * 4) + +static const Byte k_InitPluginDir_Commands[] = + { 13, 26, 31, 13, 19, 21, 11, 14, 25, 31, 1, 22, 4, 1 }; + +bool CInArchive::CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands) +{ + for (UInt32 kkk = 0; kkk < numCommands; kkk++, rawCmds += kCmdSize) + if (GetCmd(Get32(rawCmds)) != sequence[kkk]) + return false; + return true; +} + +#endif + +static const UInt32 kSectionSize_base = 6 * 4; +static const UInt32 kSectionSize_8bit = kSectionSize_base + 1024; +static const UInt32 kSectionSize_16bit = kSectionSize_base + 1024 * 2; +static const UInt32 kSectionSize_16bit_Big = kSectionSize_base + 8196 * 2; +// 8196 is default string length in NSIS-Unicode since 2.37.3 + + +static void AddString(AString &dest, const char *src) +{ + if (!dest.IsEmpty()) + dest += ' '; + dest += src; +} + +AString CInArchive::GetFormatDescription() const +{ + AString s = "NSIS-"; + char c; + if (IsPark()) + { + s += "Park-"; + c = '1'; + if (NsisType == k_NsisType_Park2) c = '2'; + else if (NsisType == k_NsisType_Park3) c = '3'; + } + else + { + c = '2'; + if (NsisType == k_NsisType_Nsis3) + c = '3'; + } + s += c; + if (IsNsis200) + s += ".00"; + else if (IsNsis225) + s += ".25"; + + if (IsUnicode) + AddString(s, "Unicode"); + if (LogCmdIsEnabled) + AddString(s, "log"); + if (BadCmd >= 0) + { + AddString(s, "BadCmd="); + UIntToString(s, BadCmd); + } + return s; +} + +#ifdef NSIS_SCRIPT + +unsigned CInArchive::GetNumSupportedCommands() const +{ + unsigned numCmds = IsPark() ? kNumCmds : kNumCmds - kNumAdditionalParkCmds; + if (!LogCmdIsEnabled) + numCmds--; + if (!IsUnicode) + numCmds -= 2; + return numCmds; +} + +#endif + +UInt32 CInArchive::GetCmd(UInt32 a) +{ + if (!IsPark()) + { + if (!LogCmdIsEnabled) + return a; + if (a < EW_SECTIONSET) + return a; + if (a == EW_SECTIONSET) + return EW_LOG; + return a - 1; + } - if (nVarIdx == NS_SHELL_CODE) - res += GetShellString(c1); - else if (nVarIdx == NS_VAR_CODE) - res += GetVar(nData); - else if (nVarIdx == NS_LANG_CODE) - res += "NS_LANG_CODE"; + if (a < EW_REGISTERDLL) + return a; + if (NsisType >= k_NsisType_Park2) + { + if (a == EW_REGISTERDLL) return EW_GETFONTVERSION; + a--; + } + if (NsisType >= k_NsisType_Park3) + { + if (a == EW_REGISTERDLL) return EW_GETFONTNAME; + a--; + } + if (a >= EW_FSEEK) + { + if (IsUnicode) + { + if (a == EW_FSEEK) return EW_FPUTWS; + if (a == EW_FSEEK + 1) return EW_FPUTWS + 1; + a -= 2; } - else if (nVarIdx == NS_SKIP_CODE) + + if (a >= EW_SECTIONSET && LogCmdIsEnabled) { - if (i < s.Length()) - res += s[i++]; + if (a == EW_SECTIONSET) + return EW_LOG; + return a - 1; } - else // Normal char - res += (char)nVarIdx; + if (a == EW_FPUTWS) + return EW_FINDPROC; + // if (a > EW_FPUTWS) return 0; } - return res; + return a; } -UString GetNsisString(const UString &s) +void CInArchive::FindBadCmd(const CBlockHeader &bh, const Byte *p) { - UString res; - for (int i = 0; i < s.Length();) + BadCmd = -1; + + for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) { - wchar_t nVarIdx = s[i++]; - if (nVarIdx > NS_UN_CODES_START && nVarIdx <= NS_UN_CODES_END) + UInt32 id = GetCmd(Get32(p)); + if (id >= kNumCmds) + continue; + if (BadCmd >= 0 && id >= (unsigned)BadCmd) + continue; + unsigned i; + if (id == EW_GETLABELADDR || + id == EW_GETFUNCTIONADDR) { - if (i == s.Length()) + BadCmd = id; + continue; + } + for (i = 6; i != 0; i--) + { + UInt32 param = Get32(p + i * 4); + if (param != 0) break; - int nData = s[i++] & 0x7FFF; + } + if (id == EW_FINDPROC && i == 0) + { + BadCmd = id; + continue; + } + if (k_Commands[id].NumParams < i) + BadCmd = id; + } +} - if (nVarIdx == NS_UN_SHELL_CODE) - res += GetUnicodeString(GetShellString(nData >> 8)); - else if (nVarIdx == NS_UN_VAR_CODE) - res += GetUnicodeString(GetVar(nData)); - else if (nVarIdx == NS_UN_LANG_CODE) - res += L"NS_LANG_CODE"; +/* We calculate the number of parameters in commands to detect + layout of commands. It's not very good way. + If you know simpler and more robust way to detect Version and layout, + please write to 7-Zip forum */ + +void CInArchive::DetectNsisType(const CBlockHeader &bh, const Byte *p) +{ + bool strongPark = false; + bool strongNsis = false; + + { + const Byte *strData = _data + _stringsPos; + if (IsUnicode) + { + UInt32 num = NumStringChars; + for (UInt32 i = 0; i < num; i++) + { + if (Get16(strData + i * 2) == 0) + { + unsigned c2 = Get16(strData + 2 + i * 2); + // if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL) + if (c2 == NS_3_CODE_VAR) + { + // it can be TXT/RTF string with marker char (1 or 2). so we must next char + // const wchar_t *p2 = (const wchar_t *)(strData + i * 2 + 2); + // p2 = p2; + if ((Get16(strData + 3 + i * 2) & 0x8000) != 0) + { + NsisType = k_NsisType_Nsis3; + strongNsis = true; + break; + } + } + } + } + if (!strongNsis) + { + NsisType = k_NsisType_Park1; + strongPark = true; + } } - else if (nVarIdx == NS_UN_SKIP_CODE) + else { - if (i == s.Length()) - break; - res += s[i++]; + UInt32 num = NumStringChars; + for (UInt32 i = 0; i < num; i++) + { + if (strData[i] == 0) + { + Byte c2 = strData[i + 1]; + // it can be TXT/RTF with marker char (1 or 2). so we must check next char + // for marker=1 (txt) + if (c2 == NS_3_CODE_VAR) + // if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL && c2 != 1) + { + if ((strData[i+ 2] & 0x80) != 0) + { + // const char *p2 = (const char *)(strData + i + 1); + // p2 = p2; + NsisType = k_NsisType_Nsis3; + strongNsis = true; + break; + } + } + } + } + } + } + + if (NsisType == k_NsisType_Nsis2 && !IsUnicode) + { + const Byte *p2 = p; + + for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p2 += kCmdSize) + { + UInt32 cmd = GetCmd(Get32(p2)); + if (cmd != EW_GETDLGITEM && + cmd != EW_ASSIGNVAR) + continue; + + UInt32 params[kNumCommandParams]; + for (unsigned i = 0; i < kNumCommandParams; i++) + params[i] = Get32(p2 + 4 + 4 * i); + + if (cmd == EW_GETDLGITEM) + { + // we can use also EW_SETCTLCOLORS + if (IsVarStr(params[1], kVar_HWNDPARENT_225)) + { + IsNsis225 = true; + if (params[0] == kVar_Spec_OUTDIR_225) + { + IsNsis200 = true; + break; + } + } + } + else // if (cmd == EW_ASSIGNVAR) + { + if (params[0] == kVar_Spec_OUTDIR_225 && + params[2] == 0 && + params[3] == 0 && + IsVarStr(params[1], kVar_OUTDIR)) + IsNsis225 = true; + } + } + } + + bool parkVer_WasDetected = false; + + if (!strongNsis && !IsNsis225 && !IsNsis200) + { + // it must be before FindBadCmd(bh, p); + unsigned mask = 0; + + unsigned numInsertMax = IsUnicode ? 4 : 2; + + const Byte *p2 = p; + + for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p2 += kCmdSize) + { + UInt32 cmd = Get32(p2); // we use original (not converted) command + + if (cmd < EW_WRITEUNINSTALLER || + cmd > EW_WRITEUNINSTALLER + numInsertMax) + continue; + + UInt32 params[kNumCommandParams]; + for (unsigned i = 0; i < kNumCommandParams; i++) + params[i] = Get32(p2 + 4 + 4 * i); + + if (params[4] != 0 || + params[5] != 0 || + params[0] <= 1 || + params[3] <= 1) + continue; + + UInt32 altParam = params[3]; + if (!IsGoodString(params[0]) || + !IsGoodString(altParam)) + continue; + + UInt32 additional = 0; + if (GetVarIndexFinished(altParam, '\\', additional) != kVar_INSTDIR) + continue; + if (AreTwoParamStringsEqual(altParam + additional, params[0])) + { + unsigned numInserts = cmd - EW_WRITEUNINSTALLER; + mask |= (1 << numInserts); + } + } + + if (mask == 1) + { + parkVer_WasDetected = true; // it can be original NSIS or Park-1 + } + else if (mask != 0) + { + ENsisType newType = NsisType; + if (IsUnicode) + switch (mask) + { + case (1 << 3): newType = k_NsisType_Park2; break; + case (1 << 4): newType = k_NsisType_Park3; break; + } + else + switch (mask) + { + case (1 << 1): newType = k_NsisType_Park2; break; + case (1 << 2): newType = k_NsisType_Park3; break; + } + if (newType != NsisType) + { + parkVer_WasDetected = true; + NsisType = newType; + } + } + } + + FindBadCmd(bh, p); + + /* + if (strongNsis) + return; + */ + + if (BadCmd < EW_REGISTERDLL) + return; + + /* + // in ANSI archive we don't check Park and log version + if (!IsUnicode) + return; + */ + + // We can support Park-ANSI archives, if we remove if (strongPark) check + if (strongPark && !parkVer_WasDetected) + { + if (BadCmd < EW_SECTIONSET) + { + NsisType = k_NsisType_Park3; + LogCmdIsEnabled = true; // version 3 is provided with log enabled + FindBadCmd(bh, p); + if (BadCmd > 0 && BadCmd < EW_SECTIONSET) + { + NsisType = k_NsisType_Park2; + LogCmdIsEnabled = false; + FindBadCmd(bh, p); + if (BadCmd > 0 && BadCmd < EW_SECTIONSET) + { + NsisType = k_NsisType_Park1; + FindBadCmd(bh, p); + } + } + } + } + + if (BadCmd >= EW_SECTIONSET) + { + LogCmdIsEnabled = !LogCmdIsEnabled; + FindBadCmd(bh, p); + if (BadCmd >= EW_SECTIONSET && LogCmdIsEnabled) + { + LogCmdIsEnabled = false; + FindBadCmd(bh, p); } - else // Normal char - res += (char)nVarIdx; } - return res; } -AString CInArchive::ReadString2A(UInt32 pos) const +Int32 CInArchive::GetVarIndex(UInt32 strPos) const { - return GetNsisString(ReadStringA(pos)); + if (strPos >= NumStringChars) + return -1; + + if (IsUnicode) + { + if (NumStringChars - strPos < 3 * 2) + return -1; + const Byte *p = _data + _stringsPos + strPos * 2; + unsigned code = Get16(p); + if (IsPark()) + { + if (code != PARK_CODE_VAR) + return -1; + UInt32 n = Get16(p + 2); + if (n == 0) + return -1; + CONVERT_NUMBER_PARK(n); + return (Int32)n; + } + + // NSIS-3 + { + if (code != NS_3_CODE_VAR) + return -1; + UInt32 n = Get16(p + 2); + if (n == 0) + return -1; + CONVERT_NUMBER_NS_3_UNICODE(n); + return (Int32)n; + } + } + + if (NumStringChars - strPos < 4) + return -1; + + const Byte *p = _data + _stringsPos + strPos; + unsigned c = *p; + if (NsisType == k_NsisType_Nsis3) + { + if (c != NS_3_CODE_VAR) + return -1; + } + else if (c != NS_CODE_VAR) + return -1; + + unsigned c0 = p[1]; + if (c0 == 0) + return -1; + unsigned c1 = p[2]; + if (c1 == 0) + return -1; + return DECODE_NUMBER_FROM_2_CHARS(c0, c1); } -UString CInArchive::ReadString2U(UInt32 pos) const +Int32 CInArchive::GetVarIndex(UInt32 strPos, UInt32 &resOffset) const { - return GetNsisString(ReadStringU(pos)); + resOffset = 0; + Int32 varIndex = GetVarIndex(strPos); + if (varIndex < 0) + return varIndex; + if (IsUnicode) + { + if (NumStringChars - strPos < 2 * 2) + return -1; + resOffset = 2; + } + else + { + if (NumStringChars - strPos < 3) + return -1; + resOffset = 3; + } + return varIndex; } -AString CInArchive::ReadString2(UInt32 pos) const +Int32 CInArchive::GetVarIndexFinished(UInt32 strPos, Byte endChar, UInt32 &resOffset) const { + resOffset = 0; + Int32 varIndex = GetVarIndex(strPos); + if (varIndex < 0) + return varIndex; if (IsUnicode) - return UnicodeStringToMultiByte(ReadString2U(pos)); + { + if (NumStringChars - strPos < 3 * 2) + return -1; + const Byte *p = _data + _stringsPos + strPos * 2; + if (Get16(p + 4) != endChar) + return -1; + resOffset = 3; + } else - return ReadString2A(pos); + { + if (NumStringChars - strPos < 4) + return -1; + const Byte *p = _data + _stringsPos + strPos; + if (p[3] != endChar) + return -1; + resOffset = 4; + } + return varIndex; } -AString CInArchive::ReadString2Qw(UInt32 pos) const +bool CInArchive::IsVarStr(UInt32 strPos, UInt32 varIndex) const { - return "\"" + ReadString2(pos) + "\""; + if (varIndex > (UInt32)0x7FFF) + return false; + UInt32 resOffset; + return GetVarIndexFinished(strPos, 0, resOffset) == (Int32)varIndex; } -#define DEL_DIR 1 -#define DEL_RECURSE 2 -#define DEL_REBOOT 4 -// #define DEL_SIMPLE 8 +bool CInArchive::IsAbsolutePathVar(UInt32 strPos) const +{ + Int32 varIndex = GetVarIndex(strPos); + if (varIndex < 0) + return false; + switch (varIndex) + { + case kVar_INSTDIR: + case kVar_EXEDIR: + case kVar_TEMP: + case kVar_PLUGINSDIR: + return true; + } + return false; +} + +#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') -static const int kNumEntryParams = 6; +// We use same check as in NSIS decoder +bool IsDrivePath(const wchar_t *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; } +bool IsDrivePath(const char *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; } + +static bool IsAbsolutePath(const wchar_t *s) +{ + return + s[0] == WCHAR_PATH_SEPARATOR && + s[1] == WCHAR_PATH_SEPARATOR || + IsDrivePath(s); +} + +static bool IsAbsolutePath(const char *s) +{ + return + s[0] == CHAR_PATH_SEPARATOR && + s[1] == CHAR_PATH_SEPARATOR || + IsDrivePath(s); +} -struct CEntry +void CInArchive::SetItemName(CItem &item, UInt32 strPos) { - UInt32 Which; - UInt32 Params[kNumEntryParams]; - AString GetParamsString(int numParams); - CEntry() + ReadString2_Raw(strPos); + bool isAbs = IsAbsolutePathVar(strPos); + if (IsUnicode) { - Which = 0; - for (UInt32 j = 0; j < kNumEntryParams; j++) - Params[j] = 0; + item.NameU = Raw_UString; + if (!isAbs && !IsAbsolutePath(Raw_UString)) + item.Prefix = UPrefixes.Size() - 1; } -}; + else + { + item.NameA = Raw_AString; + if (!isAbs && !IsAbsolutePath(Raw_AString)) + item.Prefix = APrefixes.Size() - 1; + } +} -AString CEntry::GetParamsString(int numParams) +HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) { - AString s; - for (int i = 0; i < numParams; i++) + #ifdef NSIS_SCRIPT + CDynLimBuf &s = Script; + + CObjArray<UInt32> labels; + labels.Alloc(bh.Num); + memset(labels, 0, bh.Num * sizeof(UInt32)); + { - s += " "; - UInt32 v = Params[i]; - if (v > 0xFFF00000) - s += IntToString((Int32)Params[i]); + const Byte *p = _data; + UInt32 i; + for (i = 0; i < numOnFunc; i++) + { + UInt32 func = Get32(p + onFuncOffset + 4 * i); + if (func < bh.Num) + labels[func] = (labels[func] & ~CMD_REF_OnFunc_Mask) | (CMD_REF_OnFunc | (i << CMD_REF_OnFunc_NumShifts)); + } + } + + /* + { + for (int i = 0; i < OnFuncs.Size(); i++) + { + UInt32 address = OnFuncs[i] >> kOnFuncShift; + if (address < bh.Num) + } + } + */ + + if (bhPages.Num != 0) + { + Separator(); + PrintNumComment("PAGES", bhPages.Num); + + if (bhPages.Num > (1 << 12) + || bhPages.Offset > _size + || bhPages.Num * kPageSize > _size - bhPages.Offset) + { + AddErrorLF("Pages error"); + } else - s += UIntToString(Params[i]); + { + + AddLF(); + const Byte *p = _data + bhPages.Offset; + + for (UInt32 pageIndex = 0; pageIndex < bhPages.Num; pageIndex++, p += kPageSize) + { + UInt32 dlgID = Get32(p); + UInt32 wndProcID = Get32(p + 4); + UInt32 preFunc = Get32(p + 8); + UInt32 showFunc = Get32(p + 12); + UInt32 leaveFunc = Get32(p + 16); + UInt32 flags = Get32(p + 20); + UInt32 caption = Get32(p + 24); + // UInt32 back = Get32(p + 28); + UInt32 next = Get32(p + 32); + // UInt32 clickNext = Get32(p + 36); + // UInt32 cancel = Get32(p + 40); + UInt32 params[5]; + for (int i = 0; i < 5; i++) + params[i] = Get32(p + 44 + 4 * i); + + SET_FUNC_REF(preFunc, CMD_REF_Pre); + SET_FUNC_REF(showFunc, CMD_REF_Show); + SET_FUNC_REF(leaveFunc, CMD_REF_Leave); + + if (wndProcID == PWP_COMPLETED) + CommentOpen(); + + AddCommentAndString("Page "); + Add_UInt(pageIndex); + AddLF(); + + if (flags & PF_PAGE_EX) + { + s += "PageEx "; + if (!IsInstaller) + s += "un."; + } + else + s += IsInstaller ? "Page " : "UninstPage "; + + if (wndProcID < ARRAY_SIZE(kPageTypes)) + s += kPageTypes[wndProcID]; + else + Add_UInt(wndProcID); + + + bool needCallbacks = ( + (Int32)preFunc >= 0 || + (Int32)showFunc >= 0 || + (Int32)leaveFunc >= 0); + + if (flags & PF_PAGE_EX) + { + AddLF(); + if (needCallbacks) + TabString("PageCallbacks"); + } + + if (needCallbacks) + { + AddParam_Func(labels, preFunc); // it's creator_function for PWP_CUSTOM + if (wndProcID != PWP_CUSTOM) + { + AddParam_Func(labels, showFunc); + } + AddParam_Func(labels, leaveFunc); + } + + if ((flags & PF_PAGE_EX) == 0) + { + // AddOptionalParam(caption); + if (flags & PF_CANCEL_ENABLE) + s += " /ENABLECANCEL"; + AddLF(); + } + else + { + AddLF(); + AddPageOption1(caption, "Caption"); + } + + if (wndProcID == PWP_LICENSE) + { + if ((flags & PF_LICENSE_NO_FORCE_SELECTION) != 0 || + (flags & PF_LICENSE_FORCE_SELECTION) != 0) + { + TabString("LicenseForceSelection "); + if (flags & PF_LICENSE_NO_FORCE_SELECTION) + s += "off"; + else + { + if (dlgID == IDD_LICENSE_FSCB) + s += "checkbox"; + else if (dlgID == IDD_LICENSE_FSRB) + s += "radiobuttons"; + else + Add_UInt(dlgID); + AddOptionalParams(params + 2, 2); + } + NewLine(); + } + + if (params[0] != 0 || next != 0) + { + TabString("LicenseText"); + AddParam(params[0]); + AddOptionalParam(next); + NewLine(); + } + if (params[1] != 0) + { + TabString("LicenseData"); + if ((Int32)params[1] < 0) + AddParam(params[1]); + else + AddLicense(params[1], -1); + ClearLangComment(); + NewLine(); + } + } + else if (wndProcID == PWP_SELCOM) + AddPageOption(params, 3, "ComponentsText"); + else if (wndProcID == PWP_DIR) + { + AddPageOption(params, 4, "DirText"); + if (params[4] != 0) + { + TabString("DirVar"); + AddParam_Var(params[4] - 1); + AddLF(); + } + if (flags & PF_DIR_NO_BTN_DISABLE) + { + TabString("DirVerify leave"); + AddLF(); + } + + } + else if (wndProcID == PWP_INSTFILES) + { + AddPageOption1(params[2], "CompletedText"); + AddPageOption1(params[1], "DetailsButtonText"); + } + else if (wndProcID == PWP_UNINST) + { + if (params[4] != 0) + { + TabString("DirVar"); + AddParam_Var(params[4] - 1); + AddLF(); + } + AddPageOption(params, 2, "UninstallText"); + } + + if (flags & PF_PAGE_EX) + { + s += "PageExEnd"; + NewLine(); + } + if (wndProcID == PWP_COMPLETED) + CommentClose(); + NewLine(); + } + } } - return s; -} -#ifdef NSIS_SCRIPT + CObjArray<CSection> Sections; -static AString GetRegRootID(UInt32 val) -{ - const char *s; - switch(val) { - case 0: s = "SHCTX"; break; - case 0x80000000: s = "HKCR"; break; - case 0x80000001: s = "HKCU"; break; - case 0x80000002: s = "HKLM"; break; - case 0x80000003: s = "HKU"; break; - case 0x80000004: s = "HKPD"; break; - case 0x80000005: s = "HKCC"; break; - case 0x80000006: s = "HKDD"; break; - case 0x80000050: s = "HKPT"; break; - case 0x80000060: s = "HKPN"; break; - default: - return UIntToString(val); break; + Separator(); + PrintNumComment("SECTIONS", bhSections.Num); + PrintNumComment("COMMANDS", bh.Num); + AddLF(); + + if (bhSections.Num > (1 << 15) + // || bhSections.Offset > _size + // || (bhSections.Num * SectionSize > _size - bhSections.Offset) + ) + { + AddErrorLF("Sections error"); + } + else if (bhSections.Num != 0) + { + Sections.Alloc((unsigned)bhSections.Num); + const Byte *p = _data + bhSections.Offset; + for (UInt32 i = 0; i < bhSections.Num; i++, p += SectionSize) + { + CSection §ion = Sections[i]; + section.Parse(p); + if (section.StartCmdIndex < bh.Num) + labels[section.StartCmdIndex] |= CMD_REF_Section; + } + } } - return s; -} -#endif + #endif -HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) -{ - _posInData = bh.Offset + GetOffset(); - AString prefixA; - UString prefixU; - for (UInt32 i = 0; i < bh.Num; i++) + const Byte *p; + UInt32 kkk; + + #ifdef NSIS_SCRIPT + + p = _data + bh.Offset; + + for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) + { + UInt32 commandId = GetCmd(Get32(p)); + UInt32 mask; + switch (commandId) + { + case EW_NOP: mask = 1 << 0; break; + case EW_IFFILEEXISTS: mask = 3 << 1; break; + case EW_IFFLAG: mask = 3 << 0; break; + case EW_MESSAGEBOX: mask = 5 << 3; break; + case EW_STRCMP: mask = 3 << 2; break; + case EW_INTCMP: mask = 7 << 2; break; + case EW_ISWINDOW: mask = 3 << 1; break; + case EW_CALL: + { + if (Get32(p + 4 + 4) == 1) // it's Call :Label + { + mask = 1 << 0; + break; + } + UInt32 param0 = Get32(p + 4); + if ((Int32)param0 > 0) + labels[param0 - 1] |= CMD_REF_Call; + continue; + } + default: continue; + } + for (int i = 0; mask != 0; i++, mask >>= 1) + if (mask & 1) + { + UInt32 param = Get32(p + 4 + 4 * i); + if ((Int32)param > 0 && (Int32)param <= (Int32)bh.Num) + labels[param - 1] |= CMD_REF_Goto; + } + } + + int InitPluginsDir_Start = -1; + int InitPluginsDir_End = -1; + p = _data + bh.Offset; + for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) + { + UInt32 flg = labels[kkk]; + /* + if (IsFunc(flg)) + { + AddLF(); + for (int i = 0; i < 14; i++) + { + UInt32 commandId = GetCmd(Get32(p + kCmdSize * i)); + s += ", "; + UIntToString(s, commandId); + } + AddLF(); + } + */ + if (IsFunc(flg) + && bh.Num - kkk >= ARRAY_SIZE(k_InitPluginDir_Commands) + && CompareCommands(p, k_InitPluginDir_Commands, ARRAY_SIZE(k_InitPluginDir_Commands))) + { + InitPluginsDir_Start = kkk; + InitPluginsDir_End = kkk + ARRAY_SIZE(k_InitPluginDir_Commands); + labels[kkk] |= CMD_REF_InitPluginDir; + break; + } + } + + #endif + + // AString prefixA_Temp; + // UString prefixU_Temp; + + + // const UInt32 kFindS = 158; + + #ifdef NSIS_SCRIPT + + UInt32 curSectionIndex = 0; + // UInt32 lastSectionEndCmd = 0xFFFFFFFF; + bool sectionIsOpen = false; + // int curOnFunc = 0; + bool onFuncIsOpen = false; + + /* + for (unsigned yyy = 0; yyy + 3 < _data.Size(); yyy++) + { + UInt32 val = Get32(_data + yyy); + if (val == kFindS) + val = val; + } + */ + + UInt32 overwrite_State = 0; // "SetOverwrite on" + Int32 allowSkipFiles_State = -1; // -1: on, -2: off, >=0 : RAW value + UInt32 endCommentIndex = 0; + + unsigned numSupportedCommands = GetNumSupportedCommands(); + + #endif + + p = _data + bh.Offset; + + UString spec_outdir_U; + AString spec_outdir_A; + + UPrefixes.Add(L"$INSTDIR"); + APrefixes.Add("$INSTDIR"); + + p = _data + bh.Offset; + + unsigned spec_outdir_VarIndex = IsNsis225 ? + kVar_Spec_OUTDIR_225 : + kVar_Spec_OUTDIR; + + for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) { - CEntry e; - e.Which = ReadUInt32(); - for (UInt32 j = 0; j < kNumEntryParams; j++) - e.Params[j] = ReadUInt32(); + UInt32 commandId; + UInt32 params[kNumCommandParams]; + commandId = GetCmd(Get32(p)); + { + for (unsigned i = 0; i < kNumCommandParams; i++) + { + params[i] = Get32(p + 4 + 4 * i); + /* + if (params[i] == kFindS) + i = i; + */ + } + } + #ifdef NSIS_SCRIPT - if (e.Which != EW_PUSHPOP && e.Which < sizeof(kCommandPairs) / sizeof(kCommandPairs[0])) + + bool IsSectionGroup = false; + while (curSectionIndex < bhSections.Num) { - const CCommandPair &pair = kCommandPairs[e.Which]; - Script += pair.Name; + const CSection § = Sections[curSectionIndex]; + if (sectionIsOpen) + { + if (sect.StartCmdIndex + sect.NumCommands + 1 != kkk) + break; + PrintSectionEnd(); + sectionIsOpen = false; + // lastSectionEndCmd = kkk; + curSectionIndex++; + continue; + } + if (sect.StartCmdIndex != kkk) + break; + if (PrintSectionBegin(sect, curSectionIndex)) + { + IsSectionGroup = true; + curSectionIndex++; + // do we need to flush prefixes in new section? + // FlushOutPathPrefixes(); + } + else + sectionIsOpen = true; } + + /* + if (curOnFunc < OnFuncs.Size()) + { + if ((OnFuncs[curOnFunc] >> kOnFuncShift) == kkk) + { + s += "Function .on"; + s += kOnFunc[OnFuncs[curOnFunc++] & ((1 << kOnFuncShift) - 1)]; + AddLF(); + onFuncIsOpen = true; + } + } + */ + + if (labels[kkk] != 0 && labels[kkk] != CMD_REF_Section) + { + UInt32 flg = labels[kkk]; + if (IsFunc(flg)) + { + if ((int)kkk == InitPluginsDir_Start) + CommentOpen(); + + onFuncIsOpen = true; + s += "Function "; + Add_FuncName(labels, kkk); + if (IsPageFunc(flg)) + { + BigSpaceComment(); + s += "Page "; + Add_UInt((flg & CMD_REF_Page_Mask) >> CMD_REF_Page_NumShifts); + // if (flg & CMD_REF_Creator) s += ", Creator"; + if (flg & CMD_REF_Leave) s += ", Leave"; + if (flg & CMD_REF_Pre) s += ", Pre"; + if (flg & CMD_REF_Show) s += ", Show"; + } + AddLF(); + } + if (flg & CMD_REF_Goto) + { + Add_LabelName(kkk); + s += ':'; + AddLF(); + } + } + + if (commandId != EW_RET) + { + Tab(kkk < endCommentIndex); + } + + /* + UInt32 originalCmd = Get32(p); + if (originalCmd >= EW_REGISTERDLL) + { + UIntToString(s, originalCmd); + s += ' '; + if (originalCmd != commandId) + { + UIntToString(s, commandId); + s += ' '; + } + } + */ + + unsigned numSkipParams = 0; + + if (commandId < ARRAY_SIZE(k_Commands) && commandId < numSupportedCommands) + { + numSkipParams = k_Commands[commandId].NumParams; + const char *sz = k_CommandNames[commandId]; + if (sz) + s += sz; + } + else + { + s += "Command"; + Add_UInt(commandId); + /* We don't show wrong commands that use overlapped ids. + So we change commandId to big value */ + if (commandId < (1 << 12)) + commandId += (1 << 12); + } + #endif - switch (e.Which) + switch (commandId) { case EW_CREATEDIR: { - if (IsUnicode) + bool isSetOutPath = (params[1] != 0); + + if (isSetOutPath) { - prefixU.Empty(); - prefixU = ReadString2U(e.Params[0]); + UInt32 par0 = params[0]; + + UInt32 resOffset; + Int32 idx = GetVarIndex(par0, resOffset); + if (idx == (Int32)spec_outdir_VarIndex || + idx == kVar_OUTDIR) + par0 += resOffset; + + ReadString2_Raw(par0); + + if (IsUnicode) + { + if (idx == (Int32)spec_outdir_VarIndex) + Raw_UString.Insert(0, spec_outdir_U); + else if (idx == kVar_OUTDIR) + Raw_UString.Insert(0, UPrefixes.Back()); + UPrefixes.Add(Raw_UString); + } + else + { + if (idx == (Int32)spec_outdir_VarIndex) + Raw_AString.Insert(0, spec_outdir_A); + else if (idx == kVar_OUTDIR) + Raw_AString.Insert(0, APrefixes.Back()); + APrefixes.Add(Raw_AString); + } } - else + + #ifdef NSIS_SCRIPT + s += isSetOutPath ? "SetOutPath" : "CreateDirectory"; + AddParam(params[0]); + #endif + + break; + } + + + case EW_ASSIGNVAR: + { + if (params[0] == spec_outdir_VarIndex) { - prefixA.Empty(); - prefixA = ReadString2A(e.Params[0]); + spec_outdir_U.Empty(); + spec_outdir_A.Empty(); + if (IsVarStr(params[1], kVar_OUTDIR) && + params[2] == 0 && + params[3] == 0) + { + if (IsVarStr(params[1], kVar_OUTDIR)) + { + spec_outdir_U = UPrefixes.Back(); // outdir_U; + spec_outdir_A = APrefixes.Back();// outdir_A; + } + } } + #ifdef NSIS_SCRIPT - Script += " "; - if (IsUnicode) - Script += UnicodeStringToMultiByte(prefixU); - else - Script += prefixA; + + if (params[2] == 0 && + params[3] == 0 && + params[4] == 0 && + params[5] == 0 && + params[1] != 0 && + params[1] < NumStringChars) + { + char sz[16]; + ConvertUInt32ToString(kkk + 1, sz); + if (IsDirectString_Equal(params[1], sz)) + { + // we suppose that it's GetCurrentAddress command + // but there is probability that it's StrCpy command + s += "GetCurrentAddress"; + AddParam_Var(params[0]); + SmallSpaceComment(); + } + } + s += "StrCpy"; + AddParam_Var(params[0]); + AddParam(params[1]); + + AddOptionalParams(params + 2, 2); + #endif + break; } case EW_EXTRACTFILE: { - CItem item; - item.IsUnicode = IsUnicode; - if (IsUnicode) + CItem &item = Items.AddNew(); + + UInt32 par1 = params[1]; + + SetItemName(item, par1); + + item.Pos = params[2]; + item.MTime.dwLowDateTime = params[3]; + item.MTime.dwHighDateTime = params[4]; + + #ifdef NSIS_SCRIPT + { - item.PrefixU = prefixU; - item.NameU = ReadString2U(e.Params[1]); + UInt32 overwrite = params[0] & 0x7; + if (overwrite != overwrite_State) + { + s += "SetOverwrite "; + ADD_TYPE_FROM_LIST(k_SetOverwrite_Modes, overwrite); + overwrite_State = overwrite; + AddLF(); + Tab(kkk < endCommentIndex); + } } - else + { - item.PrefixA = prefixA; - item.NameA = ReadString2A(e.Params[1]); + UInt32 nsisMB = params[0] >> 3; + if ((Int32)nsisMB != allowSkipFiles_State) + { + UInt32 mb = nsisMB & ((1 << 20) - 1); // old/new NSIS + UInt32 b1 = nsisMB >> 21; // NSIS 2.06+ + UInt32 b2 = nsisMB >> 20; // NSIS old + Int32 asf = (Int32)nsisMB; + if (mb == (MY__MB_ABORTRETRYIGNORE | MY__MB_ICONSTOP) && (b1 == MY__IDIGNORE || b2 == MY__IDIGNORE)) + asf = -1; + else if (mb == (MY__MB_RETRYCANCEL | MY__MB_ICONSTOP) && (b1 == MY__IDCANCEL || b2 == MY__IDCANCEL)) + asf = -2; + else + { + AddCommentAndString("AllowSkipFiles [Overwrite]: "); + MessageBox_MB_Part(mb); + if (b1 != 0) + { + s += " /SD"; + Add_ButtonID(b1); + } + } + if (asf != allowSkipFiles_State) + { + if (asf < 0) + { + s += "AllowSkipFiles "; + s += (asf == -1) ? "on" : "off"; + } + AddLF(); + Tab(kkk < endCommentIndex); + } + allowSkipFiles_State = (Int32)nsisMB; + } } - /* UInt32 overwriteFlag = e.Params[0]; */ - item.Pos = e.Params[2]; - item.MTime.dwLowDateTime = e.Params[3]; - item.MTime.dwHighDateTime = e.Params[4]; - /* UInt32 allowIgnore = e.Params[5]; */ - if (Items.Size() > 0) + + s += "File"; + AddParam(params[1]); + + /* params[5] contains link to LangString (negative value) + with NLF_FILE_ERROR or NLF_FILE_ERROR_NOIGNORE message for MessageBox. + We don't need to print it. */ + + #endif + + if (IsVarStr(par1, 10)) // is $R0 { - /* - if (item.Pos == Items.Back().Pos) - continue; - */ + // we parse InstallLib macro in 7-Zip installers + unsigned kBackOffset = 28; + if (kkk > 1) + { + // detect old version of InstallLib macro + if (Get32(p - 1 * kCmdSize) == EW_NOP) // goto command + kBackOffset -= 2; + } + + if (kkk > kBackOffset) + { + const Byte *p2 = p - kBackOffset * kCmdSize; + UInt32 cmd = Get32(p2); + if (cmd == EW_ASSIGNVAR) + { + UInt32 pars[6]; + for (int i = 0; i < 6; i++) + pars[i] = Get32(p2 + i * 4 + 4); + if (pars[0] == 10 + 4 && pars[2] == 0 && pars[3] == 0) // 10 + 4 means $R4 + { + ReadString2_Raw(pars[1]); + if (IsUnicode) + { + if (!Raw_UString.IsEmpty()) + item.NameU = Raw_UString; + } + else + { + if (!Raw_AString.IsEmpty()) + item.NameA = Raw_AString; + } + } + } + } } - Items.Add(item); - #ifdef NSIS_SCRIPT - Script += " "; + /* UInt32 allowIgnore = params[5]; */ + break; + } - if (IsUnicode) - Script += UnicodeStringToMultiByte(item.NameU); - else - Script += item.NameA; + case EW_SETFILEATTRIBUTES: + { + if (kkk > 0 && Get32(p - kCmdSize) == EW_EXTRACTFILE) + { + if (params[0] == Get32(p - kCmdSize + 4 + 4 * 1)) // compare with PrevCmd.Params[1] + { + CItem &item = Items.Back(); + item.Attrib_Defined = true; + item.Attrib = params[1]; + } + } + #ifdef NSIS_SCRIPT + AddParam(params[0]); + Space(); + FlagsToString2(s, g_WinAttrib, ARRAY_SIZE(g_WinAttrib), params[1]); #endif break; } + case EW_WRITEUNINSTALLER: + { + /* NSIS 2.29+ writes alternative path to params[3] + "$INSTDIR\\" + Str(params[0]) + NSIS installer uses alternative path, if main path + from params[0] is not absolute path */ + + bool pathOk = (params[0] > 0) && IsGoodString(params[0]); + + if (!pathOk) + { + #ifdef NSIS_SCRIPT + AddError("bad path"); + #endif + break; + } + + bool altPathOk = true; + + UInt32 altParam = params[3]; + if (altParam != 0) + { + altPathOk = false; + UInt32 additional = 0; + if (GetVarIndexFinished(altParam, '\\', additional) == kVar_INSTDIR) + altPathOk = AreTwoParamStringsEqual(altParam + additional, params[0]); + } + + + #ifdef NSIS_SCRIPT + + AddParam(params[0]); + + SmallSpaceComment(); + + /* + for (int i = 1; i < 3; i++) + AddParam_UInt(params[i]); + */ + + if (params[3] != 0) + AddParam(params[3]); + + #endif + + if (!altPathOk) + { + #ifdef NSIS_SCRIPT + AddError("alt path error"); + #endif + } + + if (BadCmd >= 0 && BadCmd <= EW_WRITEUNINSTALLER) + { + /* We don't cases with incorrect installer commands. + Such bad installer item can break unpacking for other items. */ + #ifdef NSIS_SCRIPT + AddError("SKIP possible BadCmd"); + #endif + break; + } + + CItem &item = Items.AddNew();; + + SetItemName(item, params[0]); + + item.Pos = params[1]; + item.PatchSize = params[2]; + item.IsUninstaller = true; + + /* + // we can add second time to test the code + CItem item2 = item; + item2.NameU += L'2'; + item2.NameA += '2'; + Items.Add(item2); + */ + + break; + } #ifdef NSIS_SCRIPT + + case EW_RET: + { + // bool needComment = false; + if (onFuncIsOpen) + { + if (kkk == bh.Num - 1 || IsProbablyEndOfFunc(labels[kkk + 1])) + { + AddStringLF("FunctionEnd"); + + if ((int)kkk + 1 == InitPluginsDir_End) + CommentClose(); + AddLF(); + onFuncIsOpen = false; + // needComment = true; + break; + } + } + // if (!needComment) + if (IsSectionGroup) + break; + if (sectionIsOpen) + { + const CSection § = Sections[curSectionIndex]; + if (sect.StartCmdIndex + sect.NumCommands == kkk) + { + PrintSectionEnd(); + sectionIsOpen = false; + curSectionIndex++; + break; + } + + // needComment = true; + // break; + } + + /* + if (needComment) + s += " ;"; + */ + TabString("Return"); + AddLF(); + break; + } + + case EW_NOP: + { + if (params[0] == 0) + s += "Nop"; + else + { + s += "Goto"; + Add_GotoVar(params[0]); + } + break; + } + + case EW_ABORT: + { + AddOptionalParam(params[0]); + break; + } + + case EW_CALL: + { + if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_EXTRACTFILE) + { + UInt32 par1 = GET_CMD_PARAM(p + kCmdSize, 1); + + UInt32 pluginPar = 0; + + if (GetVarIndexFinished(par1, '\\', pluginPar) == kVar_PLUGINSDIR) + { + pluginPar += par1; + UInt32 commandId2 = GetCmd(Get32(p + kCmdSize * 2)); + if (commandId2 == EW_SETFLAG || commandId2 == EW_UPDATETEXT) + { + UInt32 i; + for (i = kkk + 3; i < bh.Num; i++) + { + const Byte *pCmd = p + kCmdSize * (i - kkk); + UInt32 commandId3 = GetCmd(Get32(pCmd)); + if (commandId3 != EW_PUSHPOP + || GET_CMD_PARAM(pCmd, 1) != 0 + || GET_CMD_PARAM(pCmd, 2) != 0) + break; + } + if (i < bh.Num) + { + const Byte *pCmd = p + kCmdSize * (i - kkk); + + // UInt32 callDll_Param = GET_CMD_PARAM(pCmd, 0); + // UInt32 file_Param = GET_CMD_PARAM(p + kCmdSize, 1); + + if (GetCmd(Get32(pCmd)) == EW_REGISTERDLL && + AreTwoParamStringsEqual( + GET_CMD_PARAM(pCmd, 0), + GET_CMD_PARAM(p + kCmdSize, 1))) + { + // params[4] = 1 means GetModuleHandle attempt before default LoadLibraryEx; + /// new versions of NSIS use params[4] = 1 for Plugin command + if (GET_CMD_PARAM(pCmd, 2) == 0 + // && GET_CMD_PARAM(pCmd, 4) != 0 + ) + { + { + AString s2; + ReadString2(s2, pluginPar); + if (s2.Len() >= 4 && + StringsAreEqualNoCase_Ascii(s2.RightPtr(4), ".dll")) + s2.DeleteFrom(s2.Len() - 4); + s2 += "::"; + AString func; + ReadString2(func, GET_CMD_PARAM(pCmd, 1)); + s2 += func; + Add_QuStr(s2); + + if (GET_CMD_PARAM(pCmd, 3) == 1) + s += " /NOUNLOAD"; + + for (UInt32 j = i - 1; j >= kkk + 3; j--) + { + const Byte *pCmd = p - kCmdSize * (kkk - j); + AddParam(GET_CMD_PARAM(pCmd, 0)); + } + NewLine(); + Tab(true); + endCommentIndex = i + 1; + } + } + } + } + } + } + } + { + const Byte *nextCmd = p + kCmdSize; + UInt32 commandId2 = GetCmd(Get32(nextCmd)); + if (commandId2 == EW_SETFLAG + && GET_CMD_PARAM(nextCmd, 0) == k_ExecFlags_DetailsPrint + && GET_CMD_PARAM(nextCmd, 2) != 0) // is "lastused" + // || commandId2 == EW_UPDATETEXT) + { + if ((Int32)params[0] > 0 && labels[params[0] - 1] & CMD_REF_InitPluginDir) + { + s += "InitPluginsDir"; + AddLF(); + Tab(true); + endCommentIndex = kkk + 2; + } + } + } + + s += "Call "; + if ((Int32)params[0] < 0) + Add_Var(-((Int32)params[0] + 1)); + else if (params[0] == 0) + s += '0'; + else + { + UInt32 val = params[0] - 1; + if (params[1] == 1) // it's Call :Label + { + s += ':'; + Add_LabelName(val); + } + else // if (params[1] == 0) // it's Call Func + Add_FuncName(labels, val); + } + break; + } + case EW_UPDATETEXT: + case EW_SLEEP: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += UIntToString(e.Params[1]); + AddParam(params[0]); break; } - case EW_SETFILEATTRIBUTES: + + case EW_CHDETAILSVIEW: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += UIntToString(e.Params[1]); + if (params[0] == MY__SW_SHOWNA && params[1] == MY__SW_HIDE) s += " show"; + else if (params[1] == MY__SW_SHOWNA && params[0] == MY__SW_HIDE) s += " hide"; + else + for (int i = 0; i < 2; i++) + { + Space(); + Add_ShowWindow_Cmd(params[i]); + } break; } + case EW_IFFILEEXISTS: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += UIntToString(e.Params[1]); - Script += " "; - Script += UIntToString(e.Params[2]); + AddParam(params[0]); + Add_GotoVars2(¶ms[1]); break; } + + case EW_SETFLAG: + { + AString temp; + ReadString2(temp, params[1]); + if (params[0] == k_ExecFlags_Errors && params[2] == 0) + { + s += (temp.Len() == 1 && temp[0] == '0') ? "ClearErrors" : "SetErrors"; + break; + } + s += "Set"; + Add_ExecFlags(params[0]); + + if (params[2] != 0) + { + s += " lastused"; + break; + } + UInt32 v; + if (StringToUInt32(temp, v)) + { + const char *s2 = NULL; + switch (params[0]) + { + case k_ExecFlags_AutoClose: + case k_ExecFlags_RebootFlag: + if (v < 2) s2 = (v == 0) ? "false" : "true"; break; + case k_ExecFlags_ShellVarContext: + if (v < 2) s2 = (v == 0) ? "current" : "all"; break; + case k_ExecFlags_Silent: + if (v < 2) s2 = (v == 0) ? "normal" : "silent"; break; + case k_ExecFlags_RegView: + if (v == 0) s2 = "32"; + else if (v == 256) s2 = "64"; + break; + case k_ExecFlags_DetailsPrint: + if (v == 0) s2 = "both"; + else if (v == 2) s2 = "textonly"; + else if (v == 4) s2 = "listonly"; + else if (v == 6) s2 = "none"; + } + if (s2) + { + s += ' '; + s += s2; + break; + } + } + SpaceQuStr(temp); + break; + } + + case EW_IFFLAG: + { + Add_ExecFlags(params[2]); + Add_GotoVars2(¶ms[0]); + /* + static const unsigned kIfErrors = 2; + if (params[2] != kIfErrors && params[3] != 0xFFFFFFFF || + params[2] == kIfErrors && params[3] != 0) + { + s += " # FLAG &= "; + AddParam_UInt(params[3]); + } + */ + break; + } + + case EW_GETFLAG: + { + Add_ExecFlags(params[1]); + AddParam_Var(params[0]); + break; + } + case EW_RENAME: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += ReadString2(e.Params[1]); - Script += " "; - Script += UIntToString(e.Params[2]); + if (params[2] != 0) + s += k_REBOOTOK; + AddParams(params, 2); + if (params[3] != 0) + { + SmallSpaceComment(); + AddParam(params[3]); // rename comment for log file + } break; } + case EW_GETFULLPATHNAME: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += ReadString2(e.Params[1]); - Script += " "; - Script += UIntToString(e.Params[2]); + if (params[2] == 0) + s += " /SHORT"; + AddParam_Var(params[1]); + AddParam(params[0]); break; } + case EW_SEARCHPATH: + case EW_STRLEN: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += ReadString2(e.Params[1]); + AddParam_Var(params[0]); + AddParam(params[1]); break; } + case EW_GETTEMPFILENAME: { - AString s; - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += ReadString2(e.Params[1]); + AddParam_Var(params[0]); + AString temp; + ReadString2(temp, params[1]); + if (temp != "$TEMP") + SpaceQuStr(temp); break; } case EW_DELETEFILE: { - UInt64 flag = e.Params[1]; - if (flag != 0) + UInt32 flag = params[1]; + if ((flag & DEL_REBOOT) != 0) + s += k_REBOOTOK; + AddParam(params[0]); + break; + } + + case EW_MESSAGEBOX: + { + MessageBox_MB_Part(params[0]); + AddParam(params[1]); { - Script += " "; - if (flag == DEL_REBOOT) - Script += "/REBOOTOK"; - else - Script += UIntToString(e.Params[1]); + UInt32 buttonID = (params[0] >> 21); // NSIS 2.06+ + if (buttonID != 0) + { + s += " /SD"; + Add_ButtonID(buttonID); + } } - Script += " "; - Script += ReadString2(e.Params[0]); + for (int i = 2; i < 6; i += 2) + if (params[i] != 0) + { + Add_ButtonID(params[i]); + Add_GotoVar1(params[i + 1]); + } break; } + case EW_RMDIR: { - UInt64 flag = e.Params[1]; - if (flag != 0) + UInt32 flag = params[1]; + if ((flag & DEL_RECURSE) != 0) + s += " /r"; + if ((flag & DEL_REBOOT) != 0) + s += k_REBOOTOK; + AddParam(params[0]); + break; + } + + case EW_STRCMP: + { + if (params[4] != 0) + s += 'S'; + AddParams(params, 2); + Add_GotoVars2(¶ms[2]); + break; + } + + case EW_READENVSTR: + { + s += (params[2] != 0) ? + "ReadEnvStr" : + "ExpandEnvStrings"; + AddParam_Var(params[0]); + AString temp; + ReadString2(temp, params[1]); + if (params[2] != 0 &&temp.Len() >= 2 && temp[0] == '%' && temp.Back() == '%') { - if ((flag & DEL_REBOOT) != 0) - Script += " /REBOOTOK"; - if ((flag & DEL_RECURSE) != 0) - Script += " /r"; + temp.DeleteBack(); + temp.Delete(0); } - Script += " "; - Script += ReadString2(e.Params[0]); + SpaceQuStr(temp); break; } - case EW_STRLEN: + + case EW_INTCMP: { - Script += " "; - Script += GetVar(e.Params[0]);; - Script += " "; - Script += ReadString2Qw(e.Params[1]); + if (params[5] != 0) + s += 'U'; + AddParams(params, 2); + Add_GotoVar1(params[2]); + if (params[3] != 0 || params[4] != 0) + Add_GotoVars2(params + 3); break; } - case EW_ASSIGNVAR: + + case EW_INTOP: { - Script += " "; - Script += GetVar(e.Params[0]);; - Script += " "; - Script += ReadString2Qw(e.Params[1]); - AString maxLen, startOffset; - if (e.Params[2] != 0) - maxLen = ReadString2(e.Params[2]); - if (e.Params[3] != 0) - startOffset = ReadString2(e.Params[3]); - if (!maxLen.IsEmpty() || !startOffset.IsEmpty()) - { - Script += " "; - if (maxLen.IsEmpty()) - Script += "\"\""; - else - Script += maxLen; - if (!startOffset.IsEmpty()) + AddParam_Var(params[0]); + const char *kOps = "+-*/|&^!|&%<>"; // NSIS 2.01+ + // "+-*/|&^!|&%"; // NSIS 2.0b4+ + // "+-*/|&^~!|&%"; // NSIS old + UInt32 opIndex = params[3]; + char c = (opIndex < 13) ? kOps[opIndex] : '?'; + char c2 = (opIndex < 8 || opIndex == 10) ? (char)0 : c; + int numOps = (opIndex == 7) ? 1 : 2; + AddParam(params[1]); + if (numOps == 2 && c == '^' && IsDirectString_Equal(params[2], "0xFFFFFFFF")) + s += " ~ ;"; + Space(); + s += c; + if (numOps != 1) + { + if (c2 != 0) + s += c2; + AddParam(params[2]); + } + break; + } + + case EW_INTFMT: + { + AddParam_Var(params[0]); + AddParams(params + 1, 2); + break; + } + + case EW_PUSHPOP: + { + if (params[2] != 0) + { + s += "Exch"; + if (params[2] != 1) + AddParam_UInt(params[2]); + } + else if (params[1] != 0) + { + s += "Pop"; + AddParam_Var(params[0]); + } + else + { + if (NoLabels(labels + kkk + 1, 2) + && Get32(p + kCmdSize) == EW_PUSHPOP // Exch" + && GET_CMD_PARAM(p + kCmdSize, 2) == 1 + && Get32(p + kCmdSize * 2) == EW_PUSHPOP // Pop $VAR + && GET_CMD_PARAM(p + kCmdSize * 2, 1) != 0) { - Script += " "; - Script += startOffset; + if (IsVarStr(params[0], GET_CMD_PARAM(p + kCmdSize * 2, 0))) + { + s += "Exch"; + AddParam(params[0]); + NewLine(); + Tab(true); + endCommentIndex = kkk + 3; + } } + s += "Push"; + AddParam(params[0]); } break; } - case EW_STRCMP: + + case EW_FINDWINDOW: { - Script += " "; + AddParam_Var(params[0]); + AddParam(params[1]); + AddOptionalParams(params + 2, 3); + break; + } - Script += " "; - Script += ReadString2Qw(e.Params[0]); + case EW_SENDMESSAGE: + { + // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2] + AddParam(params[1]); + + const char *w = NULL; + AString t; + ReadString2(t, params[2]); + UInt32 wm; + if (StringToUInt32(t, wm)) + { + switch (wm) + { + case 0x0C: w = "SETTEXT"; break; + case 0x10: w = "CLOSE"; break; + case 0x30: w = "SETFONT"; break; + } + } + if (w) + { + s += " ${WM_"; + s += w; + s += '}'; + } + else + SpaceQuStr(t); - Script += " "; - Script += ReadString2Qw(e.Params[1]); + UInt32 spec = params[5]; + for (unsigned i = 0; i < 2; i++) + { + AString s2; + if (spec & ((UInt32)1 << i)) + s2 += "STR:"; + ReadString2(s2, params[3 + i]); + SpaceQuStr(s2); + } - for (int j = 2; j < 5; j++) + if ((Int32)params[0] >= 0) + AddParam_Var(params[0]); + + spec >>= 2; + if (spec != 0) { - Script += " "; - Script += UIntToString(e.Params[j]); + s += " /TIMEOUT="; + Add_UInt(spec); } break; } - case EW_INTCMP: + + case EW_ISWINDOW: { - if (e.Params[5] != 0) - Script += "U"; + AddParam(params[0]); + Add_GotoVars2(¶ms[1]); + break; + } + + case EW_GETDLGITEM: + { + AddParam_Var(params[0]); + AddParams(params + 1, 2); + break; + } + + case EW_SETCTLCOLORS: + { + AddParam(params[0]); + + UInt32 offset = params[1]; + + if (_size < bhCtlColors.Offset + || _size - bhCtlColors.Offset < offset + || _size - bhCtlColors.Offset - offset < k_CtlColors_Size) + { + AddError("bad offset"); + break; + } - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += ReadString2(e.Params[1]); + const Byte *p2 = _data + bhCtlColors.Offset + offset; + CNsis_CtlColors colors; + colors.Parse(p2); - for (int i = 2; i < 5; i++) + if ((colors.flags & kColorsFlags_BK_SYS) != 0 || + (colors.flags & kColorsFlags_TEXT_SYS) != 0) + s += " /BRANDING"; + + AString bk; + bool bkc = false; + if (colors.bkmode == MY__TRANSPARENT) + bk += " transparent"; + else if (colors.flags & kColorsFlags_BKB) { - Script += " "; - Script += UIntToString(e.Params[i]); + if ((colors.flags & kColorsFlags_BK_SYS) == 0 && + (colors.flags & kColorsFlags_BK) != 0) + bkc = true; } + if ((colors.flags & kColorsFlags_TEXT) != 0 || !bk.IsEmpty() || bkc) + { + Space(); + if ((colors.flags & kColorsFlags_TEXT_SYS) != 0 || (colors.flags & kColorsFlags_TEXT) == 0) + AddQuotes(); + else + Add_Color(colors.text); + } + s += bk; + if (bkc) + { + Space(); + Add_Color(colors.bkc); + } + break; } - case EW_INTOP: + + case EW_SETBRANDINGIMAGE: { - Script += " "; - Script += GetVar(e.Params[0]); - Script += " "; - int numOps = 2; - AString op; - switch (e.Params[3]) - { - case 0: op = '+'; break; - case 1: op = '-'; break; - case 2: op = '*'; break; - case 3: op = '/'; break; - case 4: op = '|'; break; - case 5: op = '&'; break; - case 6: op = '^'; break; - case 7: op = '~'; numOps = 1; break; - case 8: op = '!'; numOps = 1; break; - case 9: op = "||"; break; - case 10: op = "&&"; break; - case 11: op = '%'; break; - default: op = UIntToString(e.Params[3]); - } - AString p1 = ReadString2(e.Params[1]); - if (numOps == 1) - { - Script += op; - Script += p1; - } + s += " /IMGID="; + Add_UInt(params[1]); + if (params[2] == 1) + s += " /RESIZETOFIT"; + AddParam(params[0]); + break; + } + + case EW_CREATEFONT: + { + AddParam_Var(params[0]); + AddParam(params[1]); + AddOptionalParams(params + 2, 2); + if (params[4] & 1) s += " /ITALIC"; + if (params[4] & 2) s += " /UNDERLINE"; + if (params[4] & 4) s += " /STRIKE"; + break; + } + + case EW_SHOWWINDOW: + { + AString hw, sw; + ReadString2(hw, params[0]); + ReadString2(sw, params[1]); + if (params[3] != 0) + s += "EnableWindow"; else { - Script += p1; - Script += " "; - Script += op; - Script += " "; - Script += ReadString2(e.Params[2]); + UInt32 val; + bool valDefined = false; + if (StringToUInt32(sw, val)) + { + if (val < ARRAY_SIZE(kShowWindow_Commands)) + { + sw.Empty(); + sw += "${"; + Add_ShowWindow_Cmd_2(sw, val); + sw += '}'; + valDefined = true; + } + } + bool isHwndParent = IsVarStr(params[0], IsNsis225 ? kVar_HWNDPARENT_225 : kVar_HWNDPARENT); + if (params[2] != 0) + { + if (valDefined && val == 0 && isHwndParent) + { + s += "HideWindow"; + break; + } + } + if (valDefined && val == 5 && isHwndParent && + kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_BRINGTOFRONT) + { + s += " ; "; + } + s += "ShowWindow"; } + SpaceQuStr(hw); + SpaceQuStr(sw); break; } - case EW_PUSHPOP: + case EW_SHELLEXEC: { - int isPop = (e.Params[1] != 0); - if (isPop) + AddParams(params, 2); + if (params[2] != 0 || params[3] != MY__SW_SHOWNORMAL) { - Script += "Pop"; - Script += " "; - Script += GetVar(e.Params[0]);; + AddParam(params[2]); + if (params[3] != MY__SW_SHOWNORMAL) + { + Space(); + Add_ShowWindow_Cmd(params[3]); + } + } + if (params[5] != 0) + { + s += " ;"; + AddParam(params[5]); // it's tatus text update + } + break; + } + + case EW_EXECUTE: + { + if (params[2] != 0) + s += "Wait"; + AddParam(params[0]); + if (params[2] != 0) + if ((Int32)params[1] >= 0) + AddParam_Var(params[1]); + break; + } + + case EW_GETFILETIME: + case EW_GETDLLVERSION: + { + AddParam(params[2]); + AddParam_Var(params[0]); + AddParam_Var(params[1]); + break; + } + + case EW_REGISTERDLL: + { + AString func; + ReadString2(func, params[1]); + bool printFunc = true; + // params[4] = 1; for plugin command + if (params[2] == 0) + { + s += "CallInstDLL"; + AddParam(params[0]); + if (params[3] == 1) + s += " /NOUNLOAD"; } else { - int isExch = (e.Params[2] != 0); - if (isExch) + if (func == "DllUnregisterServer") { - Script += "Exch"; + s += "UnRegDLL"; + printFunc = false; } else { - Script += "Push"; - Script += " "; - Script += ReadString2(e.Params[0]); + s += "RegDLL"; + if (func == "DllRegisterServer") + printFunc = false; } + AddParam(params[0]); } + if (printFunc) + SpaceQuStr(func); break; } - case EW_SENDMESSAGE: + case EW_CREATESHORTCUT: { - // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2] - Script += " "; - // Script += ReadString2(e.Params[0]); - // Script += " "; - Script += ReadString2(e.Params[1]); - Script += " "; - Script += ReadString2(e.Params[2]); - - Script += " "; - UInt32 spec = e.Params[5]; - // if (spec & 1) - Script += IntToString(e.Params[3]); - // else - // Script += ReadString2(e.Params[3]); + unsigned numParams; + for (numParams = 6; numParams > 2; numParams--) + if (params[numParams - 1] != 0) + break; + + UInt32 spec = params[4]; + if (spec & 0x8000) // NSIS 3.0b0 + s += " /NoWorkingDir"; + + AddParams(params, numParams > 4 ? 4 : numParams); + if (numParams <= 4) + break; + + UInt32 icon = (spec & 0xFF); + Space(); + if (icon != 0) + Add_UInt(icon); + else + AddQuotes(); + + if ((spec >> 8) == 0 && numParams < 6) + break; + UInt32 sw = (spec >> 8) & 0x7F; + Space(); + // NSIS encoder replaces these names: + if (sw == MY__SW_SHOWMINNOACTIVE) + sw = MY__SW_SHOWMINIMIZED; + if (sw == 0) + AddQuotes(); + else + Add_ShowWindow_Cmd(sw); - Script += " "; - // if (spec & 2) - Script += IntToString(e.Params[4]); - // else - // Script += ReadString2(e.Params[4]); + UInt32 modKey = spec >> 24; + UInt32 key = (spec >> 16) & 0xFF; - if ((Int32)e.Params[0] >= 0) + if (modKey == 0 && key == 0) { - Script += " "; - Script += GetVar(e.Params[1]); + if (numParams < 6) + break; + Space(); + AddQuotes(); } - - spec >>= 2; - if (spec != 0) + else { - Script += " /TIMEOUT="; - Script += IntToString(spec); + Space(); + if (modKey & 1) s += "SHIFT|"; // HOTKEYF_SHIFT + if (modKey & 2) s += "CONTROL|"; + if (modKey & 4) s += "ALT|"; + if (modKey & 8) s += "EXT|"; + + static const unsigned kMy_VK_F1 = 0x70; + if (key >= kMy_VK_F1 && key <= kMy_VK_F1 + 23) + { + s += 'F'; + Add_UInt(key - kMy_VK_F1 + 1); + } + else if (key >= 'A' && key <= 'Z' || key >= '0' && key <= '9') + s += (char)key; + else + { + s += "Char_"; + Add_UInt(key); + } } + AddOptionalParam(params[5]); // description break; } - case EW_GETDLGITEM: + case EW_COPYFILES: { - Script += " "; - Script += GetVar(e.Params[0]);; - Script += " "; - Script += ReadString2(e.Params[1]); - Script += " "; - Script += ReadString2(e.Params[2]); + if (params[2] & 0x04) s += " /SILENT"; // FOF_SILENT + if (params[2] & 0x80) s += " /FILESONLY"; // FOF_FILESONLY + AddParams(params, 2); + if (params[3] != 0) + { + s += " ;"; + AddParam(params[3]); // status text update + } break; - } - + } - case EW_REGISTERDLL: + case EW_REBOOT: { - Script += " "; - Script += ReadString2(e.Params[0]); - Script += " "; - Script += ReadString2(e.Params[1]); - Script += " "; - Script += UIntToString(e.Params[2]); + if (params[0] != 0xbadf00d) + s += " ; Corrupted ???"; + else if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_QUIT) + endCommentIndex = kkk + 2; break; } - case EW_CREATESHORTCUT: + case EW_WRITEINI: { - AString s; - - Script += " "; - Script += ReadString2Qw(e.Params[0]); + unsigned numAlwaysParams = 0; + if (params[0] == 0) // Section + s += "FlushINI"; + else if (params[4] != 0) + { + s += "WriteINIStr"; + numAlwaysParams = 3; + } + else + { + s += "DeleteINI"; + s += (params[1] == 0) ? "Sec" : "Str"; + numAlwaysParams = 1; + } + AddParam(params[3]); // filename + // Section, EntryName, Value + AddParams(params, numAlwaysParams); + AddOptionalParams(params + numAlwaysParams, 3 - numAlwaysParams); + break; + } - Script += " "; - Script += ReadString2Qw(e.Params[1]); + case EW_READINISTR: + { + AddParam_Var(params[0]); + AddParam(params[3]); // FileName + AddParams(params +1, 2); // Section, EntryName + break; + } - for (int j = 2; j < 5; j++) + case EW_DELREG: + { + // NSIS 2.00 used another scheme! + + if (params[4] == 0) + s += "Value"; + else { - Script += " "; - Script += UIntToString(e.Params[j]); + s += "Key"; + if (params[4] & 2) + s += " /ifempty"; } + AddRegRoot(params[1]); + AddParam(params[2]); + AddOptionalParam(params[3]); break; } - /* - case EW_DELREG: + case EW_WRITEREG: { - AString keyName, valueName; - keyName = ReadString2(e.Params[1]); - bool isValue = (e.Params[2] != -1); - if (isValue) + const char *s2 = 0; + switch (params[4]) { - valueName = ReadString2(e.Params[2]); - Script += "Key"; + case 1: s2 = "Str"; break; + case 2: s2 = "ExpandStr"; break; // maybe unused + case 3: s2 = "Bin"; break; + case 4: s2 = "DWORD"; break; + default: + s += '?'; + Add_UInt(params[4]); } + if (params[4] == 1 && params[5] == 2) + s2 = "ExpandStr"; + if (s2) + s += s2; + AddRegRoot(params[0]); + AddParams(params + 1, 2); // keyName, valueName + if (params[4] != 3) + AddParam(params[3]); // value else - Script += "Value"; - Script += " "; - Script += UIntToString(e.Params[0]); - Script += " "; - Script += keyName; - if (isValue) { - Script += " "; - Script += valueName; + // Binary data. + Space(); + UInt32 offset = params[3]; + bool isSupported = false; + if (AfterHeaderSize >= 4 + && bhData.Offset <= AfterHeaderSize - 4 + && offset <= AfterHeaderSize - 4 - bhData.Offset) + { + // we support it for solid archives. + const Byte *p2 = _afterHeader + bhData.Offset + offset; + UInt32 size = Get32(p2); + if (size <= AfterHeaderSize - 4 - bhData.Offset - offset) + { + for (UInt32 i = 0; i < size; i++) + { + Byte b = (p2 + 4)[i]; + unsigned t; + t = (b >> 4); s += (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); + t = (b & 15); s += (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); + } + isSupported = true; + } + } + if (!isSupported) + { + // we must read from file here; + s += "data["; + Add_UInt(offset); + s += " ... ]"; + s += " ; !!! Unsupported"; + } } - Script += " "; - Script += UIntToString(e.Params[3]); break; } - */ - case EW_WRITEREG: + case EW_READREGSTR: + { + s += (params[4] == 1) ? "DWORD" : "Str"; + AddParam_Var(params[0]); + AddRegRoot(params[1]); + AddParams(params + 2, 2); + break; + } + + case EW_REGENUM: + { + s += (params[4] != 0) ? "Key" : "Value"; + AddParam_Var(params[0]); + AddRegRoot(params[1]); + AddParams(params + 2, 2); + break; + } + + case EW_FCLOSE: + case EW_FINDCLOSE: + { + AddParam_Var(params[0]); + break; + } + + case EW_FOPEN: { - AString s; - switch(e.Params[4]) + AddParam_Var(params[0]); + AddParam(params[3]); + UInt32 acc = params[1]; // dwDesiredAccess + UInt32 creat = params[2]; // dwCreationDisposition + if (acc == 0 && creat == 0) + break; + char cc = 0; + if (acc == MY__GENERIC_READ && creat == OPEN_EXISTING) + cc = 'r'; + else if (creat == CREATE_ALWAYS && acc == MY__GENERIC_WRITE) + cc = 'w'; + else if (creat == OPEN_ALWAYS && (acc == (MY__GENERIC_WRITE | MY__GENERIC_READ))) + cc = 'a'; + // cc = 0; + if (cc != 0) { - case 1: s = "Str"; break; - case 2: s = "ExpandStr"; break; - case 3: s = "Bin"; break; - case 4: s = "DWORD"; break; - default: s = "?" + UIntToString(e.Params[4]); break; + Space(); + s += cc; + break; } - Script += s; - Script += " "; - Script += GetRegRootID(e.Params[0]); - Script += " "; - AString keyName, valueName; - keyName = ReadString2Qw(e.Params[1]); - Script += keyName; - Script += " "; + if (acc & MY__GENERIC_READ) s += " GENERIC_READ"; + if (acc & MY__GENERIC_WRITE) s += " GENERIC_WRITE"; + if (acc & MY__GENERIC_EXECUTE) s += " GENERIC_EXECUTE"; + if (acc & MY__GENERIC_ALL) s += " GENERIC_ALL"; - valueName = ReadString2Qw(e.Params[2]); - Script += valueName; - Script += " "; + const char *s2 = NULL; + switch (creat) + { + case MY__CREATE_NEW: s2 = "CREATE_NEW"; break; + case MY__CREATE_ALWAYS: s2 = "CREATE_ALWAYS"; break; + case MY__OPEN_EXISTING: s2 = "OPEN_EXISTING"; break; + case MY__OPEN_ALWAYS: s2 = "OPEN_ALWAYS"; break; + case MY__TRUNCATE_EXISTING: s2 = "TRUNCATE_EXISTING"; break; + } + Space(); + if (s2) + s += s2; + else + Add_UInt(creat); + break; + } - valueName = ReadString2Qw(e.Params[3]); - Script += valueName; - Script += " "; + case EW_FPUTS: + case EW_FPUTWS: + { + if (commandId == EW_FPUTWS) + s += (params[2] == 0) ? "UTF16LE" : "Word"; + else if (params[2] != 0) + s += "Byte"; + AddParam_Var(params[0]); + AddParam(params[1]); + break; + } + case EW_FGETS: + case EW_FGETWS: + { + if (commandId == EW_FPUTWS) + s += (params[3] == 0) ? "UTF16LE" : "Word"; + if (params[3] != 0) + s += "Byte"; + AddParam_Var(params[0]); + AddParam_Var(params[1]); + AString maxLenStr; + ReadString2(maxLenStr, params[2]); + UInt32 maxLen; + if (StringToUInt32(maxLenStr, maxLen)) + { + if (maxLen == 1 && params[3] != 0) + break; + if (maxLen == 1023 && params[3] == 0) // NSIS_MAX_STRLEN - 1; can be other value!! + break; + } + SpaceQuStr(maxLenStr); break; } - case EW_WRITEUNINSTALLER: + case EW_FSEEK: { - Script += " "; - Script += ReadString2(e.Params[0]); - for (int j = 1; j < 3; j++) + AddParam_Var(params[0]); + AddParam(params[2]); + if (params[3] == 1) s += " CUR"; // FILE_CURRENT + if (params[3] == 2) s += " END"; // FILE_END + if ((Int32)params[1] >= 0) { - Script += " "; - Script += UIntToString(e.Params[j]); + if (params[3] == 0) s += " SET"; // FILE_BEGIN + AddParam_Var(params[1]); } break; } - default: + case EW_FINDNEXT: + { + AddParam_Var(params[1]); + AddParam_Var(params[0]); + break; + } + + case EW_FINDFIRST: + { + AddParam_Var(params[1]); + AddParam_Var(params[0]); + AddParam(params[2]); + break; + } + + case EW_LOG: { - int numParams = kNumEntryParams; - if (e.Which < sizeof(kCommandPairs) / sizeof(kCommandPairs[0])) + if (params[0] != 0) { - const CCommandPair &pair = kCommandPairs[e.Which]; - // Script += pair.Name; - numParams = pair.NumParams; + s += "Set "; + s += (params[1] == 0) ? "off" : "on"; } else { - Script += "Unknown"; - Script += UIntToString(e.Which); + s += "Text"; + AddParam(params[1]); } - Script += e.GetParamsString(numParams); + } + + case EW_SECTIONSET: + { + if ((Int32)params[2] >= 0) + { + s += "Get"; + Add_SectOp(params[2]); + AddParam(params[0]); + AddParam_Var(params[1]); + } + else + { + s += "Set"; + UInt32 t = -(Int32)params[2] - 1; + Add_SectOp(t); + AddParam(params[0]); + AddParam(params[t == 0 ? 4 : 1]); + + // params[3] != 0 means call SectionFlagsChanged in installer + // used by SECTIONSETFLAGS command + } + break; + } + + case EW_INSTTYPESET: + { + int numQwParams = 0; + const char *s2; + if (params[3] == 0) + { + if (params[2] == 0) + { + s2 = "InstTypeGetText"; + numQwParams = 1; + } + else + { + s2 = "InstTypeSetText"; + numQwParams = 2; + } + } + else + { + if (params[2] == 0) + s2 = "GetCurInstType"; + else + { + s2 = "SetCurInstType"; + numQwParams = 1; + } + } + s += s2; + AddParams(params, numQwParams); + if (params[2] == 0) + AddParam_Var(params[1]); + break; + } + + case EW_LOCKWINDOW: + { + s += (params[0] == 0) ? " on" : " off"; + break; + } + + case EW_FINDPROC: + { + AddParam_Var(params[0]); + AddParam(params[1]); + break; + } + + default: + { + numSkipParams = 0; } #endif } + #ifdef NSIS_SCRIPT - Script += kCrLf; + + unsigned numParams = kNumCommandParams; + + for (; numParams > 0; numParams--) + if (params[numParams - 1] != 0) + break; + + if (numParams > numSkipParams) + { + s += " ; !!!! Unknown Params: "; + unsigned i; + for (i = 0; i < numParams; i++) + AddParam(params[i]); + + s += " ;"; + + for (i = 0; i < numParams; i++) + { + Space(); + UInt32 v = params[i]; + if (v > 0xFFF00000) + Add_SignedInt(s, (Int32)v); + else + Add_UInt(v); + } + } + + NewLine(); + #endif } + #ifdef NSIS_SCRIPT + + if (sectionIsOpen) + { + if (curSectionIndex < bhSections.Num) + { + const CSection § = Sections[curSectionIndex]; + if (sect.StartCmdIndex + sect.NumCommands + 1 == kkk) + { + PrintSectionEnd(); + sectionIsOpen = false; + // lastSectionEndCmd = kkk; + curSectionIndex++; + } + } + } + + while (curSectionIndex < bhSections.Num) + { + const CSection § = Sections[curSectionIndex]; + if (sectionIsOpen) + { + if (sect.StartCmdIndex + sect.NumCommands != kkk) + AddErrorLF("SECTION ERROR"); + PrintSectionEnd(); + sectionIsOpen = false; + curSectionIndex++; + } + else + { + if (curSectionIndex == 49) + curSectionIndex = curSectionIndex; + + if (PrintSectionBegin(sect, curSectionIndex)) + curSectionIndex++; + else + sectionIsOpen = true; + } + } + + #endif + + return S_OK; +} + +static int CompareItems(void *const *p1, void *const *p2, void *param) +{ + const CItem &i1 = **(CItem **)p1; + const CItem &i2 = **(CItem **)p2; + RINOZ(MyCompare(i1.Pos, i2.Pos)); + const CInArchive *inArchive = (const CInArchive *)param; + if (inArchive->IsUnicode) + { + if (i1.Prefix != i2.Prefix) + { + if (i1.Prefix < 0) return -1; + if (i2.Prefix < 0) return 1; + RINOZ(wcscmp( + inArchive->UPrefixes[i1.Prefix], + inArchive->UPrefixes[i2.Prefix])); + } + RINOZ(wcscmp(i1.NameU, i2.NameU)); + } + else + { + if (i1.Prefix != i2.Prefix) + { + if (i1.Prefix < 0) return -1; + if (i2.Prefix < 0) return 1; + RINOZ(strcmp( + inArchive->APrefixes[i1.Prefix], + inArchive->APrefixes[i2.Prefix])); + } + RINOZ(strcmp(i1.NameA, i2.NameA)); + } + return 0; +} + +HRESULT CInArchive::SortItems() +{ { - Items.Sort(CompareItems, 0); - int i; - // if (IsSolid) - for (i = 0; i + 1 < Items.Size();) + Items.Sort(CompareItems, (void *)this); + unsigned i; + + for (i = 0; i + 1 < Items.Size(); i++) { - bool sameName = IsUnicode ? - (Items[i].NameU == Items[i + 1].NameU) : - (Items[i].NameA == Items[i + 1].NameA); - if (Items[i].Pos == Items[i + 1].Pos && sameName) - Items.Delete(i + 1); + const CItem &i1 = Items[i]; + const CItem &i2 = Items[i + 1]; + if (i1.Pos != i2.Pos) + continue; + + if (IsUnicode) + { + if (i1.NameU != i2.NameU) continue; + if (i1.Prefix != i2.Prefix) + { + if (i1.Prefix < 0 || i2.Prefix < 0) continue; + if (UPrefixes[i1.Prefix] != UPrefixes[i2.Prefix]) continue; + } + } else - i++; + { + if (i1.NameA != i2.NameA) continue; + if (i1.Prefix != i2.Prefix) + { + if (i1.Prefix < 0 || i2.Prefix < 0) continue; + if (APrefixes[i1.Prefix] != APrefixes[i2.Prefix]) continue; + } + } + Items.Delete(i + 1); + i--; } + for (i = 0; i < Items.Size(); i++) { CItem &item = Items[i]; UInt32 curPos = item.Pos + 4; - for (int nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++) + for (unsigned nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++) { UInt32 nextPos = Items[nextIndex].Pos; if (curPos <= nextPos) { - item.EstimatedSizeIsDefined = true; + item.EstimatedSize_Defined = true; item.EstimatedSize = nextPos - curPos; break; } } } + if (!IsSolid) { for (i = 0; i < Items.Size(); i++) { CItem &item = Items[i]; RINOK(_stream->Seek(GetPosOfNonSolidItem(i), STREAM_SEEK_SET, NULL)); - const UInt32 kSigSize = 4 + 1 + 5; + const UInt32 kSigSize = 4 + 1 + 1 + 4; // size,[flag],prop,dict BYTE sig[kSigSize]; size_t processedSize = kSigSize; RINOK(ReadStream(_stream, sig, &processedSize)); if (processedSize < 4) return S_FALSE; UInt32 size = Get32(sig); - if ((size & 0x80000000) != 0) + if ((size & kMask_IsCompressed) != 0) { item.IsCompressed = true; - // is compressed; - size &= ~0x80000000; + size &= ~kMask_IsCompressed; if (Method == NMethodType::kLZMA) { if (processedSize < 9) return S_FALSE; + /* if (FilterFlag) item.UseFilter = (sig[4] != 0); - item.DictionarySize = Get32(sig + 5 + (FilterFlag ? 1 : 0)); + */ + item.DictionarySize = Get32(sig + 4 + 1 + (FilterFlag ? 1 : 0)); } } else { item.IsCompressed = false; item.Size = size; - item.SizeIsDefined = true; + item.Size_Defined = true; } item.CompressedSize = size; - item.CompressedSizeIsDefined = true; + item.CompressedSize_Defined = true; } } } return S_OK; } +// Flags for common_header.flags +#define CH_FLAGS_DETAILS_SHOWDETAILS 1 +#define CH_FLAGS_DETAILS_NEVERSHOW 2 +#define CH_FLAGS_PROGRESS_COLORED 4 +#define CH_FLAGS_SILENT 8 +#define CH_FLAGS_SILENT_LOG 16 +#define CH_FLAGS_AUTO_CLOSE 32 +#define CH_FLAGS_DIR_NO_SHOW 64 // unused now +#define CH_FLAGS_NO_ROOT_DIR 128 +#define CH_FLAGS_COMP_ONLY_ON_CUSTOM 256 +#define CH_FLAGS_NO_CUSTOM 512 + +static const char *k_PostStrings[] = +{ + "install_directory_auto_append" + , "uninstchild" // NSIS 2.25+, used by uninstaller: + , "uninstcmd" // NSIS 2.25+, used by uninstaller: + , "wininit" // NSIS 2.25+, used by move file on reboot +}; + HRESULT CInArchive::Parse() { // UInt32 offset = ReadUInt32(); - // ???? offset == FirstHeader.HeaderLength - /* UInt32 ehFlags = */ ReadUInt32(); - CBlockHeader bhPages, bhSections, bhEntries, bhStrings, bhLangTables, bhCtlColors, bhData; - // CBlockHeader bgFont; - ReadBlockHeader(bhPages); - ReadBlockHeader(bhSections); - ReadBlockHeader(bhEntries); - ReadBlockHeader(bhStrings); - ReadBlockHeader(bhLangTables); - ReadBlockHeader(bhCtlColors); - // ReadBlockHeader(bgFont); - ReadBlockHeader(bhData); + // ???? offset == FirstHeader.HeaderSize + const Byte *p = _data; + + CBlockHeader bhEntries, bhStrings, bhLangTables; + bhEntries.Parse(p + 4 + 8 * 2); + bhStrings.Parse(p + 4 + 8 * 3); + bhLangTables.Parse(p + 4 + 8 * 4); + + #ifdef NSIS_SCRIPT + + CBlockHeader bhFont; + bhPages.Parse(p + 4 + 8 * 0); + bhSections.Parse(p + 4 + 8 * 1); + bhCtlColors.Parse(p + 4 + 8 * 5); + bhFont.Parse(p + 4 + 8 * 6); + bhData.Parse(p + 4 + 8 * 7); + + #endif _stringsPos = bhStrings.Offset; - UInt32 pos = GetOffset() + _stringsPos; - int numZeros0 = 0; - int numZeros1 = 0; - int i; - const int kBlockSize = 256; - for (i = 0; i < kBlockSize; i++) - { - if (pos >= _size || pos + 1 >= _size) - break; - char c0 = _data[pos++]; - char c1 = _data[pos++]; - wchar_t c = (c0 | ((wchar_t)c1 << 8)); + if (_stringsPos > _size) + return S_FALSE; + { + if (bhLangTables.Offset < bhStrings.Offset) + return S_FALSE; + UInt32 stringTableSize = bhLangTables.Offset - bhStrings.Offset; + if (stringTableSize < 2) + return S_FALSE; + const Byte *strData = _data + _stringsPos; + if (strData[stringTableSize - 1] != 0) + return S_FALSE; + IsUnicode = (Get16(strData) == 0); + NumStringChars = stringTableSize; + if (IsUnicode) + { + if ((stringTableSize & 1) != 0) + return S_FALSE; + NumStringChars >>= 1; + if (strData[stringTableSize - 2] != 0) + return S_FALSE; + } - if (c >= NS_UN_CODES_START && c < NS_UN_CODES_END) + } + + if (bhEntries.Num > (1 << 25)) + return S_FALSE; + if (bhEntries.Offset > _size) + return S_FALSE; + if (bhEntries.Num * kCmdSize > _size - bhEntries.Offset) + return S_FALSE; + + DetectNsisType(bhEntries, _data + bhEntries.Offset); + + #ifdef NSIS_SCRIPT + + { + AddCommentAndString("NSIS script"); + if (IsUnicode) + Script += " (UTF-8)"; + Space(); + Script += GetFormatDescription(); + AddLF(); + } + { + AddCommentAndString(IsInstaller ? "Install" : "Uninstall"); + AddLF(); + } + + AddLF(); + if (IsUnicode) + AddStringLF("Unicode true"); + + if (Method != NMethodType::kCopy) + { + const char *m = NULL; + switch (Method) { - if (pos >= _size || pos + 1 >= _size) - break; - pos += 2; - numZeros1++; + case NMethodType::kDeflate: m = "zlib"; break; + case NMethodType::kBZip2: m = "bzip2"; break; + case NMethodType::kLZMA: m = "lzma"; break; + } + Script += "SetCompressor"; + if (IsSolid) + Script += " /SOLID"; + if (m) + { + Space(); + Script += m; + } + AddLF(); + } + if (Method == NMethodType::kLZMA) + { + // if (DictionarySize != (8 << 20)) + { + Script += "SetCompressorDictSize"; + AddParam_UInt(DictionarySize >> 20); + AddLF(); } + } + + Separator(); + PrintNumComment("HEADER SIZE", FirstHeader.HeaderSize); + // if (bhPages.Offset != 300 && bhPages.Offset != 288) + if (bhPages.Offset != 0) + { + PrintNumComment("START HEADER SIZE", bhPages.Offset); + } + + if (bhSections.Num > 0) + { + if (bhEntries.Offset < bhSections.Offset) + return S_FALSE; + SectionSize = (bhEntries.Offset - bhSections.Offset) / bhSections.Num; + if (bhSections.Offset + bhSections.Num * SectionSize != bhEntries.Offset) + return S_FALSE; + if (SectionSize < kSectionSize_base) + return S_FALSE; + UInt32 maxStringLen = SectionSize - kSectionSize_base; + if (IsUnicode) + { + if ((maxStringLen & 1) != 0) + return S_FALSE; + maxStringLen >>= 1; + } + // if (maxStringLen != 1024) + { + if (maxStringLen == 0) + PrintNumComment("SECTION SIZE", SectionSize); + else + PrintNumComment("MAX STRING LENGTH", maxStringLen); + } + } + + PrintNumComment("STRING CHARS", NumStringChars); + // PrintNumComment("LANG TABLE SIZE", bhCtlColors.Offset - bhLangTables.Offset); + + if (bhCtlColors.Offset > _size) + AddErrorLF("Bad COLORS TABLE"); + // PrintNumComment("COLORS TABLE SIZE", bhFont.Offset - bhCtlColors.Offset); + if (bhCtlColors.Num != 0) + PrintNumComment("COLORS Num", bhCtlColors.Num); + + // bhData uses offset in _afterHeader (not in _data) + // PrintNumComment("FONT TABLE SIZE", bhData.Offset - bhFont.Offset); + if (bhFont.Num != 0) + PrintNumComment("FONTS Num", bhFont.Num); + + // PrintNumComment("DATA SIZE", FirstHeader.HeaderSize - bhData.Offset); + if (bhData.Num != 0) + PrintNumComment("DATA NUM", bhData.Num); + + AddLF(); + + AddStringLF("OutFile [NSIS].exe"); + AddStringLF("!include WinMessages.nsh"); + + AddLF(); + + strUsed.Alloc(NumStringChars); + memset(strUsed, 0, NumStringChars); + + { + UInt32 ehFlags = Get32(p); + UInt32 showDetails = ehFlags & 3;// CH_FLAGS_DETAILS_SHOWDETAILS & CH_FLAGS_DETAILS_NEVERSHOW; + if (showDetails >= 1 && showDetails <= 2) + { + Script += IsInstaller ? "ShowInstDetails" : "ShowUninstDetails"; + Script += (showDetails == 1) ? " show" : " nevershow"; + AddLF(); + } + if (ehFlags & CH_FLAGS_PROGRESS_COLORED) AddStringLF("InstProgressFlags colored" ); + if ((ehFlags & (CH_FLAGS_SILENT | CH_FLAGS_SILENT_LOG)) != 0) + { + Script += IsInstaller ? "SilentInstall " : "SilentUnInstall "; + Script += (ehFlags & CH_FLAGS_SILENT_LOG) ? "silentlog" : "silent"; + AddLF(); + } + if (ehFlags & CH_FLAGS_AUTO_CLOSE) AddStringLF("AutoCloseWindow true"); + if ((ehFlags & CH_FLAGS_NO_ROOT_DIR) == 0) AddStringLF("AllowRootDirInstall true"); + if (ehFlags & CH_FLAGS_NO_CUSTOM) AddStringLF("InstType /NOCUSTOM"); + if (ehFlags & CH_FLAGS_COMP_ONLY_ON_CUSTOM) AddStringLF("InstType /COMPONENTSONLYONCUSTOM"); + } + + // Separator(); + // AddLF(); + + Int32 licenseLangIndex = -1; + { + const Byte *pp = _data + bhPages.Offset; + + for (UInt32 pageIndex = 0; pageIndex < bhPages.Num; pageIndex++, pp += kPageSize) + { + UInt32 wndProcID = Get32(pp + 4); + UInt32 param1 = Get32(pp + 44 + 4 * 1); + if (wndProcID != PWP_LICENSE || param1 == 0) + continue; + if ((Int32)param1 < 0) + licenseLangIndex = - ((Int32)param1 + 1); + else + noParseStringIndexes.AddToUniqueSorted(param1); + } + } + + unsigned paramsOffset = 4 + 8 * 8; + if (bhPages.Offset == 276) + paramsOffset -= 8; + + const Byte *p2 = p + paramsOffset; + + { + UInt32 rootKey = Get32(p2); // (rootKey = -1) in uninstaller by default (the bug in NSIS) + UInt32 subKey = Get32(p2 + 4); + UInt32 value = Get32(p2 + 8); + if ((rootKey != 0 && rootKey != (UInt32)(Int32)-1) || subKey != 0 || value != 0) + { + Script += "InstallDirRegKey"; + AddRegRoot(rootKey); + AddParam(subKey); + AddParam(value); + NewLine(); + } + } + + + { + UInt32 bg_color1 = Get32(p2 + 12); + UInt32 bg_color2 = Get32(p2 + 16); + UInt32 bg_textcolor = Get32(p2 + 20); + if (bg_color1 != (UInt32)(Int32)-1 || bg_color2 != (UInt32)(Int32)-1 || bg_textcolor != (UInt32)(Int32)-1) + { + Script += "BGGradient"; + if (bg_color1 != 0 || bg_color2 != 0xFF0000 || bg_textcolor != (UInt32)(Int32)-1) + { + Add_ColorParam(bg_color1); + Add_ColorParam(bg_color2); + if (bg_textcolor != (UInt32)(Int32)-1) + Add_ColorParam(bg_textcolor); + } + AddLF(); + } + } + + { + UInt32 lb_bg = Get32(p2 + 24); + UInt32 lb_fg = Get32(p2 + 28); + if ((lb_bg != (UInt32)(Int32)-1 || lb_fg != (UInt32)(Int32)-1) && + (lb_bg != 0 || lb_fg != 0xFF00)) + { + Script += "InstallColors"; + Add_ColorParam(lb_fg); + Add_ColorParam(lb_bg); + AddLF(); + } + } + + UInt32 license_bg = Get32(p2 + 36); + if (license_bg != (UInt32)(Int32)-1 && license_bg != -15) // COLOR_BTNFACE + { + Script += "LicenseBkColor"; + if ((Int32)license_bg == -5) // COLOR_WINDOW + Script += " /windows"; + /* + else if ((Int32)license_bg == -15) + Script += " /grey"; + */ else + Add_ColorParam(license_bg); + AddLF(); + } + + UInt32 langtable_size = Get32(p2 + 32); + if (bhLangTables.Num > 0) + { + UInt32 numStrings = (langtable_size - 10) / 4; + _numLangStrings = numStrings; + AddLF(); + Separator(); + PrintNumComment("LANG TABLES", bhLangTables.Num); + PrintNumComment("LANG STRINGS", numStrings); + AddLF(); + + if (licenseLangIndex >= 0) + { + for (UInt32 i = 0; i < bhLangTables.Num; i++) + { + const Byte *p = _data + bhLangTables.Offset + langtable_size * i; + LANGID langID = Get16(p); + UInt32 val = Get32(p + 10 + licenseLangIndex * 4); + if (val != 0) + { + Script += "LicenseLangString "; + Add_LangStr_Simple(licenseLangIndex); + AddParam_UInt(langID); + AddLicense(val, langID); + noParseStringIndexes.AddToUniqueSorted(val); + NewLine(); + } + } + AddLF(); + } + + UInt32 brandingText = 0; + UInt32 caption = 0; + UInt32 name = 0; + UInt32 i; + for (i = 0; i < bhLangTables.Num; i++) + { + const Byte *p = _data + bhLangTables.Offset + langtable_size * i; + LANGID langID = Get16(p); + if (i == 0 || langID == 1033) + _mainLang = p + 10; + { + UInt32 v = Get32(p + 10 + 0 * 4); + if (v != 0 && (langID == 1033 || brandingText == 0)) + brandingText = v; + } + { + UInt32 v = Get32(p + 10 + 1 * 4); + if (v != 0 && (langID == 1033 || caption == 0)) + caption = v; + } + { + UInt32 v = Get32(p + 10 + 2 * 4); + if (v != 0 && (langID == 1033 || name == 0)) + name = v; + } + } + + if (name != 0) { - if (c0 == 0 && c1 != 0) - numZeros0++; - if (c1 == 0) - numZeros1++; + Script += "Name"; + AddParam(name); + NewLine(); + + ReadString2(Name, name); + } + + /* + if (caption != 0) + { + Script += "Caption"; + AddParam(caption); + NewLine(); + } + */ + + if (brandingText != 0) + { + Script += "BrandingText"; + AddParam(brandingText); + NewLine(); + + ReadString2(BrandingText, brandingText); } - // printf("\nnumZeros0 = %2x %2x", _data[pos + 0], _data[pos + 1]); + + for (i = 0; i < bhLangTables.Num; i++) + { + const Byte *p = _data + bhLangTables.Offset + langtable_size * i; + LANGID langID = Get16(p); + + AddLF(); + AddCommentAndString("LANG:"); + AddParam_UInt(langID); + /* + Script += " ("; + LangId_To_String(Script, langID); + Script += ')'; + */ + AddLF(); + // UInt32 dlg_offset = Get32(p + 2); + // UInt32 g_exec_flags_rtl = Get32(p + 6); + + + for (UInt32 j = 0; j < numStrings; j++) + { + UInt32 val = Get32(p + 10 + j * 4); + if (val != 0) + { + if ((Int32)j != licenseLangIndex) + { + Script += "LangString "; + Add_LangStr_Simple(j); + AddParam_UInt(langID); + AddParam(val); + AddLF(); + } + } + } + AddLF(); + } + ClearLangComment(); } - IsUnicode = (numZeros1 > numZeros0 * 3 + kBlockSize / 16); - // printf("\nnumZeros0 = %3d numZeros1 = %3d", numZeros0, numZeros1); - return ReadEntries(bhEntries); + + { + unsigned numInternalVars = GET_NUM_INTERNAL_VARS; + UInt32 numUsedVars = GetNumUsedVars(); + if (numUsedVars > numInternalVars) + { + Separator(); + PrintNumComment("VARIABLES", numUsedVars - numInternalVars); + AddLF(); + AString temp; + for (UInt32 i = numInternalVars; i < numUsedVars; i++) + { + Script += "Var "; + temp.Empty(); + GetVar2(temp, i); + AddStringLF(temp); + } + AddLF(); + } + } + + onFuncOffset = paramsOffset + 40; + numOnFunc = ARRAY_SIZE(kOnFunc); + if (bhPages.Offset == 276) + numOnFunc--; + p2 += 40 + numOnFunc * 4; + + #define NSIS_MAX_INST_TYPES 32 + + AddLF(); + + UInt32 i; + for (i = 0; i < NSIS_MAX_INST_TYPES + 1; i++, p2 += 4) + { + UInt32 instType = Get32(p2); + if (instType != 0) + { + Script += "InstType"; + AString s2; + if (!IsInstaller) + s2 += "un."; + ReadString2(s2, instType); + SpaceQuStr(s2); + NewLine(); + } + } + + { + UInt32 installDir = Get32(p2); + p2 += 4; + if (installDir != 0) + { + Script += "InstallDir"; + AddParam(installDir); + NewLine(); + } + } + + if (bhPages.Offset >= 288) + for (i = 0; i < 4; i++) + { + if (i != 0 && bhPages.Offset < 300) + break; + UInt32 param = Get32(p2 + 4 * i); + if (param == 0 || param == (UInt32)(Int32)-1) + continue; + + /* + uninstaller: + UInt32 uninstChild = Get32(p2 + 8); // "$TEMP\\$1u_.exe" + UInt32 uninstCmd = Get32(p2 + 12); // "\"$TEMP\\$1u_.exe\" $0 _?=$INSTDIR\\" + int str_wininit = Get32(p2 + 16); // "$WINDIR\\wininit.ini" + */ + + AddCommentAndString(k_PostStrings[i]); + Script += " ="; + AddParam(param); + NewLine(); + } + + AddLF(); + + #endif + + RINOK(ReadEntries(bhEntries)); + + #ifdef NSIS_SCRIPT + + Separator(); + AddCommentAndString("UNREFERENCED STRINGS:"); + AddLF(); + AddLF(); + CommentOpen(); + + for (i = 0; i < NumStringChars;) + { + if (!strUsed[i] && i != 0) + // Script += "!!! "; + { + Add_UInt(i); + AddParam(i); + NewLine(); + } + if (IsUnicode) + i += GetUi16Str_Len((const Byte *)_data + _stringsPos + i * 2); + else + i += (UInt32)strlen((const char *)(const Byte *)_data + _stringsPos + i); + i++; + } + CommentClose(); + #endif + + return SortItems(); } static bool IsLZMA(const Byte *p, UInt32 &dictionary) { dictionary = Get32(p + 1); - return (p[0] == 0x5D && p[1] == 0x00 && p[2] == 0x00 && p[5] == 0x00); + return (p[0] == 0x5D && + p[1] == 0x00 && p[2] == 0x00 && + p[5] == 0x00 && (p[6] & 0x80) == 0x00); } static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag) @@ -1276,7 +5545,7 @@ static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag) thereIsFlag = false; return true; } - if (IsLZMA(p + 1, dictionary)) + if (p[0] <= 1 && IsLZMA(p + 1, dictionary)) { thereIsFlag = true; return true; @@ -1289,92 +5558,131 @@ static bool IsBZip2(const Byte *p) return (p[0] == 0x31 && p[1] < 14); } -HRESULT CInArchive::Open2( - DECL_EXTERNAL_CODECS_LOC_VARS2 - ) +HRESULT CInArchive::Open2(const Byte *sig, size_t size) { - RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &StreamOffset)); - - const UInt32 kSigSize = 4 + 1 + 5 + 1; // size, flag, lzma props, lzma first byte - BYTE sig[kSigSize]; - RINOK(ReadStream_FALSE(_stream, sig, kSigSize)); - UInt64 position; - RINOK(_stream->Seek(StreamOffset, STREAM_SEEK_SET, &position)); + const UInt32 kSigSize = 4 + 1 + 5 + 2; // size, flag, 5 - lzma props, 2 - lzma first bytes + if (size < kSigSize) + return S_FALSE; _headerIsCompressed = true; IsSolid = true; FilterFlag = false; + UseFilter = false; DictionarySize = 1; + #ifdef NSIS_SCRIPT + AfterHeaderSize = 0; + #endif + UInt32 compressedHeaderSize = Get32(sig); - if (compressedHeaderSize == FirstHeader.HeaderLength) + + /* + XX XX XX XX XX XX XX XX == FirstHeader.HeaderSize, nonsolid, uncompressed + 5D 00 00 dd dd 00 solid LZMA + 00 5D 00 00 dd dd 00 solid LZMA, empty filter (there are no such archives) + 01 5D 00 00 dd dd 00 solid LZMA, BCJ filter (only 7-Zip installer used that format) + + SS SS SS 80 00 5D 00 00 dd dd 00 non-solid LZMA, empty filter + SS SS SS 80 01 5D 00 00 dd dd 00 non-solid LZMA, BCJ filte + SS SS SS 80 01 tt non-solid BZip (tt < 14 + SS SS SS 80 non-solid deflate + + 01 tt solid BZip (tt < 14 + other solid Deflate + */ + + if (compressedHeaderSize == FirstHeader.HeaderSize) { _headerIsCompressed = false; IsSolid = false; Method = NMethodType::kCopy; } else if (IsLZMA(sig, DictionarySize, FilterFlag)) - { Method = NMethodType::kLZMA; - } - else if (IsLZMA(sig + 4, DictionarySize, FilterFlag)) - { - IsSolid = false; - Method = NMethodType::kLZMA; - } else if (sig[3] == 0x80) { IsSolid = false; - if (IsBZip2(sig + 4)) + if (IsLZMA(sig + 4, DictionarySize, FilterFlag) && sig[3] == 0x80) + Method = NMethodType::kLZMA; + else if (IsBZip2(sig + 4)) Method = NMethodType::kBZip2; else Method = NMethodType::kDeflate; } else if (IsBZip2(sig)) - { Method = NMethodType::kBZip2; - } else - { Method = NMethodType::kDeflate; - } - _posInData = 0; - if (!IsSolid) + if (IsSolid) + { + RINOK(_stream->Seek(DataStreamOffset, STREAM_SEEK_SET, NULL)); + } + else { - _headerIsCompressed = ((compressedHeaderSize & 0x80000000) != 0); - if (_headerIsCompressed) - compressedHeaderSize &= ~0x80000000; + _headerIsCompressed = ((compressedHeaderSize & kMask_IsCompressed) != 0); + compressedHeaderSize &= ~kMask_IsCompressed; _nonSolidStartOffset = compressedHeaderSize; - RINOK(_stream->Seek(StreamOffset + 4, STREAM_SEEK_SET, NULL)); + RINOK(_stream->Seek(DataStreamOffset + 4, STREAM_SEEK_SET, NULL)); } - UInt32 unpackSize = FirstHeader.HeaderLength; + + _data.Alloc(FirstHeader.HeaderSize); + _size = (size_t)FirstHeader.HeaderSize; + + Decoder.Method = Method; + Decoder.FilterFlag = FilterFlag; + Decoder.Solid = IsSolid; + Decoder.InputStream = _stream; + Decoder.Buffer.Alloc(kInputBufSize); + Decoder.StreamPos = 0; + if (_headerIsCompressed) { - // unpackSize = (1 << 23); - _data.SetCapacity(unpackSize); - RINOK(Decoder.Init( - EXTERNAL_CODECS_LOC_VARS - _stream, Method, FilterFlag, UseFilter)); - size_t processedSize = unpackSize; + RINOK(Decoder.Init(_stream, UseFilter)); + if (IsSolid) + { + size_t processedSize = 4; + Byte buf[4]; + RINOK(Decoder.Read(buf, &processedSize)); + if (processedSize != 4) + return S_FALSE; + if (Get32((const Byte *)buf) != FirstHeader.HeaderSize) + return S_FALSE; + } + size_t processedSize = FirstHeader.HeaderSize; RINOK(Decoder.Read(_data, &processedSize)); - if (processedSize != unpackSize) + if (processedSize != FirstHeader.HeaderSize) return S_FALSE; - _size = processedSize; + + #ifdef NSIS_SCRIPT if (IsSolid) { - UInt32 size2 = ReadUInt32(); - if (size2 < _size) - _size = size2; + /* we need additional bytes for data for WriteRegBin */ + AfterHeaderSize = (1 << 12); + _afterHeader.Alloc(AfterHeaderSize); + size_t processedSize = AfterHeaderSize; + RINOK(Decoder.Read(_afterHeader, &processedSize)); + AfterHeaderSize = (UInt32)processedSize; } + #endif } else { - _data.SetCapacity(unpackSize); - _size = (size_t)unpackSize; - RINOK(ReadStream_FALSE(_stream, (Byte *)_data, unpackSize)); + size_t processedSize = FirstHeader.HeaderSize; + RINOK(ReadStream(_stream, (Byte *)_data, &processedSize)); + if (processedSize < FirstHeader.HeaderSize) + return S_FALSE; } + + #ifdef NUM_SPEED_TESTS + for (unsigned i = 0; i < NUM_SPEED_TESTS; i++) + { + RINOK(Parse()); + Clear2(); + } + #endif + return Parse(); } @@ -1404,57 +5712,212 @@ FirstHeader UInt32 Flags; Byte Signature[16]; // points to the header+sections+entries+stringtable in the datablock - UInt32 HeaderLength; - UInt32 ArchiveSize; + UInt32 HeaderSize; + UInt32 ArcSize; } */ -HRESULT CInArchive::Open( - DECL_EXTERNAL_CODECS_LOC_VARS - IInStream *inStream, const UInt64 *maxCheckStartPosition) + +// ---------- PE (EXE) parsing ---------- + +static const unsigned k_PE_StartSize = 0x40; +static const unsigned k_PE_HeaderSize = 4 + 20; +static const unsigned k_PE_OptHeader32_Size_MIN = 96; + +static inline bool CheckPeOffset(UInt32 pe) +{ + return (pe >= 0x40 && pe <= 0x1000 && (pe & 7) == 0); +} + + +static bool IsArc_Pe(const Byte *p, size_t size) +{ + if (size < 2) + return false; + if (p[0] != 'M' || p[1] != 'Z') + return false; + if (size < k_PE_StartSize) + return false; // k_IsArc_Res_NEED_MORE; + UInt32 pe = Get32(p + 0x3C); + if (!CheckPeOffset(pe)) + return false; + if (pe + k_PE_HeaderSize > size) + return false; // k_IsArc_Res_NEED_MORE; + + p += pe; + if (Get32(p) != 0x00004550) + return false; + return Get16(p + 4 + 16) >= k_PE_OptHeader32_Size_MIN; +} + +HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *maxCheckStartPosition) { Clear(); - RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); - UInt64 maxSize = ((maxCheckStartPosition != 0) ? *maxCheckStartPosition : 0); - const UInt32 kStep = 512; - Byte buffer[kStep]; - UInt64 position = 0; - for (; position <= maxSize; position += kStep) + RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &StartOffset)); + + const UInt32 kStartHeaderSize = 4 * 7; + const unsigned kStep = 512; // nsis start is aligned for 512 + Byte buf[kStep]; + UInt64 pos = StartOffset; + size_t bufSize = 0; + UInt64 pePos = (UInt64)(Int64)-1; + + for (;;) { - RINOK(ReadStream_FALSE(inStream, buffer, kStep)); - if (memcmp(buffer + 4, kSignature, kSignatureSize) == 0) + bufSize = kStep; + RINOK(ReadStream(inStream, buf, &bufSize)); + if (bufSize < kStartHeaderSize) + return S_FALSE; + if (memcmp(buf + 4, kSignature, kSignatureSize) == 0) break; + if (IsArc_Pe(buf, bufSize)) + pePos = pos; + pos += kStep; + UInt64 proc = pos - StartOffset; + if (maxCheckStartPosition && proc > *maxCheckStartPosition) + { + if (pePos == 0) + { + if (proc > (1 << 20)) + return S_FALSE; + } + else + return S_FALSE; + } + } + + if (pePos == (UInt64)(Int64)-1) + { + UInt64 posCur = StartOffset; + for (;;) + { + if (posCur < kStep) + break; + posCur -= kStep; + if (pos - posCur > (1 << 20)) + break; + bufSize = kStep; + RINOK(inStream->Seek(posCur, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream(inStream, buf, &bufSize)); + if (bufSize < kStep) + break; + if (IsArc_Pe(buf, bufSize)) + { + pePos = posCur; + break; + } + } + + // restore buf to nsis header + bufSize = kStep; + RINOK(inStream->Seek(pos, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream(inStream, buf, &bufSize)); + if (bufSize < kStartHeaderSize) + return S_FALSE; + } + + StartOffset = pos; + UInt32 peSize = 0; + + if (pePos != (UInt64)(Int64)-1) + { + UInt64 peSize64 = (pos - pePos); + if (peSize64 < (1 << 20)) + { + peSize = (UInt32)peSize64; + StartOffset = pePos; + } } - if (position > maxSize) + + DataStreamOffset = pos + kStartHeaderSize; + FirstHeader.Flags = Get32(buf); + if ((FirstHeader.Flags & (~kFlagsMask)) != 0) return S_FALSE; - const UInt32 kStartHeaderSize = 4 * 7; - RINOK(inStream->Seek(0, STREAM_SEEK_END, &_archiveSize)); - RINOK(inStream->Seek(position + kStartHeaderSize, STREAM_SEEK_SET, 0)); - FirstHeader.Flags = Get32(buffer); - FirstHeader.HeaderLength = Get32(buffer + kSignatureSize + 4); - FirstHeader.ArchiveSize = Get32(buffer + kSignatureSize + 8); - if (_archiveSize - position < FirstHeader.ArchiveSize) + IsInstaller = (FirstHeader.Flags & NFlags::kUninstall) == 0; + + FirstHeader.HeaderSize = Get32(buf + kSignatureSize + 4); + FirstHeader.ArcSize = Get32(buf + kSignatureSize + 8); + if (FirstHeader.ArcSize <= kStartHeaderSize) return S_FALSE; + + RINOK(inStream->Seek(0, STREAM_SEEK_END, &_fileSize)); + IsArc = true; + + if (peSize != 0) + { + ExeStub.Alloc(peSize); + RINOK(inStream->Seek(pePos, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(inStream, ExeStub, peSize)); + } + + HRESULT res = S_FALSE; try { - _stream = inStream; - HRESULT res = Open2(EXTERNAL_CODECS_LOC_VARS2); - if (res != S_OK) - Clear(); + CLimitedInStream *_limitedStreamSpec = new CLimitedInStream; + _stream = _limitedStreamSpec; + _limitedStreamSpec->SetStream(inStream); + _limitedStreamSpec->InitAndSeek(pos, FirstHeader.ArcSize); + DataStreamOffset -= pos; + res = Open2(buf + kStartHeaderSize, bufSize - kStartHeaderSize); + } + catch(...) + { + _stream.Release(); + throw; + // res = S_FALSE; + } + if (res != S_OK) + { _stream.Release(); - return res; + // Clear(); } - catch(...) { Clear(); return S_FALSE; } + return res; } -void CInArchive::Clear() +UString CInArchive::ConvertToUnicode(const AString &s) const +{ + if (IsUnicode) + { + UString res; + if (ConvertUTF8ToUnicode(s, res)) + return res; + } + return MultiByteToUnicodeString(s); +} + +void CInArchive::Clear2() { + IsUnicode = false; + NsisType = k_NsisType_Nsis2; + IsNsis225 = false; + IsNsis200 = false; + LogCmdIsEnabled = false; + BadCmd = -1; + #ifdef NSIS_SCRIPT + Name.Empty(); + BrandingText.Empty(); Script.Empty(); + LicenseFiles.Clear(); + _numRootLicenses = 0; + langStrIDs.Clear(); + LangComment.Empty(); + noParseStringIndexes.Clear(); #endif + + APrefixes.Clear(); + UPrefixes.Clear(); Items.Clear(); + IsUnicode = false; + ExeStub.Free(); +} + +void CInArchive::Clear() +{ + Clear2(); + IsArc = false; _stream.Release(); } diff --git a/CPP/7zip/Archive/Nsis/NsisIn.h b/CPP/7zip/Archive/Nsis/NsisIn.h index 7ca719e4..3acd9ee5 100755..100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.h +++ b/CPP/7zip/Archive/Nsis/NsisIn.h @@ -3,21 +3,28 @@ #ifndef __ARCHIVE_NSIS_IN_H #define __ARCHIVE_NSIS_IN_H -#include "Common/Buffer.h" -#include "Common/MyCom.h" -#include "Common/StringConvert.h" +#include "../../../../C/CpuArch.h" + +#include "../../../Common/DynLimBuf.h" +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyCom.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" #include "NsisDecode.h" -// #define NSIS_SCRIPT +/* If NSIS_SCRIPT is defined, it will decompile NSIS script to [NSIS].nsi file. + The code is much larger in that case. */ + +#define NSIS_SCRIPT namespace NArchive { namespace NNsis { -const int kSignatureSize = 16; -#define NSIS_SIGNATURE { 0xEF, 0xBE, 0xAD, 0xDE, 0x4E, 0x75, 0x6C, 0x6C, 0x73, 0x6F, 0x66, 0x74, 0x49, 0x6E, 0x73, 0x74} +const size_t kScriptSizeLimit = 1 << 27; -extern Byte kSignature[kSignatureSize]; +const unsigned kSignatureSize = 16; +#define NSIS_SIGNATURE { 0xEF, 0xBE, 0xAD, 0xDE, 'N', 'u', 'l', 'l', 's', 'o', 'f', 't', 'I', 'n', 's', 't' } const UInt32 kFlagsMask = 0xF; namespace NFlags @@ -31,18 +38,17 @@ namespace NFlags struct CFirstHeader { UInt32 Flags; - UInt32 HeaderLength; - - UInt32 ArchiveSize; + UInt32 HeaderSize; + UInt32 ArcSize; bool ThereIsCrc() const { - if ((Flags & NFlags::kForceCrc ) != 0) - return true; - return ((Flags & NFlags::kNoCrc) == 0); + return + (Flags & NFlags::kForceCrc) != 0 || + (Flags & NFlags::kNoCrc) == 0; } - UInt32 GetDataSize() const { return ArchiveSize - (ThereIsCrc() ? 4 : 0); } + UInt32 GetDataSize() const { return ArcSize - (ThereIsCrc() ? 4 : 0); } }; @@ -50,123 +56,330 @@ struct CBlockHeader { UInt32 Offset; UInt32 Num; + + void Parse(const Byte *p) + { + Offset = GetUi32(p); + Num = GetUi32(p + 4); + } }; struct CItem { - AString PrefixA; - UString PrefixU; - AString NameA; - UString NameU; - FILETIME MTime; - bool IsUnicode; - bool UseFilter; bool IsCompressed; - bool SizeIsDefined; - bool CompressedSizeIsDefined; - bool EstimatedSizeIsDefined; + bool Size_Defined; + bool CompressedSize_Defined; + bool EstimatedSize_Defined; + bool Attrib_Defined; + bool IsUninstaller; + // bool UseFilter; + + UInt32 Attrib; UInt32 Pos; UInt32 Size; UInt32 CompressedSize; UInt32 EstimatedSize; UInt32 DictionarySize; - - CItem(): IsUnicode(false), UseFilter(false), IsCompressed(true), SizeIsDefined(false), - CompressedSizeIsDefined(false), EstimatedSizeIsDefined(false), Size(0), DictionarySize(1) {} + UInt32 PatchSize; // for Uninstaller.exe + int Prefix; // - 1 means no prefix - bool IsINSTDIR() const + FILETIME MTime; + AString NameA; + UString NameU; + + CItem(): + IsCompressed(true), + Size_Defined(false), + CompressedSize_Defined(false), + EstimatedSize_Defined(false), + Attrib_Defined(false), + IsUninstaller(false), + // UseFilter(false), + Attrib(0), + Pos(0), + Size(0), + CompressedSize(0), + EstimatedSize(0), + DictionarySize(1), + PatchSize(0), + Prefix(-1) { - return (PrefixA.Length() >= 3 || PrefixU.Length() >= 3); + MTime.dwLowDateTime = 0; + MTime.dwHighDateTime = 0; } - UString GetReducedName(bool unicode) const + /* + bool IsINSTDIR() const { - UString s; - if (unicode) - s = PrefixU; - else - s = MultiByteToUnicodeString(PrefixA); - if (s.Length() > 0) - if (s.Back() != L'\\') - s += L'\\'; - if (unicode) - s += NameU; - else - s += MultiByteToUnicodeString(NameA); - const int len = 9; - if (s.Left(len).CompareNoCase(L"$INSTDIR\\") == 0) - s = s.Mid(len); - return s; + return (PrefixA.Len() >= 3 || PrefixU.Len() >= 3); } + */ }; -class CInArchive +enum ENsisType { - UInt64 _archiveSize; - CMyComPtr<IInStream> _stream; - - Byte ReadByte(); - UInt32 ReadUInt32(); - HRESULT Open2( - DECL_EXTERNAL_CODECS_LOC_VARS2 - ); - void ReadBlockHeader(CBlockHeader &bh); - AString ReadStringA(UInt32 pos) const; - UString ReadStringU(UInt32 pos) const; - AString ReadString2A(UInt32 pos) const; - UString ReadString2U(UInt32 pos) const; - AString ReadString2(UInt32 pos) const; - AString ReadString2Qw(UInt32 pos) const; - HRESULT ReadEntries(const CBlockHeader &bh); - HRESULT Parse(); + k_NsisType_Nsis2, + k_NsisType_Nsis3, + k_NsisType_Park1, // Park 2.46.1- + k_NsisType_Park2, // Park 2.46.2 : GetFontVersion + k_NsisType_Park3 // Park 2.46.3+ : GetFontName +}; + +#ifdef NSIS_SCRIPT +struct CSection +{ + UInt32 InstallTypes; // bits set for each of the different install_types, if any. + UInt32 Flags; // SF_* - defined above + UInt32 StartCmdIndex; // code; + UInt32 NumCommands; // code_size; + UInt32 SizeKB; + UInt32 Name; + + void Parse(const Byte *data); +}; + +struct CLicenseFile +{ + UInt32 Offset; + UInt32 Size; + AString Name; + CByteBuffer Text; +}; + +#endif + +class CInArchive +{ +public: + #ifdef NSIS_SCRIPT + CDynLimBuf Script; + #endif CByteBuffer _data; - UInt64 _size; + CObjectVector<CItem> Items; + bool IsUnicode; +private: + UInt32 _stringsPos; // relative to _data + UInt32 NumStringChars; + size_t _size; // it's Header Size - size_t _posInData; + AString Raw_AString; + UString Raw_UString; - UInt32 _stringsPos; + ENsisType NsisType; + bool IsNsis200; // NSIS 2.03 and before + bool IsNsis225; // NSIS 2.25 and before + + bool LogCmdIsEnabled; + int BadCmd; // -1: no bad command; in another cases lowest bad command id + bool IsPark() const { return NsisType >= k_NsisType_Park1; } + UInt64 _fileSize; + bool _headerIsCompressed; UInt32 _nonSolidStartOffset; + + #ifdef NSIS_SCRIPT + + CByteBuffer strUsed; + + CBlockHeader bhPages; + CBlockHeader bhSections; + CBlockHeader bhCtlColors; + CBlockHeader bhData; + UInt32 AfterHeaderSize; + CByteBuffer _afterHeader; + + UInt32 SectionSize; + const Byte *_mainLang; + UInt32 _numLangStrings; + AString LangComment; + CRecordVector<UInt32> langStrIDs; + UInt32 numOnFunc; + UInt32 onFuncOffset; + // CRecordVector<UInt32> OnFuncs; + unsigned _numRootLicenses; + CRecordVector<UInt32> noParseStringIndexes; + AString _tempString_for_GetVar; + AString _tempString_for_AddFuncName; + AString _tempString; + + #endif + + public: - HRESULT Open( - DECL_EXTERNAL_CODECS_LOC_VARS - IInStream *inStream, const UInt64 *maxCheckStartPosition); - void Clear(); + CMyComPtr<IInStream> _stream; // it's limited stream that contains only NSIS archive + UInt64 StartOffset; // offset in original stream. + UInt64 DataStreamOffset; // = sizeof(FirstHeader) = offset of Header in _stream + + bool IsArc; - UInt64 StreamOffset; CDecoder Decoder; - CObjectVector<CItem> Items; + CByteBuffer ExeStub; CFirstHeader FirstHeader; NMethodType::EEnum Method; UInt32 DictionarySize; bool IsSolid; bool UseFilter; bool FilterFlag; - bool IsUnicode; + + bool IsInstaller; + AString Name; + AString BrandingText; + UStringVector UPrefixes; + AStringVector APrefixes; #ifdef NSIS_SCRIPT - AString Script; + CObjectVector<CLicenseFile> LicenseFiles; #endif - UInt32 GetOffset() const { return IsSolid ? 4 : 0; } - UInt64 GetDataPos(int index) + +private: + void GetShellString(AString &s, unsigned index1, unsigned index2); + void GetNsisString_Raw(const Byte *s); + void GetNsisString_Unicode_Raw(const Byte *s); + void ReadString2_Raw(UInt32 pos); + bool IsGoodString(UInt32 param) const; + bool AreTwoParamStringsEqual(UInt32 param1, UInt32 param2) const; + + void Add_LangStr(AString &res, UInt32 id); + + #ifdef NSIS_SCRIPT + + void Add_UInt(UInt32 v); + void AddLicense(UInt32 param, Int32 langID); + + void Add_LangStr_Simple(UInt32 id); + void Add_FuncName(const UInt32 *labels, UInt32 index); + void AddParam_Func(const UInt32 *labels, UInt32 index); + void Add_LabelName(UInt32 index); + + void Add_Color2(UInt32 v); + void Add_ColorParam(UInt32 v); + void Add_Color(UInt32 index); + + void Add_ButtonID(UInt32 buttonID); + + void Add_ShowWindow_Cmd(UInt32 cmd); + void Add_TypeFromList(const char **table, unsigned tableSize, UInt32 type); + void Add_ExecFlags(UInt32 flagsType); + void Add_SectOp(UInt32 opType); + + void Add_Var(UInt32 index); + void AddParam_Var(UInt32 value); + void AddParam_UInt(UInt32 value); + + void Add_GotoVar(UInt32 param); + void Add_GotoVar1(UInt32 param); + void Add_GotoVars2(const UInt32 *params); + + + + bool PrintSectionBegin(const CSection §, unsigned index); + void PrintSectionEnd(); + + void GetNsisString(AString &res, const Byte *s); + void GetNsisString_Unicode(AString &res, const Byte *s); + UInt32 GetNumUsedVars() const; + void ReadString2(AString &s, UInt32 pos); + + void MessageBox_MB_Part(UInt32 param); + void AddParam(UInt32 pos); + void AddOptionalParam(UInt32 pos); + void AddParams(const UInt32 *params, unsigned num); + void AddPageOption1(UInt32 param, const char *name); + void AddPageOption(const UInt32 *params, unsigned num, const char *name); + void AddOptionalParams(const UInt32 *params, unsigned num); + void AddRegRoot(UInt32 value); + + + void ClearLangComment(); + void Separator(); + void Space(); + void Tab(); + void Tab(bool commented); + void BigSpaceComment(); + void SmallSpaceComment(); + void AddCommentAndString(const char *s); + void AddError(const char *s); + void AddErrorLF(const char *s); + void CommentOpen(); + void CommentClose(); + void AddLF(); + void AddQuotes(); + void TabString(const char *s); + void AddStringLF(const char *s); + void NewLine(); + void PrintNumComment(const char *name, UInt32 value); + void Add_QuStr(const AString &s); + void SpaceQuStr(const AString &s); + bool CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands); + + #endif + + #ifdef NSIS_SCRIPT + unsigned GetNumSupportedCommands() const; + #endif + + UInt32 GetCmd(UInt32 a); + void FindBadCmd(const CBlockHeader &bh, const Byte *); + void DetectNsisType(const CBlockHeader &bh, const Byte *); + + HRESULT ReadEntries(const CBlockHeader &bh); + HRESULT SortItems(); + HRESULT Parse(); + HRESULT Open2(const Byte *data, size_t size); + void Clear2(); + + void GetVar2(AString &res, UInt32 index); + void GetVar(AString &res, UInt32 index); + Int32 GetVarIndex(UInt32 strPos) const; + Int32 GetVarIndex(UInt32 strPos, UInt32 &resOffset) const; + Int32 GetVarIndexFinished(UInt32 strPos, Byte endChar, UInt32 &resOffset) const; + bool IsVarStr(UInt32 strPos, UInt32 varIndex) const; + bool IsAbsolutePathVar(UInt32 strPos) const; + void SetItemName(CItem &item, UInt32 strPos); + +public: + HRESULT Open(IInStream *inStream, const UInt64 *maxCheckStartPosition); + AString GetFormatDescription() const; + HRESULT InitDecoder() + { + bool useFilter; + return Decoder.Init(_stream, useFilter); + } + + HRESULT SeekTo_DataStreamOffset() + { + return _stream->Seek(DataStreamOffset, STREAM_SEEK_SET, NULL); + } + + HRESULT SeekToNonSolidItem(unsigned index) + { + return _stream->Seek(GetPosOfNonSolidItem(index), STREAM_SEEK_SET, NULL); + } + + void Clear(); + + bool IsDirectString_Equal(UInt32 offset, const char *s) const; + /* + UInt64 GetDataPos(unsigned index) { const CItem &item = Items[index]; - return GetOffset() + FirstHeader.HeaderLength + item.Pos; + return GetOffset() + FirstHeader.HeaderSize + item.Pos; } + */ - UInt64 GetPosOfSolidItem(int index) const + UInt64 GetPosOfSolidItem(unsigned index) const { const CItem &item = Items[index]; - return 4 + FirstHeader.HeaderLength + item.Pos; + return 4 + (UInt64)FirstHeader.HeaderSize + item.Pos; } - UInt64 GetPosOfNonSolidItem(int index) const + UInt64 GetPosOfNonSolidItem(unsigned index) const { const CItem &item = Items[index]; - return StreamOffset + _nonSolidStartOffset + 4 + item.Pos; + return DataStreamOffset + _nonSolidStartOffset + 4 + item.Pos; } void Release() @@ -174,6 +387,52 @@ public: Decoder.Release(); } + bool IsTruncated() const { return (_fileSize - StartOffset < FirstHeader.ArcSize); } + + UString GetReducedName(unsigned index) const + { + const CItem &item = Items[index]; + + UString s; + if (item.Prefix >= 0) + { + if (IsUnicode) + s = UPrefixes[item.Prefix]; + else + s = MultiByteToUnicodeString(APrefixes[item.Prefix]); + if (s.Len() > 0) + if (s.Back() != L'\\') + s += L'\\'; + } + + if (IsUnicode) + { + s += item.NameU; + if (item.NameU.IsEmpty()) + s += L"file"; + } + else + { + s += MultiByteToUnicodeString(item.NameA); + if (item.NameA.IsEmpty()) + s += L"file"; + } + + const char *kRemoveStr = "$INSTDIR\\"; + if (s.IsPrefixedBy_Ascii_NoCase(kRemoveStr)) + s.Delete(0, MyStringLen(kRemoveStr)); + if (item.IsUninstaller && ExeStub.Size() == 0) + s += L".nsis"; + return s; + } + + UString ConvertToUnicode(const AString &s) const; + + CInArchive() + #ifdef NSIS_SCRIPT + : Script(kScriptSizeLimit) + #endif + {} }; }} diff --git a/CPP/7zip/Archive/Nsis/NsisRegister.cpp b/CPP/7zip/Archive/Nsis/NsisRegister.cpp index 41dedb0d..b363bdec 100755..100644 --- a/CPP/7zip/Archive/Nsis/NsisRegister.cpp +++ b/CPP/7zip/Archive/Nsis/NsisRegister.cpp @@ -5,9 +5,20 @@ #include "../../Common/RegisterArc.h" #include "NsisHandler.h" -static IInArchive *CreateArc() { return new NArchive::NNsis::CHandler; } + +namespace NArchive { +namespace NNsis { + +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"Nsis", L"", 0, 0x9, NSIS_SIGNATURE, NArchive::NNsis::kSignatureSize, false, CreateArc, 0 }; + { "Nsis", "nsis", 0, 0x9, + NArchive::NNsis::kSignatureSize, NSIS_SIGNATURE, + 4, + NArcInfoFlags::kFindSignature | + NArcInfoFlags::kUseGlobalOffset, + CreateArc }; REGISTER_ARC(Nsis) + +}} diff --git a/CPP/7zip/Archive/Nsis/StdAfx.h b/CPP/7zip/Archive/Nsis/StdAfx.h index 2e4be10b..2854ff3e 100755..100644 --- a/CPP/7zip/Archive/Nsis/StdAfx.h +++ b/CPP/7zip/Archive/Nsis/StdAfx.h @@ -3,7 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" -#include "../../../Common/NewHandler.h" +#include "../../../Common/Common.h" #endif diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp index 505486fc..dfe5eade 100755..100644 --- a/CPP/7zip/Archive/NtfsHandler.cpp +++ b/CPP/7zip/Archive/NtfsHandler.cpp @@ -11,15 +11,15 @@ #include "../../../C/CpuArch.h" -#include "Common/Buffer.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/MyCom.h" -#include "Common/StringConvert.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/MyCom.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" +#include "../Common/MethodProps.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" @@ -30,8 +30,10 @@ #ifdef SHOW_DEBUG_INFO #define PRF(x) x +#define PRF_UTF16(x) PRF(printf("%S", x)) #else #define PRF(x) +#define PRF_UTF16(x) #endif #ifdef SHOW_DEBUG_INFO2 @@ -48,26 +50,36 @@ #define G32(p, dest) dest = Get32(p); #define G64(p, dest) dest = Get64(p); +using namespace NWindows; + namespace NArchive { namespace Ntfs { -static const UInt32 kNumSysRecs = 16; -static const UInt32 kRecIndex_Volume = 3; -static const UInt32 kRecIndex_BadClus = 8; +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 unsigned kNumSysRecs = 16; + +static const unsigned kRecIndex_Volume = 3; +static const unsigned kRecIndex_BadClus = 8; +static const unsigned kRecIndex_Security = 9; struct CHeader { - Byte SectorSizeLog; - Byte ClusterSizeLog; + unsigned SectorSizeLog; + unsigned ClusterSizeLog; // Byte MediaType; UInt32 NumHiddenSectors; + UInt64 NumSectors; UInt64 NumClusters; UInt64 MftCluster; UInt64 SerialNumber; UInt16 SectorsPerTrack; UInt16 NumHeads; - UInt64 GetPhySize() const { return NumClusters << ClusterSizeLog; } + UInt64 GetPhySize_Clusters() const { return NumClusters << ClusterSizeLog; } + UInt64 GetPhySize_Max() const { return (NumSectors + 1) << SectorSizeLog; } UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; } bool Parse(const Byte *p); }; @@ -89,35 +101,38 @@ bool CHeader::Parse(const Byte *p) switch (p[0]) { case 0xE9: codeOffset = 3 + (Int16)Get16(p + 1); break; - case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (signed char)p[1]; break; + case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (int)(signed char)p[1]; break; default: return false; } - Byte sectorsPerClusterLog; + unsigned sectorsPerClusterLog; if (memcmp(p + 3, "NTFS ", 8) != 0) return false; { - int s = GetLog(Get16(p + 11)); - if (s < 9 || s > 12) + int t = GetLog(Get16(p + 11)); + if (t < 9 || t > 12) return false; - SectorSizeLog = (Byte)s; - s = GetLog(p[13]); - if (s < 0) + SectorSizeLog = t; + t = GetLog(p[13]); + if (t < 0) return false; - sectorsPerClusterLog = (Byte)s; + sectorsPerClusterLog = t; ClusterSizeLog = SectorSizeLog + sectorsPerClusterLog; + if (ClusterSizeLog > 30) + return false; } for (int i = 14; i < 21; i++) if (p[i] != 0) return false; - // MediaType = p[21]; + if (p[21] != 0xF8) // MediaType = Fixed_Disk + return false; if (Get16(p + 22) != 0) // NumFatSectors return false; - G16(p + 24, SectorsPerTrack); - G16(p + 26, NumHeads); - G32(p + 28, NumHiddenSectors); + G16(p + 24, SectorsPerTrack); // 63 usually + G16(p + 26, NumHeads); // 255 + G32(p + 28, NumHiddenSectors); // 63 (XP) / 2048 (Vista and win7) / (0 on media that are not partitioned ?) if (Get32(p + 32) != 0) // NumSectors32 return false; @@ -132,15 +147,19 @@ bool CHeader::Parse(const Byte *p) return false; if (p[0x27] != 0) // reserved return false; - UInt64 numSectors = Get64(p + 0x28); - NumClusters = numSectors >> sectorsPerClusterLog; + + NumSectors = Get64(p + 0x28); + if (NumSectors >= ((UInt64)1 << (62 - SectorSizeLog))) + return false; + + NumClusters = NumSectors >> sectorsPerClusterLog; G64(p + 0x30, MftCluster); // G64(p + 0x38, Mft2Cluster); G64(p + 0x48, SerialNumber); UInt32 numClustersInMftRec; UInt32 numClustersInIndexBlock; - G32(p + 0x40, numClustersInMftRec); + G32(p + 0x40, numClustersInMftRec); // -10 means 2 ^10 = 1024 bytes. G32(p + 0x44, numClustersInIndexBlock); return (numClustersInMftRec < 256 && numClustersInIndexBlock < 256); } @@ -148,6 +167,7 @@ bool CHeader::Parse(const Byte *p) struct CMftRef { UInt64 Val; + UInt64 GetIndex() const { return Val & (((UInt64)1 << 48) - 1); } UInt16 GetNumber() const { return (UInt16)(Val >> 48); } bool IsBaseItself() const { return Val == 0; } @@ -178,17 +198,19 @@ enum DEF_ATTR_TYPE(0x1000, FIRST_USER_DEFINED_ATTRIBUTE) }; -static const Byte kFileNameType_Posix = 0; -static const Byte kFileNameType_Win32 = 1; -static const Byte kFileNameType_Dos = 2; -static const Byte kFileNameType_Win32Dos = 3; +static const Byte kFileNameType_Posix = 0; +static const Byte kFileNameType_Win32 = 1; +static const Byte kFileNameType_Dos = 2; +static const Byte kFileNameType_Win32Dos = 3; struct CFileNameAttr { CMftRef ParentDirRef; + + // Probably these timestamps don't contain some useful timestamps. So we don't use them // UInt64 CTime; // UInt64 MTime; - // UInt64 ThisRecMTime; + // UInt64 ThisRecMTime; // xp-64: the time of previous name change (not last name change. why?) // UInt64 ATime; // UInt64 AllocatedSize; // UInt64 DataSize; @@ -201,12 +223,12 @@ struct CFileNameAttr bool Parse(const Byte *p, unsigned size); }; -static void GetString(const Byte *p, unsigned length, UString &res) +static void GetString(const Byte *p, unsigned len, UString &res) { - wchar_t *s = res.GetBuffer(length); - for (unsigned i = 0; i < length; i++) + wchar_t *s = res.GetBuffer(len); + for (unsigned i = 0; i < len; i++) s[i] = Get16(p + i * 2); - s[length] = 0; + s[len] = 0; res.ReleaseBuffer(); } @@ -224,10 +246,10 @@ bool CFileNameAttr::Parse(const Byte *p, unsigned size) G32(p + 0x38, Attrib); // G16(p + 0x3C, PackedEaSize); NameType = p[0x41]; - unsigned length = p[0x40]; - if (0x42 + length > size) + unsigned len = p[0x40]; + if (0x42 + len > size) return false; - GetString(p + 0x42, length, Name); + GetString(p + 0x42, len, Name); return true; } @@ -244,9 +266,9 @@ struct CSiAttr UInt32 Version; UInt32 ClassId; UInt32 OwnerId; - UInt32 SecurityId; - UInt64 QuotaCharged; */ + UInt32 SecurityId; // SecurityId = 0 is possible ? + // UInt64 QuotaCharged; bool Parse(const Byte *p, unsigned size); }; @@ -260,6 +282,9 @@ bool CSiAttr::Parse(const Byte *p, unsigned size) // G64(p + 0x10, ThisRecMTime); G64(p + 0x18, ATime); G32(p + 0x20, Attrib); + SecurityId = 0; + if (size >= 0x38) + G32(p + 0x34, SecurityId); return true; } @@ -295,7 +320,7 @@ bool CVolInfo::Parse(const Byte *p, unsigned size) struct CAttr { UInt32 Type; - // UInt32 Length; + // UInt32 Len; UString Name; // UInt16 Flags; // UInt16 Instance; @@ -317,15 +342,15 @@ struct CAttr bool IsCompressionUnitSupported() const { return CompressionUnit == 0 || CompressionUnit == 4; } UInt32 Parse(const Byte *p, unsigned size); - bool ParseFileName(CFileNameAttr &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); } - bool ParseSi(CSiAttr &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); } - bool ParseVolInfo(CVolInfo &a) const { return a.Parse(Data, (unsigned)Data.GetCapacity()); } - bool ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, int compressionUnit) const; - UInt64 GetSize() const { return NonResident ? Size : Data.GetCapacity(); } + bool ParseFileName(CFileNameAttr &a) const { return a.Parse(Data, (unsigned)Data.Size()); } + bool ParseSi(CSiAttr &a) const { return a.Parse(Data, (unsigned)Data.Size()); } + bool ParseVolInfo(CVolInfo &a) const { return a.Parse(Data, (unsigned)Data.Size()); } + bool ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, unsigned compressionUnit) const; + UInt64 GetSize() const { return NonResident ? Size : Data.Size(); } UInt64 GetPackSize() const { if (!NonResident) - return Data.GetCapacity(); + return Data.Size(); if (CompressionUnit != 0) return PackSize; return AllocatedSize; @@ -339,7 +364,7 @@ static int CompareAttr(void *const *elem1, void *const *elem2, void *) const CAttr &a1 = *(*((const CAttr **)elem1)); const CAttr &a2 = *(*((const CAttr **)elem2)); RINOZ(MyCompare(a1.Type, a2.Type)); - RINOZ(MyCompare(a1.Name, a2.Name)); + RINOZ(wcscmp(a1.Name, a2.Name)); return MyCompare(a1.LowVcn, a2.LowVcn); } @@ -349,25 +374,28 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size) return 0; G32(p, Type); if (Type == 0xFFFFFFFF) - return 4; + 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 length = Get32(p + 0x04); - PRF(printf(" L=%3d", length)); - if (length > size) + UInt32 len = Get32(p + 0x04); + PRF(printf(" L=%3d", len)); + if (len > size) + return 0; + if ((len & 7) != 0) return 0; NonResident = p[0x08]; { - int nameLength = p[9]; + unsigned nameLength = p[9]; UInt32 nameOffset = Get16(p + 0x0A); if (nameLength != 0) { - if (nameOffset + nameLength * 2 > length) + if (nameOffset + nameLength * 2 > len) return 0; GetString(p + nameOffset, nameLength, Name); - PRF(printf(" N=%S", Name)); + PRF(printf(" N=")); + PRF_UTF16(Name); } } @@ -380,7 +408,7 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size) UInt32 offs; if (NonResident) { - if (length < 0x40) + if (len < 0x40) return 0; PRF(printf(" NR")); G64(p + 0x10, LowVcn); @@ -394,7 +422,7 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size) PackSize = Size; if (CompressionUnit != 0) { - if (length < 0x48) + if (len < 0x48) return 0; G64(p + 0x40, PackSize); PRF(printf(" PS=%I64x", PackSize)); @@ -406,12 +434,12 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size) PRF(printf(" IS=%I64d", InitializedSize)); PRF(printf(" Low=%I64d", LowVcn)); PRF(printf(" High=%I64d", HighVcn)); - PRF(printf(" CU=%d", (int)CompressionUnit)); - dataSize = length - offs; + PRF(printf(" CU=%d", (unsigned)CompressionUnit)); + dataSize = len - offs; } else { - if (length < 0x18) + if (len < 0x18) return 0; PRF(printf(" RES")); dataSize = Get32(p + 0x10); @@ -420,24 +448,23 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size) // G16(p + 0x16, ResidentFlags); // PRF(printf(" ResFlags=%4X", ResidentFlags)); } - if (offs > length || dataSize > length || length - dataSize < offs) + if (offs > len || dataSize > len || len - dataSize < offs) return 0; - Data.SetCapacity(dataSize); - memcpy(Data, p + offs, dataSize); + Data.CopyFrom(p + offs, dataSize); #ifdef SHOW_DEBUG_INFO PRF(printf(" : ")); - for (unsigned i = 0; i < Data.GetCapacity(); i++) + for (unsigned i = 0; i < Data.Size(); i++) { - PRF(printf(" %02X", (int)Data[i])); + PRF(printf(" %02X", (unsigned)Data[i])); } #endif - return length; + return len; } -bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, int compressionUnit) const +bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, unsigned compressionUnit) const { const Byte *p = Data; - unsigned size = (unsigned)Data.GetCapacity(); + unsigned size = (unsigned)Data.Size(); UInt64 vcn = LowVcn; UInt64 lcn = 0; UInt64 highVcn1 = HighVcn + 1; @@ -504,8 +531,8 @@ bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, static const UInt64 kEmptyTag = (UInt64)(Int64)-1; -static const int kNumCacheChunksLog = 1; -static const UInt32 kNumCacheChunks = (1 << kNumCacheChunksLog); +static const unsigned kNumCacheChunksLog = 1; +static const size_t kNumCacheChunks = (1 << kNumCacheChunksLog); class CInStream: public IInStream, @@ -518,32 +545,32 @@ class CInStream: size_t _compressedPos; UInt64 _tags[kNumCacheChunks]; - int _chunkSizeLog; + unsigned _chunkSizeLog; CByteBuffer _inBuf; CByteBuffer _outBuf; public: CMyComPtr<IInStream> Stream; UInt64 Size; UInt64 InitializedSize; - int BlockSizeLog; - int CompressionUnit; + unsigned BlockSizeLog; + unsigned CompressionUnit; bool InUse; CRecordVector<CExtent> Extents; HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); } UInt32 GetCuSize() const { return (UInt32)1 << (BlockSizeLog + CompressionUnit); } - HRESULT InitAndSeek(int compressionUnit) + HRESULT InitAndSeek(unsigned compressionUnit) { CompressionUnit = compressionUnit; if (compressionUnit != 0) { UInt32 cuSize = GetCuSize(); - _inBuf.SetCapacity(cuSize); + _inBuf.Alloc(cuSize); _chunkSizeLog = BlockSizeLog + CompressionUnit; - _outBuf.SetCapacity(kNumCacheChunks << _chunkSizeLog); + _outBuf.Alloc(kNumCacheChunks << _chunkSizeLog); } - for (int i = 0; i < kNumCacheChunks; i++) + for (size_t i = 0; i < kNumCacheChunks; i++) _tags[i] = kEmptyTag; _sparseMode = false; @@ -683,10 +710,10 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) UInt64 virtBlock = _virtPos >> BlockSizeLog; UInt64 virtBlock2 = virtBlock & ~((UInt64)comprUnitSize - 1); - int left = 0, right = Extents.Size(); + unsigned left = 0, right = Extents.Size(); for (;;) { - int mid = (left + right) / 2; + unsigned mid = (left + right) / 2; if (mid == left) break; if (virtBlock2 < Extents[mid].Virt) @@ -698,7 +725,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) bool isCompressed = false; UInt64 virtBlock2End = virtBlock2 + comprUnitSize; if (CompressionUnit != 0) - for (int i = left; i < Extents.Size(); i++) + for (unsigned i = left; i < Extents.Size(); i++) { const CExtent &e = Extents[i]; if (e.Virt >= virtBlock2End) @@ -710,7 +737,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) } } - int i; + unsigned i; for (i = left; Extents[i + 1].Virt <= virtBlock; i++); _sparseMode = false; @@ -733,7 +760,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) break; } bool thereArePhy = false; - for (int i2 = left; i2 < Extents.Size(); i2++) + for (unsigned i2 = left; i2 < Extents.Size(); i2++) { const CExtent &e = Extents[i2]; if (e.Virt >= virtBlock2End) @@ -812,19 +839,22 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) STDMETHODIMP CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { - UInt64 newVirtPos = offset; - switch(seekOrigin) + switch (seekOrigin) { case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: newVirtPos += _virtPos; break; - case STREAM_SEEK_END: newVirtPos += Size; break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += Size; break; default: return STG_E_INVALIDFUNCTION; } - if (_virtPos != newVirtPos) + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + if (_virtPos != (UInt64)offset) + { _curRem = 0; - _virtPos = newVirtPos; + _virtPos = offset; + } if (newPosition) - *newPosition = newVirtPos; + *newPosition = offset; return S_OK; } @@ -847,9 +877,9 @@ STDMETHODIMP CByteBufStream::Read(void *data, UInt32 size, UInt32 *processedSize { if (processedSize != NULL) *processedSize = 0; - if (_virtPos >= Buf.GetCapacity()) - return (_virtPos == Buf.GetCapacity()) ? S_OK: E_FAIL; - UInt64 rem = Buf.GetCapacity() - _virtPos; + if (_virtPos >= Buf.Size()) + return (_virtPos == Buf.Size()) ? S_OK: E_FAIL; + UInt64 rem = Buf.Size() - _virtPos; if (rem < size) size = (UInt32)rem; memcpy(data, Buf + (size_t)_virtPos, size); @@ -861,20 +891,23 @@ STDMETHODIMP CByteBufStream::Read(void *data, UInt32 size, UInt32 *processedSize STDMETHODIMP CByteBufStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { - switch(seekOrigin) + switch (seekOrigin) { - case STREAM_SEEK_SET: _virtPos = offset; break; - case STREAM_SEEK_CUR: _virtPos += offset; break; - case STREAM_SEEK_END: _virtPos = Buf.GetCapacity() + offset; break; + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += Buf.Size(); break; default: return STG_E_INVALIDFUNCTION; } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = offset; if (newPosition) - *newPosition = _virtPos; + *newPosition = offset; return S_OK; } -static HRESULT DataParseExtents(int clusterSizeLog, const CObjectVector<CAttr> &attrs, - int attrIndex, int attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &Extents) +static HRESULT DataParseExtents(unsigned clusterSizeLog, const CObjectVector<CAttr> &attrs, + unsigned attrIndex, unsigned attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &Extents) { CExtent e; e.Virt = 0; @@ -887,12 +920,12 @@ static HRESULT DataParseExtents(int clusterSizeLog, const CObjectVector<CAttr> & (attr0.AllocatedSize & ((1 << clusterSizeLog) - 1)) != 0) return S_FALSE; - for (int i = attrIndex; i < attrIndexLim; i++) + for (unsigned i = attrIndex; i < attrIndexLim; i++) if (!attrs[i].ParseExtents(Extents, numPhysClusters, attr0.CompressionUnit)) return S_FALSE; UInt64 packSizeCalc = 0; - for (int k = 0; k < Extents.Size(); k++) + FOR_VECTOR (k, Extents) { CExtent &e = Extents[k]; if (!e.IsEmpty()) @@ -916,18 +949,18 @@ static HRESULT DataParseExtents(int clusterSizeLog, const CObjectVector<CAttr> & struct CDataRef { - int Start; - int Num; + unsigned Start; + unsigned Num; }; -static const UInt32 kMagic_FILE = 0x454c4946; +static const UInt32 kMagic_FILE = 0x454C4946; static const UInt32 kMagic_BAAD = 0x44414142; struct CMftRec { UInt32 Magic; // UInt64 Lsn; - UInt16 SeqNumber; + UInt16 SeqNumber; // Number of times this mft record has been reused UInt16 Flags; // UInt16 LinkCount; // UInt16 NextAttrInstance; @@ -938,8 +971,18 @@ struct CMftRec CObjectVector<CAttr> DataAttrs; CObjectVector<CFileNameAttr> FileNames; CRecordVector<CDataRef> DataRefs; + // CAttr SecurityAttr; CSiAttr SiAttr; + + CByteBuffer ReparseData; + + bool IsAltStream(int dataIndex) const + { + return dataIndex >= 0 && ( + (IsDir() || + !DataAttrs[DataRefs[dataIndex].Start].Name.IsEmpty())); + } void MoveAttrsFrom(CMftRec &src) { @@ -952,12 +995,12 @@ struct CMftRec UInt64 GetPackSize() const { UInt64 res = 0; - for (int i = 0; i < DataRefs.Size(); i++) + FOR_VECTOR (i, DataRefs) res += DataAttrs[DataRefs[i].Start].GetPackSize(); return res; } - bool Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector<CAttr> *attrs); + bool Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector<CAttr> *attrs); bool IsEmpty() const { return (Magic <= 2); } bool IsFILE() const { return (Magic == kMagic_FILE); } @@ -968,10 +1011,10 @@ struct CMftRec void ParseDataNames(); HRESULT GetStream(IInStream *mainStream, int dataIndex, - int clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const; - int GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const; + unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const; + unsigned GetNumExtents(int dataIndex, unsigned clusterSizeLog, UInt64 numPhysClusters) const; - UInt64 GetSize(int dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); } + UInt64 GetSize(unsigned dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); } CMftRec(): MyNumNameLinks(0) {} }; @@ -981,7 +1024,7 @@ void CMftRec::ParseDataNames() DataRefs.Clear(); DataAttrs.Sort(CompareAttr, 0); - for (int i = 0; i < DataAttrs.Size();) + for (unsigned i = 0; i < DataAttrs.Size();) { CDataRef ref; ref.Start = i; @@ -994,7 +1037,7 @@ void CMftRec::ParseDataNames() } HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex, - int clusterSizeLog, UInt64 numPhysClusters, IInStream **destStream) const + unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **destStream) const { *destStream = 0; CByteBufStream *streamSpec = new CByteBufStream; @@ -1003,11 +1046,11 @@ HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex, if (dataIndex < 0) return E_FAIL; - if (dataIndex < DataRefs.Size()) + if ((unsigned)dataIndex < DataRefs.Size()) { const CDataRef &ref = DataRefs[dataIndex]; - int numNonResident = 0; - int i; + unsigned numNonResident = 0; + unsigned i; for (i = ref.Start; i < ref.Start + ref.Num; i++) if (DataAttrs[i].NonResident) numNonResident++; @@ -1037,14 +1080,14 @@ HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex, return S_OK; } -int CMftRec::GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClusters) const +unsigned CMftRec::GetNumExtents(int dataIndex, unsigned clusterSizeLog, UInt64 numPhysClusters) const { if (dataIndex < 0) return 0; { const CDataRef &ref = DataRefs[dataIndex]; - int numNonResident = 0; - int i; + unsigned numNonResident = 0; + unsigned i; for (i = ref.Start; i < ref.Start + ref.Num; i++) if (DataAttrs[i].NonResident) numNonResident++; @@ -1060,36 +1103,49 @@ int CMftRec::GetNumExtents(int dataIndex, int clusterSizeLog, UInt64 numPhysClus return 0; // error; return extents.Size() - 1; } - // if (attr0.Data.GetCapacity() != 0) + // if (attr0.Data.Size() != 0) // return 1; return 0; } } -bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNumber, +bool CMftRec::Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector<CAttr> *attrs) { G32(p, Magic); if (!IsFILE()) return IsEmpty() || IsBAAD(); - UInt32 usaOffset; - UInt32 numUsaItems; - G16(p + 0x04, usaOffset); - G16(p + 0x06, numUsaItems); - if ((usaOffset & 1) != 0 || usaOffset + numUsaItems * 2 > ((UInt32)1 << sectorSizeLog) - 2 || - numUsaItems == 0 || numUsaItems - 1 != numSectors) - return false; - - UInt16 usn = Get16(p + usaOffset); - // PRF(printf("\nusn = %d", usn)); - for (UInt32 i = 1; i < numUsaItems; i++) { - void *pp = p + (i << sectorSizeLog) - 2; - if (Get16(pp) != usn) + UInt32 usaOffset; + UInt32 numUsaItems; + G16(p + 0x04, usaOffset); + G16(p + 0x06, numUsaItems); + + /* NTFS stores (usn) to 2 last bytes in each sector (before writing record to disk). + Original values of these two bytes are stored in table. + So we restore original data from table */ + + if ((usaOffset & 1) != 0 + || usaOffset + numUsaItems * 2 > ((UInt32)1 << sectorSizeLog) - 2 + || numUsaItems == 0 + || numUsaItems - 1 != numSectors) return false; - SetUi16(pp, Get16(p + usaOffset + i * 2)); + + if (usaOffset >= 0x30) // NTFS 3.1+ + if (Get32(p + 0x2C) != recNumber) + return false; + + UInt16 usn = Get16(p + usaOffset); + // PRF(printf("\nusn = %d", usn)); + for (UInt32 i = 1; i < numUsaItems; i++) + { + void *pp = p + (i << sectorSizeLog) - 2; + if (Get16(pp) != usn) + return false; + SetUi16(pp, Get16(p + usaOffset + i * 2)); + } } // G64(p + 0x08, Lsn); @@ -1109,28 +1165,36 @@ bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNum // return false; // Check it; } // G16(p + 0x28, NextAttrInstance); - if (usaOffset >= 0x30) - if (Get32(p + 0x2C) != recNumber) // NTFS 3.1+ - return false; UInt32 limit = numSectors << sectorSizeLog; - if (attrOffs >= limit || (attrOffs & 7) != 0 || bytesInUse > limit + if (attrOffs >= limit + || (attrOffs & 7) != 0 + || (bytesInUse & 7) != 0 + || bytesInUse > limit || bytesAlloc != limit) return false; + limit = bytesInUse; - for (UInt32 t = attrOffs; t < limit;) + for (UInt32 t = attrOffs;;) { + if (t >= limit) + return false; + CAttr attr; // PRF(printf("\n %2d:", Attrs.Size())); PRF(printf("\n")); - UInt32 length = attr.Parse(p + t, limit - t); - if (length == 0 || limit - t < length) + UInt32 len = attr.Parse(p + t, limit - t); + if (len == 0 || limit - t < len) return false; - t += length; + t += len; if (attr.Type == 0xFFFFFFFF) + { + if (t != limit) + return false; break; - switch(attr.Type) + } + switch (attr.Type) { case ATTR_TYPE_FILE_NAME: { @@ -1138,8 +1202,8 @@ bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNum if (!attr.ParseFileName(fna)) return false; FileNames.Add(fna); - PRF(printf(" flags = %4x", (int)fna.NameType)); - PRF(printf("\n %S", fna.Name)); + PRF(printf(" flags = %4x\n ", (int)fna.NameType)); + PRF_UTF16(fna.Name); break; } case ATTR_TYPE_STANDARD_INFO: @@ -1149,6 +1213,14 @@ bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNum case ATTR_TYPE_DATA: DataAttrs.Add(attr); break; + case ATTR_TYPE_REPARSE_POINT: + ReparseData = attr.Data; + break; + /* + case ATTR_TYPE_SECURITY_DESCRIPTOR: + SecurityAttr = attr; + break; + */ default: if (attrs) attrs->Add(attr); @@ -1161,49 +1233,99 @@ bool CMftRec::Parse(Byte *p, int sectorSizeLog, UInt32 numSectors, UInt32 recNum struct CItem { - int RecIndex; - int DataIndex; - CMftRef ParentRef; - UString Name; - UInt32 Attrib; - - bool IsDir() const { return (DataIndex < 0); } + unsigned RecIndex; // index in Recs array + unsigned NameIndex; // index in CMftRec::FileNames + + int DataIndex; /* index in CMftRec::DataRefs + -1: for folders + -1: for files that have no DATA_ATRIBUTE */ + + int ParentFolder; /* index in Items array + -1: for root items + -2: [LOST] folder + -3: [UNKNOWN] folder (deleted lost) */ + int ParentHost; /* index in Items array, if it's AltStream + -1: if it's not AltStream + -1: if there is no Host item */ + + CItem(): DataIndex(-1), ParentFolder(-1), ParentHost(-1) {} + + bool IsDir() const { return DataIndex < 0; } + // check it !!! + // probably NTFS for empty file still creates empty DATA_ATTRIBUTE + // But it doesn't do it for $Secure:$SDS }; struct CDatabase { - CHeader Header; - CObjectVector<CItem> Items; + CRecordVector<CItem> Items; CObjectVector<CMftRec> Recs; CMyComPtr<IInStream> InStream; + CHeader Header; + unsigned RecSizeLog; + UInt64 PhySize; + IArchiveOpenCallback *OpenCallback; CByteBuffer ByteBuf; CObjectVector<CAttr> VolAttrs; + CByteBuffer SecurData; + CRecordVector<size_t> SecurOffsets; + + bool _showSystemFiles; + bool _showDeletedFiles; + UStringVector VirtFolderNames; + int _systemFolderIndex; + int _lostFolderIndex_Normal; + int _lostFolderIndex_Deleted; + + // bool _headerWarning; + + bool ThereAreAltStreams; + + void InitProps() + { + _showSystemFiles = true; + // we show SystemFiles by default since it's difficult to track $Extend\* system files + // it must be fixed later + _showDeletedFiles = false; + } + + CDatabase() { InitProps(); } ~CDatabase() { ClearAndClose(); } void Clear(); void ClearAndClose(); - UString GetItemPath(Int32 index) const; + void GetItemPath(unsigned index, NCOM::CPropVariant &path) const; HRESULT Open(); - HRESULT ReadDir(Int32 parent, UInt32 cluster, int level); HRESULT SeekToCluster(UInt64 cluster); - int FindMtfRec(const CMftRef &ref) const + int FindDirItemForMtfRec(UInt64 recIndex) const { - UInt64 val = ref.GetIndex(); - int left = 0, right = Items.Size(); + if (recIndex >= Recs.Size()) + return -1; + const CMftRec &rec = Recs[(unsigned)recIndex]; + if (!rec.IsDir()) + return -1; + unsigned left = 0, right = Items.Size(); while (left != right) { - int mid = (left + right) / 2; - UInt64 midValue = Items[mid].RecIndex; - if (val == midValue) - return mid; - if (val < midValue) + unsigned mid = (left + right) / 2; + const CItem &item = Items[mid]; + UInt64 midValue = item.RecIndex; + if (recIndex == midValue) + { + // if (!item.IsAltStream) + // if (!rec.IsAltStream(item.DataIndex)) + if (item.DataIndex < 0) + return mid; + right = mid; + } + else if (recIndex < midValue) right = mid; else left = mid + 1; @@ -1211,6 +1333,19 @@ struct CDatabase return -1; } + bool FindSecurityDescritor(UInt32 id, UInt64 &offset, UInt32 &size) const; + + HRESULT ParseSecuritySDS_2(); + void ParseSecuritySDS() + { + HRESULT res = ParseSecuritySDS_2(); + if (res != S_OK) + { + SecurOffsets.Clear(); + SecurData.Free(); + } + } + }; HRESULT CDatabase::SeekToCluster(UInt64 cluster) @@ -1222,6 +1357,15 @@ void CDatabase::Clear() { Items.Clear(); Recs.Clear(); + SecurOffsets.Clear(); + SecurData.Free(); + VirtFolderNames.Clear(); + _systemFolderIndex = -1; + _lostFolderIndex_Normal = -1; + _lostFolderIndex_Deleted = -1; + ThereAreAltStreams = false; + // _headerWarning = false; + PhySize = 0; } void CDatabase::ClearAndClose() @@ -1232,55 +1376,273 @@ void CDatabase::ClearAndClose() #define MY_DIR_PREFIX(x) L"[" x L"]" WSTRING_PATH_SEPARATOR -UString CDatabase::GetItemPath(Int32 index) const +void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const { const CItem *item = &Items[index]; - UString name = item->Name; - for (int j = 0; j < 256; j++) - { - CMftRef ref = item->ParentRef; - index = FindMtfRec(ref); - if (ref.GetIndex() == 5) - return name; - if (index < 0 || Recs[Items[index].RecIndex].SeqNumber != ref.GetNumber()) - return MY_DIR_PREFIX(L"UNKNOWN") + name; - item = &Items[index]; - name = item->Name + WCHAR_PATH_SEPARATOR + name; - } - return MY_DIR_PREFIX(L"BAD") + name; + unsigned size = 0; + const CMftRec &rec = Recs[item->RecIndex]; + size += rec.FileNames[item->NameIndex].Name.Len(); + + bool isAltStream = rec.IsAltStream(item->DataIndex); + if (isAltStream) + { + const CAttr &data = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start]; + size += data.Name.Len(); + size++; + } + + /* + if (item->ParentHost >= 0) + { + item = &Items[item->ParentHost]; + size += item->Name.Len() + 1; + } + */ + + for (unsigned i = 0;; i++) + { + if (i > 256) + { + path = "[TOO-LONG]"; + return; + } + const wchar_t *servName; + if (item->RecIndex < kNumSysRecs) + servName = kVirtualFolder_System; + else + { + int index2 = item->ParentFolder; + if (index2 >= 0) + { + item = &Items[index2]; + size += Recs[item->RecIndex].FileNames[item->NameIndex].Name.Len() + 1; + continue; + } + if (index2 == -1) + break; + servName = (index2 == -2) ? + kVirtualFolder_Lost_Normal : + kVirtualFolder_Lost_Deleted; + } + size += MyStringLen(servName) + 1; + break; + } + + wchar_t *s = path.AllocBstr(size); + + item = &Items[index]; + + bool needColon = false; + if (isAltStream) + { + const UString &name = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start].Name; + size -= name.Len(); + MyStringCopy(s + size, (const wchar_t *)name); + s[--size] = ':'; + needColon = true; + } + + { + const UString &name = rec.FileNames[item->NameIndex].Name; + unsigned len = name.Len(); + MyStringCopy(s + size - len, (const wchar_t *)name); + if (needColon) + s[size] = ':'; + size -= len; + } + + /* + { + unsigned len = item->Name.Len(); + size -= len; + MyStringCopy(s + size, (const wchar_t *)item->Name); + } + */ + + + /* + if (item->ParentHost >= 0) + { + item = &Items[item->ParentHost]; + unsigned len = item->Name.Len(); + size--; + size -= len; + MyStringCopy(s + size, (const wchar_t *)item->Name); + s[size + len] = ':'; + } + */ + + for (;;) + { + const wchar_t *servName; + if (item->RecIndex < kNumSysRecs) + servName = kVirtualFolder_System; + else + { + int index2 = item->ParentFolder; + if (index2 >= 0) + { + item = &Items[index2]; + const UString &name = Recs[item->RecIndex].FileNames[item->NameIndex].Name; + unsigned len = name.Len(); + size--; + size -= len; + MyStringCopy(s + size, (const wchar_t *)name); + s[size + len] = WCHAR_PATH_SEPARATOR; + continue; + } + if (index2 == -1) + break; + servName = (index2 == -2) ? + kVirtualFolder_Lost_Normal : + kVirtualFolder_Lost_Deleted; + } + MyStringCopy(s, servName); + s[MyStringLen(servName)] = WCHAR_PATH_SEPARATOR; + break; + } +} + +bool CDatabase::FindSecurityDescritor(UInt32 item, UInt64 &offset, UInt32 &size) const +{ + offset = 0; + size = 0; + unsigned left = 0, right = SecurOffsets.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + size_t offs = SecurOffsets[mid]; + UInt32 midValue = Get32(((const Byte *)SecurData) + offs + 4); + if (item == midValue) + { + offset = Get64((const Byte *)SecurData + offs + 8) + 20; + size = Get32((const Byte *)SecurData + offs + 16) - 20; + return true; + } + if (item < midValue) + right = mid; + else + left = mid + 1; + } + return false; +} + +/* +static int CompareIDs(const size_t *p1, const size_t *p2, void *data) +{ + UInt32 id1 = Get32(((const Byte *)data) + *p1 + 4); + UInt32 id2 = Get32(((const Byte *)data) + *p2 + 4); + return MyCompare(id1, id2); +} +*/ + +// security data contains duplication copy after each 256 KB. +static const unsigned kSecureDuplicateStepBits = 18; + +HRESULT CDatabase::ParseSecuritySDS_2() +{ + const Byte *p = SecurData; + size_t size = SecurData.Size(); + const size_t kDuplicateStep = (size_t)1 << kSecureDuplicateStepBits; + const size_t kDuplicateMask = kDuplicateStep - 1; + size_t lim = MyMin(size, kDuplicateStep); + UInt32 idPrev = 0; + for (size_t pos = 0; pos < size && size - pos >= 20;) + { + UInt32 id = Get32(p + pos + 4); + UInt64 offs = Get64(p + pos + 8); + UInt32 entrySize = Get32(p + pos + 16); + if (offs == pos && entrySize >= 20 && lim - pos >= entrySize) + { + if (id <= idPrev) + return S_FALSE; + idPrev = id; + SecurOffsets.Add(pos); + pos += entrySize; + pos = (pos + 0xF) & ~(size_t)0xF; + if ((pos & kDuplicateMask) != 0) + continue; + } + else + pos = (pos + kDuplicateStep) & ~kDuplicateMask; + pos += kDuplicateStep; + lim = pos + kDuplicateStep; + if (lim >= size) + lim = size; + } + // we checked that IDs are sorted, so we don't need Sort + // SecurOffsets.Sort(CompareIDs, (void *)p); + return S_OK; } HRESULT CDatabase::Open() { Clear(); + + /* NTFS layout: + 1) main part (as specified by NumClusters). Only that part is available, if we open "\\.\c:" + 2) additional empty sectors (as specified by NumSectors) + 3) the copy of first sector (boot sector) + + We support both cases: + - the file with only main part + - full file (as raw data on partition), including the copy + of first sector (boot sector) at the end of data + + We don't support the case, when only the copy of boot sector + at the end was detected as NTFS signature. + */ - static const UInt32 kHeaderSize = 512; - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)); - if (!Header.Parse(buf)) - return S_FALSE; - UInt64 fileSize; - RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize)); - if (fileSize < Header.GetPhySize()) - return S_FALSE; - + { + static const UInt32 kHeaderSize = 512; + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)); + if (!Header.Parse(buf)) + return S_FALSE; + + UInt64 fileSize; + RINOK(InStream->Seek(0, STREAM_SEEK_END, &fileSize)); + PhySize = Header.GetPhySize_Clusters(); + if (fileSize < PhySize) + return S_FALSE; + + UInt64 phySizeMax = Header.GetPhySize_Max(); + if (fileSize >= phySizeMax) + { + RINOK(InStream->Seek(Header.NumSectors << Header.SectorSizeLog, STREAM_SEEK_SET, NULL)); + Byte buf2[kHeaderSize]; + if (ReadStream_FALSE(InStream, buf2, kHeaderSize) == S_OK) + { + if (memcmp(buf, buf2, kHeaderSize) == 0) + PhySize = phySizeMax; + // else _headerWarning = true; + } + } + } + SeekToCluster(Header.MftCluster); CMftRec mftRec; UInt32 numSectorsInRec; - int recSizeLog; + CMyComPtr<IInStream> mftStream; { UInt32 blockSize = 1 << 12; - ByteBuf.SetCapacity(blockSize); + ByteBuf.Alloc(blockSize); RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize)); - UInt32 allocSize = Get32(ByteBuf + 0x1C); - recSizeLog = GetLog(allocSize); - if (recSizeLog < Header.SectorSizeLog) - return false; - numSectorsInRec = 1 << (recSizeLog - Header.SectorSizeLog); - if (!mftRec.Parse(ByteBuf, Header.SectorSizeLog, numSectorsInRec, NULL, 0)) + { + UInt32 allocSize = Get32(ByteBuf + 0x1C); + int t = GetLog(allocSize); + if (t < (int)Header.SectorSizeLog) + return S_FALSE; + RecSizeLog = t; + if (RecSizeLog > 15) + return S_FALSE; + } + + numSectorsInRec = 1 << (RecSizeLog - Header.SectorSizeLog); + if (!mftRec.Parse(ByteBuf, Header.SectorSizeLog, numSectorsInRec, 0, NULL)) return S_FALSE; if (!mftRec.IsFILE()) return S_FALSE; @@ -1292,23 +1654,28 @@ HRESULT CDatabase::Open() return S_FALSE; } + // CObjectVector<CAttr> SecurityAttrs; + UInt64 mftSize = mftRec.DataAttrs[0].Size; - if ((mftSize >> 4) > Header.GetPhySize()) + if ((mftSize >> 4) > Header.GetPhySize_Clusters()) return S_FALSE; - UInt64 numFiles = mftSize >> recSizeLog; + UInt64 numFiles = mftSize >> RecSizeLog; if (numFiles > (1 << 30)) return S_FALSE; if (OpenCallback) { RINOK(OpenCallback->SetTotal(&numFiles, &mftSize)); } - const UInt32 kBufSize = (1 << 15); - if (kBufSize < (1 << recSizeLog)) + + const size_t kBufSize = (1 << 15); + const size_t recSize = ((size_t)1 << RecSizeLog); + if (kBufSize < recSize) return S_FALSE; - ByteBuf.SetCapacity((size_t)kBufSize); - Recs.Reserve((int)numFiles); + ByteBuf.Alloc(kBufSize); + Recs.ClearAndReserve((unsigned)numFiles); + for (UInt64 pos64 = 0;;) { if (OpenCallback) @@ -1319,28 +1686,85 @@ HRESULT CDatabase::Open() RINOK(OpenCallback->SetCompleted(&numFiles, &pos64)); } } - UInt32 readSize = kBufSize; + size_t readSize = kBufSize; UInt64 rem = mftSize - pos64; if (readSize > rem) - readSize = (UInt32)rem; - if (readSize < ((UInt32)1 << recSizeLog)) + readSize = (size_t)rem; + if (readSize < recSize) break; - RINOK(ReadStream_FALSE(mftStream, ByteBuf, (size_t)readSize)); + RINOK(ReadStream_FALSE(mftStream, ByteBuf, readSize)); pos64 += readSize; - for (int i = 0; ((UInt32)(i + 1) << recSizeLog) <= readSize; i++) + + for (size_t i = 0; readSize >= recSize; i += recSize, readSize -= recSize) { PRF(printf("\n---------------------")); PRF(printf("\n%5d:", Recs.Size())); - Byte *p = ByteBuf + ((UInt32)i << recSizeLog); + + Byte *p = ByteBuf + i; CMftRec rec; - if (!rec.Parse(p, Header.SectorSizeLog, numSectorsInRec, (UInt32)Recs.Size(), - (Recs.Size() == kRecIndex_Volume) ? &VolAttrs: NULL)) + + CObjectVector<CAttr> *attrs = NULL; + unsigned recIndex = Recs.Size(); + switch (recIndex) + { + case kRecIndex_Volume: attrs = &VolAttrs; break; + // case kRecIndex_Security: attrs = &SecurityAttrs; break; + } + + if (!rec.Parse(p, Header.SectorSizeLog, numSectorsInRec, (UInt32)Recs.Size(), attrs)) return S_FALSE; Recs.Add(rec); } } - int i; + /* + // that code looks too complex. And we can get security info without index parsing + for (i = 0; i < SecurityAttrs.Size(); i++) + { + const CAttr &attr = SecurityAttrs[i]; + if (attr.Name == L"$SII") + { + if (attr.Type == ATTR_TYPE_INDEX_ROOT) + { + const Byte *data = attr.Data; + size_t size = attr.Data.Size(); + + // Index Root + UInt32 attrType = Get32(data); + UInt32 collationRule = Get32(data + 4); + UInt32 indexAllocationEtrySizeSize = Get32(data + 8); + UInt32 clustersPerIndexRecord = Get32(data + 0xC); + data += 0x10; + + // Index Header + UInt32 firstEntryOffset = Get32(data); + UInt32 totalSize = Get32(data + 4); + UInt32 allocSize = Get32(data + 8); + UInt32 flags = Get32(data + 0xC); + + int num = 0; + for (int j = 0 ; j < num; j++) + { + if (Get32(data) != 0x1414 || // offset and size + Get32(data + 4) != 0 || + Get32(data + 8) != 0x428) // KeySize / EntrySize + break; + UInt32 flags = Get32(data + 12); + UInt32 id = Get32(data + 0x10); + if (id = Get32(data + 0x18)) + break; + UInt32 descriptorOffset = Get64(data + 0x1C); + UInt32 descriptorSize = Get64(data + 0x24); + data += 0x28; + } + // break; + } + } + } + */ + + unsigned i; + for (i = 0; i < Recs.Size(); i++) { CMftRec &rec = Recs[i]; @@ -1349,7 +1773,7 @@ HRESULT CDatabase::Open() UInt64 refIndex = rec.BaseMftRef.GetIndex(); if (refIndex > (UInt32)Recs.Size()) return S_FALSE; - CMftRec &refRec = Recs[(int)refIndex]; + CMftRec &refRec = Recs[(unsigned)refIndex]; bool moveAttrs = (refRec.SeqNumber == rec.BaseMftRef.GetNumber() && refRec.BaseMftRef.IsBaseItself()); if (rec.InUse() && refRec.InUse()) { @@ -1371,81 +1795,357 @@ HRESULT CDatabase::Open() CMftRec &rec = Recs[i]; if (!rec.IsFILE() || !rec.BaseMftRef.IsBaseItself()) continue; - int numNames = 0; + if (i < kNumSysRecs && !_showSystemFiles) + continue; + if (!rec.InUse() && !_showDeletedFiles) + continue; + + unsigned numNames = 0; // printf("\n%4d: ", i); - for (int t = 0; t < rec.FileNames.Size(); t++) + FOR_VECTOR (t, rec.FileNames) { const CFileNameAttr &fna = rec.FileNames[t]; - // printf("%4d %S | ", (int)fna.NameType, fna.Name); + // PRF(printf("%4d ", (int)fna.NameType)); + // PRF_UTF16(fna.Name) + // PRF(printf(" | ")); if (fna.IsDos()) continue; - int numDatas = rec.DataRefs.Size(); + unsigned numDatas = rec.DataRefs.Size(); - // For hard linked files we show substreams only for first Name. + /* + // we can use that code to reduce the number of alt streams + // For hard linked files we show alt streams only for first Name. if (numDatas > 1 && numNames > 0) numDatas = 1; + */ + numNames++; + // here we suppose that first stream is main stream (unnamed stream). + // IS IT SO ???? + int hostIndex = -1; if (rec.IsDir()) { CItem item; - item.Name = fna.Name; + item.NameIndex = t; item.RecIndex = i; - item.DataIndex = -1; - item.ParentRef = fna.ParentDirRef; - item.Attrib = rec.SiAttr.Attrib | 0x10; + // item.ParentRef = fna.ParentDirRef; + // item.Attrib = rec.SiAttr.Attrib | 0x10; // item.Attrib = fna.Attrib; - Items.Add(item); + hostIndex = Items.Add(item); + } + else + { + + // probably NTFS for empty file still creates empty DATA_ATTRIBUTE + // But it doesn't do it for $Secure:$SDS + if (rec.DataRefs.IsEmpty() || + !rec.DataAttrs[rec.DataRefs[0].Start].Name.IsEmpty()) + { + CItem item; + item.NameIndex = t; + item.RecIndex = i; + // item.ParentRef = fna.ParentDirRef; + // item.Attrib = rec.SiAttr.Attrib; + hostIndex = Items.Add(item); + } + } + + { + bool isThereUnNamedStream = false; + for (unsigned di = 0; di < numDatas; di++) + { + const UString &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name; + if (subName.IsEmpty()) + isThereUnNamedStream = true; + } + if (!rec.IsDir() && !isThereUnNamedStream) + { + // return S_FALSE; + } } - for (int di = 0; di < numDatas; di++) + + for (unsigned di = 0; di < numDatas; di++) { CItem item; - item.Name = fna.Name; - item.Attrib = rec.SiAttr.Attrib; + item.NameIndex = t; + // item.FileNameAttr = fna; + // item.Name = fna.Name; + // item.Attrib = rec.SiAttr.Attrib; const UString &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name; - if (!subName.IsEmpty()) + if (subName.IsEmpty()) + { + if (hostIndex >= 0) + continue; + hostIndex = Items.Size(); + } + else { // $BadClus:$Bad is sparse file for all clusters. So we skip it. if (i == kRecIndex_BadClus && subName == L"$Bad") continue; - item.Name += L":"; - item.Name += subName; - item.Attrib = fna.Attrib; + if (hostIndex >= 0) + { + // item.Name = subName; + } + else + { + // there is no host file for some streams + // return E_FAIL; + // item.Name += L":"; + // item.Name += subName; + } + // item.Attrib = fna.Attrib; + item.ParentHost = hostIndex; + // item.IsAltStream = true; + ThereAreAltStreams = true; } PRF(printf("\n%3d", i)); - PRF(printf(" attrib=%2x", rec.SiAttr.Attrib)); - PRF(printf(" %S", item.Name)); + PRF(printf(" attrib=%2x ", rec.SiAttr.Attrib)); + // PRF_UTF16(item.Name); item.RecIndex = i; item.DataIndex = di; - item.ParentRef = fna.ParentDirRef; + // item.ParentRef = fna.ParentDirRef; Items.Add(item); rec.MyNumNameLinks++; } } - rec.FileNames.ClearAndFree(); + // rec.FileNames.ClearAndFree(); + } + + if (Recs.Size() > kRecIndex_Security) + { + const CMftRec &rec = Recs[kRecIndex_Security]; + FOR_VECTOR (di, rec.DataRefs) + { + const CAttr &attr = rec.DataAttrs[rec.DataRefs[di].Start]; + if (attr.Name == L"$SDS") + { + CMyComPtr<IInStream> sdsStream; + RINOK(rec.GetStream(InStream, di, Header.ClusterSizeLog, Header.NumClusters, &sdsStream)); + if (sdsStream) + { + UInt64 size64 = attr.GetSize(); + if (size64 < (UInt32)1 << 29) + { + size_t size = (size_t)size64; + if ((((size + 1) >> kSecureDuplicateStepBits) & 1) != 0) + { + size -= (1 << kSecureDuplicateStepBits); + SecurData.Alloc(size); + if (ReadStream_FALSE(sdsStream, SecurData, size) == S_OK) + { + ParseSecuritySDS(); + break; + } + } + } + } + break; + } + } + } + + bool thereAreUnknownFolders_Normal = false; + bool thereAreUnknownFolders_Deleted = false; + + for (i = 0; i < Items.Size(); i++) + { + CItem &item = Items[i]; + const CMftRec &rec = Recs[item.RecIndex]; + const CFileNameAttr &fn = rec.FileNames[item.NameIndex]; + const CMftRef &parentDirRef = fn.ParentDirRef; + UInt64 refIndex = parentDirRef.GetIndex(); + if (refIndex == 5) + item.ParentFolder = -1; + else + { + int index = FindDirItemForMtfRec(refIndex); + if (index < 0 || + Recs[Items[index].RecIndex].SeqNumber != parentDirRef.GetNumber()) + { + if (Recs[item.RecIndex].InUse()) + { + thereAreUnknownFolders_Normal = true; + index = -2; + } + else + { + thereAreUnknownFolders_Deleted = true; + index = -3; + } + } + item.ParentFolder = index; + } } + unsigned virtIndex = Items.Size(); + if (_showSystemFiles) + { + _systemFolderIndex = virtIndex++; + VirtFolderNames.Add(kVirtualFolder_System); + } + if (thereAreUnknownFolders_Normal) + { + _lostFolderIndex_Normal = virtIndex++; + VirtFolderNames.Add(kVirtualFolder_Lost_Normal); + } + if (thereAreUnknownFolders_Deleted) + { + _lostFolderIndex_Deleted = virtIndex++; + VirtFolderNames.Add(kVirtualFolder_Lost_Deleted); + } + return S_OK; } class CHandler: public IInArchive, + public IArchiveGetRawProps, public IInArchiveGetStream, + public ISetProperties, public CMyUnknownImp, CDatabase { public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + MY_UNKNOWN_IMP4( + IInArchive, + IArchiveGetRawProps, + IInArchiveGetStream, + ISetProperties) INTERFACE_IInArchive(;) + INTERFACE_IArchiveGetRawProps(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); }; +STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) +{ + *numProps = 2; + return S_OK; +} + +STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) +{ + *name = NULL; + *propID = index == 0 ? kpidNtReparse : kpidNtSecure; + return S_OK; +} + +STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType) +{ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; + + if (index >= Items.Size()) + return S_OK; + const CItem &item = Items[index]; + + if (item.ParentHost >= 0) + { + *parentType = NParentType::kAltStream; + *parent = (UInt32)(Int32)item.ParentHost; + return S_OK; + } + if (item.RecIndex < kNumSysRecs) + { + if (_showSystemFiles) + *parent = _systemFolderIndex; + } + else if (item.ParentFolder >= 0) + *parent = item.ParentFolder; + else if (item.ParentFolder == -2) + *parent = _lostFolderIndex_Normal; + else if (item.ParentFolder == -3) + *parent = _lostFolderIndex_Deleted; + return S_OK; +} + +STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + + if (propID == kpidName) + { + #ifdef MY_CPU_LE + const UString *s; + if (index >= Items.Size()) + s = &VirtFolderNames[index - Items.Size()]; + else + { + const CItem &item = Items[index]; + const CMftRec &rec = Recs[item.RecIndex]; + + // fix it for no HOST case !! + // if (item.IsAltStream && item.DataIndex >= 0) + if (rec.IsAltStream(item.DataIndex)) + { + if (item.ParentHost < 0) + return S_OK; + const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start]; + s = &data.Name; + } + else + { + s = &rec.FileNames[item.NameIndex].Name; + } + // s = &item.Name; + } + *data = (const wchar_t *)*s; + *dataSize = (s->Len() + 1) * sizeof(wchar_t); + *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE; + #endif + return S_OK; + } + + if (propID == kpidNtReparse) + { + if (index >= Items.Size()) + return S_OK; + const CItem &item = Items[index]; + const CMftRec &rec = Recs[item.RecIndex]; + const CByteBuffer &reparse = rec.ReparseData; + + if (reparse.Size() != 0) + { + *dataSize = (UInt32)reparse.Size(); + *propType = NPropDataType::kRaw; + *data = (const Byte *)reparse; + } + } + + if (propID == kpidNtSecure) + { + if (index >= Items.Size()) + return S_OK; + const CItem &item = Items[index]; + const CMftRec &rec = Recs[item.RecIndex]; + if (rec.SiAttr.SecurityId >= 0) + { + UInt64 offset; + UInt32 size; + if (FindSecurityDescritor(rec.SiAttr.SecurityId, offset, size)) + { + *dataSize = size; + *propType = NPropDataType::kRaw; + *data = (const Byte *)SecurData + offset; + } + } + } + return S_OK; +} + STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) { COM_TRY_BEGIN + *stream = 0; + if (index >= Items.Size()) + return S_OK; IInStream *stream2; const CItem &item = Items[index]; const CMftRec &rec = Recs[item.RecIndex]; @@ -1455,18 +2155,66 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } +/* +enum +{ + kpidLink2 = kpidUserDefined, + kpidLinkType, + kpidRecMTime, + kpidRecMTime2, + kpidMTime2, + kpidCTime2, + kpidATime2 +}; + static const STATPROPSTG kProps[] = { { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, { NULL, kpidSize, VT_UI8}, { NULL, kpidPackSize, VT_UI8}, + + // { NULL, kpidLink, VT_BSTR}, + + // { L"Link 2", kpidLink2, VT_BSTR}, + // { L"Link Type", kpidLinkType, VT_UI2}, + { NULL, kpidINode, VT_UI8}, + { NULL, kpidMTime, VT_FILETIME}, { NULL, kpidCTime, VT_FILETIME}, { NULL, kpidATime, VT_FILETIME}, + + // { L"Record Modified", kpidRecMTime, VT_FILETIME}, + + // { L"Modified 2", kpidMTime2, VT_FILETIME}, + // { L"Created 2", kpidCTime2, VT_FILETIME}, + // { L"Accessed 2", kpidATime2, VT_FILETIME}, + // { L"Record Modified 2", kpidRecMTime2, VT_FILETIME}, + { NULL, kpidAttrib, VT_UI4}, - { NULL, kpidLinks, VT_UI4}, - { NULL, kpidNumBlocks, VT_UI4} + { NULL, kpidNumBlocks, VT_UI4}, + { NULL, kpidIsDeleted, VT_BOOL}, +}; +*/ + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidAttrib, + kpidLinks, + kpidINode, + kpidNumBlocks, + kpidIsDeleted +}; + +enum +{ + kpidRecordSize = kpidUserDefined }; static const STATPROPSTG kArcProps[] = @@ -1474,21 +2222,34 @@ static const STATPROPSTG kArcProps[] = { NULL, kpidVolumeName, VT_BSTR}, { NULL, kpidFileSystem, VT_BSTR}, { NULL, kpidClusterSize, VT_UI4}, - { NULL, kpidPhySize, VT_UI8}, + { NULL, kpidSectorSize, VT_UI4}, + { L"Record Size", kpidRecordSize, VT_UI4}, { NULL, kpidHeadersSize, VT_UI8}, { NULL, kpidCTime, VT_FILETIME}, + { NULL, kpidId, VT_UI8}, +}; - { NULL, kpidSectorSize, VT_UI4}, - { NULL, kpidId, VT_UI8} - // { NULL, kpidSectorsPerTrack, VT_UI4}, - // { NULL, kpidNumHeads, VT_UI4}, - // { NULL, kpidHiddenSectors, VT_UI4} +/* +static const Byte kArcProps[] = +{ + kpidVolumeName, + kpidFileSystem, + kpidClusterSize, + kpidHeadersSize, + kpidCTime, + + kpidSectorSize, + kpidId + // kpidSectorsPerTrack, + // kpidNumHeads, + // kpidHiddenSectors }; +*/ IMP_IInArchive_Props -IMP_IInArchive_ArcProps +IMP_IInArchive_ArcProps_WITH_NAME -static void NtfsTimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop) +static void NtfsTimeToProp(UInt64 t, NCOM::CPropVariant &prop) { FILETIME ft; ft.dwLowDateTime = (DWORD)t; @@ -1499,19 +2260,19 @@ static void NtfsTimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop) STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; const CMftRec *volRec = (Recs.Size() > kRecIndex_Volume ? &Recs[kRecIndex_Volume] : NULL); - switch(propID) + switch (propID) { case kpidClusterSize: prop = Header.ClusterSize(); break; - case kpidPhySize: prop = Header.GetPhySize(); break; + case kpidPhySize: prop = PhySize; break; /* case kpidHeadersSize: { UInt64 val = 0; - for (int i = 0; i < kNumSysRecs; i++) + for (unsigned i = 0; i < kNumSysRecs; i++) { printf("\n%2d: %8I64d ", i, Recs[i].GetPackSize()); if (i == 8) @@ -1522,16 +2283,18 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) break; } */ - case kpidCTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.CTime, prop); break;break; + case kpidCTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.CTime, prop); break; + case kpidMTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.MTime, prop); break; + case kpidShortComment: case kpidVolumeName: { - for (int i = 0; i < VolAttrs.Size(); i++) + FOR_VECTOR (i, VolAttrs) { const CAttr &attr = VolAttrs[i]; if (attr.Type == ATTR_TYPE_VOLUME_NAME) { UString name; - GetString(attr.Data, (int)attr.Data.GetCapacity() / 2, name); + GetString(attr.Data, (unsigned)attr.Data.Size() / 2, name); prop = name; break; } @@ -1541,7 +2304,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidFileSystem: { AString s = "NTFS"; - for (int i = 0; i < VolAttrs.Size(); i++) + FOR_VECTOR (i, VolAttrs) { const CAttr &attr = VolAttrs[i]; if (attr.Type == ATTR_TYPE_VOLUME_INFO) @@ -1564,7 +2327,31 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) break; } case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break; + case kpidRecordSize: prop = (UInt32)1 << RecSizeLog; break; case kpidId: prop = Header.SerialNumber; break; + + case kpidIsTree: prop = true; break; + case kpidIsDeleted: prop = _showDeletedFiles; break; + case kpidIsAltStream: prop = ThereAreAltStreams; break; + case kpidIsAux: prop = true; break; + case kpidINode: prop = true; break; + + case kpidWarning: + if (_lostFolderIndex_Normal >= 0) + prop = "There are lost files"; + + /* + case kpidWarningFlags: + { + UInt32 flags = 0; + if (_headerWarning) + flags |= k_ErrorFlags_HeadersError; + if (flags != 0) + prop = flags; + break; + } + */ + // case kpidMediaType: prop = Header.MediaType; break; // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break; // case kpidNumHeads: prop = Header.NumHeads; break; @@ -1578,7 +2365,26 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; + if (index >= Items.Size()) + { + switch (propID) + { + case kpidName: + case kpidPath: + prop = VirtFolderNames[index - Items.Size()]; + break; + case kpidIsDir: prop = true; break; + case kpidIsAux: prop = true; break; + case kpidIsDeleted: + if ((int)index == _lostFolderIndex_Deleted) + prop = true; + break; + } + prop.Detach(value); + return S_OK; + } + const CItem &item = Items[index]; const CMftRec &rec = Recs[item.RecIndex]; @@ -1586,30 +2392,108 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (item.DataIndex >= 0) data = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start]; - switch(propID) + // const CFileNameAttr *fn = &rec.FileNames[item.NameIndex]; + /* + if (rec.FileNames.Size() > 0) + fn = &rec.FileNames[0]; + */ + + switch (propID) { case kpidPath: + GetItemPath(index, prop); + break; + + /* + case kpidLink: + if (!rec.ReparseAttr.SubsName.IsEmpty()) + { + prop = rec.ReparseAttr.SubsName; + } + break; + case kpidLink2: + if (!rec.ReparseAttr.PrintName.IsEmpty()) + { + prop = rec.ReparseAttr.PrintName; + } + break; + + case kpidLinkType: + if (rec.ReparseAttr.Tag != 0) + { + prop = (rec.ReparseAttr.Tag & 0xFFFF); + } + break; + */ + + case kpidINode: { - UString name = GetItemPath(index); - const wchar_t *prefix = NULL; - if (!rec.InUse()) - prefix = MY_DIR_PREFIX(L"DELETED"); - else if (item.RecIndex < kNumSysRecs) - prefix = MY_DIR_PREFIX(L"SYSTEM"); - if (prefix) - name = prefix + name; - prop = name; + // const CMftRec &rec = Recs[item.RecIndex]; + // prop = ((UInt64)rec.SeqNumber << 48) | item.RecIndex; + prop = item.RecIndex; + break; + } + + case kpidName: + { + // prop = item.Name; + const UString *s; + if (rec.IsAltStream(item.DataIndex)) + { + const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start]; + s = &data.Name; + if (item.ParentHost < 0) + { + UString s2 = rec.FileNames[item.NameIndex].Name; + s2 += L':'; + s2 += *s; + prop = s2; + break; + } + } + else + { + s = &rec.FileNames[item.NameIndex].Name; + } + prop = *s; + break; } case kpidIsDir: prop = item.IsDir(); break; + case kpidIsAltStream: prop = rec.IsAltStream(item.DataIndex); break; + case kpidIsDeleted: prop = !rec.InUse(); break; + case kpidIsAux: prop = false; break; + case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break; - case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break; case kpidATime: NtfsTimeToProp(rec.SiAttr.ATime, prop); break; + // case kpidRecMTime: if (fn) NtfsTimeToProp(rec.SiAttr.ThisRecMTime, prop); break; + + /* + case kpidMTime2: if (fn) NtfsTimeToProp(fn->MTime, prop); break; + case kpidCTime2: if (fn) NtfsTimeToProp(fn->CTime, prop); break; + case kpidATime2: if (fn) NtfsTimeToProp(fn->ATime, prop); break; + case kpidRecMTime2: if (fn) NtfsTimeToProp(fn->ThisRecMTime, prop); break; + */ + case kpidAttrib: - prop = item.Attrib; + { + UInt32 attrib; + /* WinXP-64: The CFileNameAttr::Attrib is not updated after some changes. Why? + CSiAttr:attrib is updated better. So we use CSiAttr:Sttrib */ + /* + if (fn) + attrib = fn->Attrib; + else + */ + attrib = rec.SiAttr.Attrib; + if (item.IsDir()) + attrib |= FILE_ATTRIBUTE_DIRECTORY; + + prop = attrib; break; + } case kpidLinks: prop = rec.MyNumNameLinks; break; case kpidSize: if (data) prop = data->GetSize(); break; case kpidPackSize: if (data) prop = data->GetPackSize(); break; @@ -1654,7 +2538,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = Items.Size(); if (numItems == 0) @@ -1663,9 +2547,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt64 totalSize = 0; for (i = 0; i < numItems; i++) { + UInt32 index = allFilesMode ? i : indices[i]; + if (index >= (UInt32)Items.Size()) + continue; const CItem &item = Items[allFilesMode ? i : indices[i]]; const CMftRec &rec = Recs[item.RecIndex]; - if (!rec.IsDir()) + if (item.DataIndex >= 0) totalSize += rec.GetSize(item.DataIndex); } RINOK(extractCallback->SetTotal(totalSize)); @@ -1673,9 +2560,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt64 totalPackSize; totalSize = totalPackSize = 0; - CByteBuffer buf; UInt32 clusterSize = Header.ClusterSize(); - buf.SetCapacity(clusterSize); + CByteBuffer buf(clusterSize); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; @@ -1696,17 +2582,18 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; + UInt32 index = allFilesMode ? i : indices[i]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - const CItem &item = Items[index]; - if (item.IsDir()) + if (index >= (UInt32)Items.Size() || Items[index].IsDir()) { RINOK(extractCallback->PrepareOperation(askMode)); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); continue; } + const CItem &item = Items[index]; + if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); @@ -1723,7 +2610,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<IInStream> inStream; HRESULT hres = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &inStream); if (hres == S_FALSE) - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; else { RINOK(hres); @@ -1750,15 +2637,46 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { - *numItems = Items.Size(); + *numItems = Items.Size() + VirtFolderNames.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +{ + InitProps(); + + for (UInt32 i = 0; i < numProps; i++) + { + UString name = names[i]; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + const PROPVARIANT &prop = values[i]; + + if (name.IsEqualTo("ld")) + { + RINOK(PROPVARIANT_to_bool(prop, _showDeletedFiles)); + } + else if (name.IsEqualTo("ls")) + { + RINOK(PROPVARIANT_to_bool(prop, _showSystemFiles)); + } + else + return E_INVALIDARG; + } return S_OK; } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"NTFS", L"ntfs img", 0, 0xD9, { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 }, 9, false, CreateArc, 0 }; + { "NTFS", "ntfs img", 0, 0xD9, + 9, { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 }, + 3, + 0, + CreateArc }; -REGISTER_ARC(Fat) +REGISTER_ARC(Ntfs) }} diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp index e5946969..08bcd062 100755..100644 --- a/CPP/7zip/Archive/PeHandler.cpp +++ b/CPP/7zip/Archive/PeHandler.cpp @@ -2,15 +2,17 @@ #include "StdAfx.h" +// #include <stdio.h> + #include "../../../C/CpuArch.h" -#include "Common/DynamicBuffer.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/StringConvert.h" +#include "../../Common/DynamicBuffer.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/StringConvert.h" -#include "Windows/PropVariantUtils.h" -#include "Windows/Time.h" +#include "../../Windows/PropVariantUtils.h" +#include "../../Windows/TimeUtils.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -24,21 +26,69 @@ #define Get32(p) GetUi32(p) #define Get64(p) GetUi64(p) +#define G16(offs, v) v = Get16(p + (offs)) +#define G32(offs, v) v = Get32(p + (offs)) +#define G64(offs, v) v = Get64(p + (offs)) + +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + using namespace NWindows; namespace NArchive { namespace NPe { -#define NUM_SCAN_SECTIONS_MAX (1 << 6) +static const UInt32 k_Signature = 0x00004550; -#define PE_SIG 0x00004550 -#define PE_OptHeader_Magic_32 0x10B -#define PE_OptHeader_Magic_64 0x20B +static HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 excludePos, UInt32 &res) +{ + const UInt32 kBufSizeMax = (UInt32)1 << 16; + UInt32 bufSize = MyMin(kBufSizeMax, size); + bufSize += (bufSize & 1); + CByteBuffer buffer(bufSize); + Byte *buf = buffer; + UInt32 sum = 0; + UInt32 pos = 0; + for (;;) + { + UInt32 rem = size - pos; + if (rem > bufSize) + rem = bufSize; + if (rem == 0) + break; + size_t processed = rem; + RINOK(ReadStream(stream, buf, &processed)); + + if ((processed & 1) != 0) + buf[processed] = 0; + + for (unsigned j = 0; j < 4; j++) + { + UInt32 e = excludePos + j; + if (pos <= e) + { + e -= pos; + if (e < processed) + buf[e] = 0; + } + } + + for (size_t i = 0; i < processed; i += 2) + { + sum += Get16(buf + i); + sum = (sum + (sum >> 16)) & 0xFFFF; + } + pos += (UInt32)processed; + if (rem != processed) + break; + } + res = sum + pos; + return S_OK; +} static AString GetDecString(UInt32 v) { - char sz[32]; - ConvertUInt64ToString(v, sz); + char sz[16]; + ConvertUInt32ToString(v, sz); return sz; } @@ -47,65 +97,80 @@ struct CVersion UInt16 Major; UInt16 Minor; - void Parse(const Byte *buf); - AString GetString() const { return GetDecString(Major) + '.' + GetDecString(Minor); } + void Parse(const Byte *p) + { + G16(0, Major); + G16(2, Minor); + } + void ToProp(NCOM::CPropVariant &prop); }; -void CVersion::Parse(const Byte *p) +void CVersion::ToProp(NCOM::CPropVariant &prop) { - Major = Get16(p); - Minor = Get16(p + 2); + char sz[32]; + ConvertUInt32ToString(Major, sz); + unsigned len = MyStringLen(sz); + sz[len] = '.'; + ConvertUInt32ToString(Minor, sz + len + 1); + prop = sz; } -static const UInt32 kHeaderSize = 4 + 20; +static const unsigned kHeaderSize = 4 + 20; +static const unsigned k_OptHeader32_Size_MIN = 96; +static const unsigned k_OptHeader64_Size_MIN = 112; + +static const UInt32 PE_IMAGE_FILE_DLL = (1 << 13); struct CHeader { + UInt16 Machine; UInt16 NumSections; UInt32 Time; UInt32 PointerToSymbolTable; UInt32 NumSymbols; UInt16 OptHeaderSize; UInt16 Flags; - UInt16 Machine; - bool Parse(const Byte *buf); + bool Parse(const Byte *p); + bool IsDll() const { return (Flags & PE_IMAGE_FILE_DLL) != 0; } }; bool CHeader::Parse(const Byte *p) { - if (Get32(p) != PE_SIG) + if (Get32(p) != k_Signature) return false; p += 4; - Machine = Get16(p + 0); - NumSections = Get16(p + 2); - Time = Get32(p + 4); - PointerToSymbolTable = Get32(p + 8); - NumSymbols = Get32(p + 12); - OptHeaderSize = Get16(p + 16); - Flags = Get16(p + 18); - return true; + G16( 0, Machine); + G16( 2, NumSections); + G32( 4, Time); + G32( 8, PointerToSymbolTable); + G32(12, NumSymbols); + G16(16, OptHeaderSize); + G16(18, Flags); + return OptHeaderSize >= k_OptHeader32_Size_MIN; } struct CDirLink { UInt32 Va; UInt32 Size; - void Parse(const Byte *p); + + CDirLink(): Va(0), Size(0) {} + void Parse(const Byte *p) + { + G32(0, Va); + G32(4, Size); + } }; -void CDirLink::Parse(const Byte *p) -{ - Va = Get32(p); - Size = Get32(p + 4); -} - enum { kDirLink_Certificate = 4, kDirLink_Debug = 6 }; +static const UInt32 kNumDirItemsMax = 16; + struct CDebugEntry { UInt32 Flags; @@ -116,21 +181,25 @@ struct CDebugEntry UInt32 Va; UInt32 Pa; - void Parse(const Byte *p); + void Parse(const Byte *p) + { + G32(0, Flags); + G32(4, Time); + Ver.Parse(p + 8); + G32(12, Type); + G32(16, Size); + G32(20, Va); + G32(24, Pa); + } }; -void CDebugEntry::Parse(const Byte *p) -{ - Flags = Get32(p); - Time = Get32(p + 4); - Ver.Parse(p + 8); - Type = Get32(p + 12); - Size = Get32(p + 16); - Va = Get32(p + 20); - Pa = Get32(p + 24); -} +static const UInt32 k_CheckSum_Field_Offset = 64; -static const UInt32 kNumDirItemsMax = 16; +static const UInt32 PE_OptHeader_Magic_32 = 0x10B; +static const UInt32 PE_OptHeader_Magic_64 = 0x20B; + +static const UInt32 k_SubSystems_EFI_First = 10; +static const UInt32 k_SubSystems_EFI_Last = 13; struct COptHeader { @@ -178,10 +247,19 @@ struct COptHeader return i; return -1; } + + bool IsSybSystem_EFI() const + { + return + SubSystem >= k_SubSystems_EFI_First && + SubSystem <= k_SubSystems_EFI_Last; + } }; bool COptHeader::Parse(const Byte *p, UInt32 size) { + if (size < k_OptHeader32_Size_MIN) + return false; Magic = Get16(p); switch (Magic) { @@ -194,19 +272,14 @@ bool COptHeader::Parse(const Byte *p, UInt32 size) LinkerVerMajor = p[2]; LinkerVerMinor = p[3]; - bool hdr64 = Is64Bit(); + G32( 4, CodeSize); + G32( 8, InitDataSize); + G32(12, UninitDataSize); + // G32(16, AddressOfEntryPoint); + // G32(20, BaseOfCode); - CodeSize = Get32(p + 4); - InitDataSize = Get32(p + 8); - UninitDataSize = Get32(p + 12); - - // AddressOfEntryPoint = Get32(p + 16); - // BaseOfCode = Get32(p + 20); - // BaseOfData32 = hdr64 ? 0: Get32(p + 24); - ImageBase = hdr64 ? GetUi64(p + 24) : Get32(p + 28); - - SectAlign = Get32(p + 32); - FileAlign = Get32(p + 36); + G32(32, SectAlign); + G32(36, FileAlign); OsVer.Parse(p + 40); ImageVer.Parse(p + 44); @@ -214,28 +287,39 @@ bool COptHeader::Parse(const Byte *p, UInt32 size) // reserved = Get32(p + 52); - ImageSize = Get32(p + 56); - HeadersSize = Get32(p + 60); - CheckSum = Get32(p + 64); - SubSystem = Get16(p + 68); - DllCharacts = Get16(p + 70); + G32(56, ImageSize); + G32(60, HeadersSize); + G32(64, CheckSum); + G16(68, SubSystem); + G16(70, DllCharacts); - if (hdr64) + UInt32 pos; + if (Is64Bit()) { - StackReserve = Get64(p + 72); - StackCommit = Get64(p + 80); - HeapReserve = Get64(p + 88); - HeapCommit = Get64(p + 96); + if (size < k_OptHeader64_Size_MIN) + return false; + // BaseOfData32 = 0; + G64(24, ImageBase); + G64(72, StackReserve); + G64(80, StackCommit); + G64(88, HeapReserve); + G64(96, HeapCommit); + pos = 108; } else { - StackReserve = Get32(p + 72); - StackCommit = Get32(p + 76); - HeapReserve = Get32(p + 80); - HeapCommit = Get32(p + 84); + // G32(24, BaseOfData32); + G32(28, ImageBase); + G32(72, StackReserve); + G32(76, StackCommit); + G32(80, HeapReserve); + G32(84, HeapCommit); + pos = 92; } - UInt32 pos = (hdr64 ? 108 : 92); - NumDirItems = Get32(p + pos); + + G32(pos, NumDirItems); + if (NumDirItems > (1 << 16)) + return false; pos += 4; if (pos + 8 * NumDirItems != size) return false; @@ -257,28 +341,31 @@ struct CSection UInt32 Flags; UInt32 Time; // UInt16 NumRelocs; - bool IsDebug; bool IsRealSect; + bool IsDebug; bool IsAdditionalSection; CSection(): IsRealSect(false), IsDebug(false), IsAdditionalSection(false) {} - UInt64 GetPackSize() const { return PSize; } - void UpdateTotalSize(UInt32 &totalSize) + void UpdateTotalSize(UInt32 &totalSize) const { UInt32 t = Pa + PSize; - if (t > totalSize) + if (totalSize < t) totalSize = t; } void Parse(const Byte *p); + + int Compare(const CSection &s) const + { + RINOZ(MyCompare(Pa, s.Pa)); + return MyCompare(PSize, s.PSize); + } }; -static bool operator <(const CSection &a1, const CSection &a2) { return (a1.Pa < a2.Pa) || ((a1.Pa == a2.Pa) && (a1.PSize < a2.PSize)) ; } -static bool operator ==(const CSection &a1, const CSection &a2) { return (a1.Pa == a2.Pa) && (a1.PSize == a2.PSize); } +static const unsigned kNameSize = 8; static AString GetName(const Byte *name) { - const int kNameSize = 8; AString res; char *p = res.GetBuffer(kNameSize); memcpy(p, name, kNameSize); @@ -290,12 +377,12 @@ static AString GetName(const Byte *name) void CSection::Parse(const Byte *p) { Name = GetName(p); - VSize = Get32(p + 8); - Va = Get32(p + 12); - PSize = Get32(p + 16); - Pa = Get32(p + 20); - // NumRelocs = Get16(p + 32); - Flags = Get32(p + 36); + G32( 8, VSize); + G32(12, Va); + G32(16, PSize); + G32(20, Pa); + // G16(32, NumRelocs); + G32(36, Flags); } static const CUInt32PCharPair g_HeaderCharacts[] = @@ -352,6 +439,7 @@ static const CUInt32PCharPair g_SectFlags[] = static const CUInt32PCharPair g_MachinePairs[] = { { 0x014C, "x86" }, + { 0x014D, "I860" }, { 0x0162, "MIPS-R3000" }, { 0x0166, "MIPS-R4000" }, { 0x0168, "MIPS-R10000" }, @@ -364,24 +452,31 @@ static const CUInt32PCharPair g_MachinePairs[] = { 0x01A8, "SH5" }, { 0x01C0, "ARM" }, { 0x01C2, "ARM-Thumb" }, + { 0x01C4, "ARM-NT" }, + { 0x01D3, "AM33" }, { 0x01F0, "PPC" }, { 0x01F1, "PPC-FP" }, { 0x0200, "IA-64" }, + { 0x0266, "MIPS-16" }, { 0x0284, "Alpha-64" }, - { 0x0200, "IA-64" }, - { 0x0366, "MIPSFPU" }, + { 0x0366, "MIPS-FPU" }, + { 0x0466, "MIPS-FPU16" }, + { 0x0520, "TriCore" }, + { 0x0CEF, "CEF" }, + { 0x0EBC, "EFI" }, { 0x8664, "x64" }, - { 0x0EBC, "EFI" } + { 0x9041, "M32R" }, + { 0xC0EE, "CEE" } }; static const CUInt32PCharPair g_SubSystems[] = { - { 0, "Unknown" }, - { 1, "Native" }, - { 2, "Windows GUI" }, - { 3, "Windows CUI" }, - { 7, "Posix" }, - { 9, "Windows CE" }, + { 0, "Unknown" }, + { 1, "Native" }, + { 2, "Windows GUI" }, + { 3, "Windows CUI" }, + { 7, "Posix" }, + { 9, "Windows CE" }, { 10, "EFI" }, { 11, "EFI Boot" }, { 12, "EFI Runtime" }, @@ -391,35 +486,35 @@ static const CUInt32PCharPair g_SubSystems[] = static const wchar_t *g_ResTypes[] = { - NULL, - L"CURSOR", - L"BITMAP", - L"ICON", - L"MENU", - L"DIALOG", - L"STRING", - L"FONTDIR", - L"FONT", - L"ACCELERATOR", - L"RCDATA", - L"MESSAGETABLE", - L"GROUP_CURSOR", - NULL, - L"GROUP_ICON", - NULL, - L"VERSION", - L"DLGINCLUDE", - NULL, - L"PLUGPLAY", - L"VXD", - L"ANICURSOR", - L"ANIICON", - L"HTML", - L"MANIFEST" + NULL + , L"CURSOR" + , L"BITMAP" + , L"ICON" + , L"MENU" + , L"DIALOG" + , L"STRING" + , L"FONTDIR" + , L"FONT" + , L"ACCELERATOR" + , L"RCDATA" + , L"MESSAGETABLE" + , L"GROUP_CURSOR" + , NULL + , L"GROUP_ICON" + , NULL + , L"VERSION" + , L"DLGINCLUDE" + , NULL + , L"PLUGPLAY" + , L"VXD" + , L"ANICURSOR" + , L"ANIICON" + , L"HTML" + , L"MANIFEST" }; -const UInt32 kFlag = (UInt32)1 << 31; -const UInt32 kMask = ~kFlag; +static const UInt32 kFlag = (UInt32)1 << 31; +static const UInt32 kMask = ~kFlag; struct CTableItem { @@ -428,8 +523,8 @@ struct CTableItem }; -const UInt32 kBmpHeaderSize = 14; -const UInt32 kIconHeaderSize = 22; +static const UInt32 kBmpHeaderSize = 14; +static const UInt32 kIconHeaderSize = 22; struct CResItem { @@ -450,45 +545,110 @@ struct CResItem bool IsIcon() const { return Type == 3; } bool IsString() const { return Type == 6; } bool IsRcData() const { return Type == 10; } + bool IsVersion() const { return Type == 16; } bool IsRcDataOrUnknown() const { return IsRcData() || Type > 64; } }; -struct CStringItem +struct CTextFile { - UInt32 Lang; - UInt32 Size; CByteDynamicBuffer Buf; + size_t FinalSize() const { return Buf.GetPos(); } + void AddChar(Byte c); void AddWChar(UInt16 c); + void AddWChar_Smart(UInt16 c); + void NewLine(); + void AddString(const char *s); + void AddSpaces(int num); + void AddBytes(const Byte *p, size_t len); + + void OpenBlock(int num) + { + AddSpaces(num); + AddChar('{'); + NewLine(); + } + void CloseBlock(int num) + { + AddSpaces(num); + AddChar('}'); + NewLine(); + } }; -void CStringItem::AddChar(Byte c) +void CTextFile::AddChar(Byte c) +{ + Byte *p = Buf.GetCurPtrAndGrow(2); + p[0] = c; + p[1] = 0; +} + +void CTextFile::AddWChar(UInt16 c) { - Buf.EnsureCapacity(Size + 2); - Buf[Size++] = c; - Buf[Size++] = 0; + Byte *p = Buf.GetCurPtrAndGrow(2); + SetUi16(p, c); } -void CStringItem::AddWChar(UInt16 c) +void CTextFile::AddWChar_Smart(UInt16 c) { if (c == '\n') { AddChar('\\'); c = 'n'; } - Buf.EnsureCapacity(Size + 2); - SetUi16(Buf + Size, c); - Size += 2; + AddWChar(c); +} + +void CTextFile::NewLine() +{ + AddChar(0x0D); + AddChar(0x0A); +} + +void CTextFile::AddString(const char *s) +{ + for (;; s++) + { + char c = *s; + if (c == 0) + return; + AddChar(c); + } } +void CTextFile::AddSpaces(int num) +{ + for (int i = 0; i < num; i++) + AddChar(' '); +} + +void CTextFile::AddBytes(const Byte *data, size_t size) +{ + Byte *p = Buf.GetCurPtrAndGrow(size); + memcpy(p, data, size); +} + +struct CStringItem: public CTextFile +{ + UInt32 Lang; +}; + +struct CByteBuffer_WithLang: public CByteBuffer +{ + UInt32 Lang; +}; + + struct CMixItem { int SectionIndex; int ResourceIndex; int StringIndex; + int VersionIndex; - bool IsSectionItem() const { return ResourceIndex < 0 && StringIndex < 0; }; + CMixItem(): SectionIndex(-1), ResourceIndex(-1), StringIndex(-1), VersionIndex(-1) {} + bool IsSectionItem() const { return ResourceIndex < 0 && StringIndex < 0 && VersionIndex < 0; }; }; struct CUsedBitmap @@ -498,113 +658,95 @@ public: void Alloc(size_t size) { size = (size + 7) / 8; - Buf.SetCapacity(size); + Buf.Alloc(size); memset(Buf, 0, size); } + void Free() { - Buf.SetCapacity(0); + Buf.Free(); } - bool SetRange(size_t from, int size) + + bool SetRange(size_t from, unsigned size) { - for (int i = 0; i < size; i++) + for (unsigned i = 0; i < size; i++) { size_t pos = (from + i) >> 3; Byte mask = (Byte)(1 << ((from + i) & 7)); Byte b = Buf[pos]; if ((b & mask) != 0) return false; - Buf[pos] = b | mask; + Buf[pos] = (Byte)(b | mask); } return true; } }; +struct CStringKeyValue +{ + UString Key; + UString Value; +}; class CHandler: public IInArchive, public IInArchiveGetStream, + public IArchiveAllowTail, public CMyUnknownImp { CMyComPtr<IInStream> _stream; CObjectVector<CSection> _sections; UInt32 _peOffset; CHeader _header; - COptHeader _optHeader; UInt32 _totalSize; - UInt32 _totalSizeLimited; Int32 _mainSubfile; + CRecordVector<CMixItem> _mixItems; CRecordVector<CResItem> _items; CObjectVector<CStringItem> _strings; + CObjectVector<CByteBuffer_WithLang> _versionFiles; + UString _versionFullString; + UString _versionShortString; + UString _originalFilename; + CObjectVector<CStringKeyValue> _versionKeys; CByteBuffer _buf; bool _oneLang; - UString _resourceFileName; + UString _resourcesPrefix; CUsedBitmap _usedRes; bool _parseResources; + bool _checksumError; - CRecordVector<CMixItem> _mixItems; + COptHeader _optHeader; + + bool _allowTail; HRESULT LoadDebugSections(IInStream *stream, bool &thereIsSection); HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); - bool Parse(const Byte *buf, UInt32 size); void AddResNameToString(UString &s, UInt32 id) const; - UString GetLangPrefix(UInt32 lang); + void AddLangPrefix(UString &s, UInt32 lang) const; HRESULT ReadString(UInt32 offset, UString &dest) const; HRESULT ReadTable(UInt32 offset, CRecordVector<CTableItem> &items); bool ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size); - HRESULT OpenResources(int sectIndex, IInStream *stream, IArchiveOpenCallback *callback); + HRESULT OpenResources(unsigned sectIndex, IInStream *stream, IArchiveOpenCallback *callback); void CloseResources(); bool CheckItem(const CSection §, const CResItem &item, size_t offset) const { - return item.Offset >= sect.Va && offset <= _buf.GetCapacity() && _buf.GetCapacity() - offset >= item.Size; + return item.Offset >= sect.Va && offset <= _buf.Size() && _buf.Size() - offset >= item.Size; } public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + CHandler(): _allowTail(false) {} + + MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IArchiveAllowTail) INTERFACE_IInArchive(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(AllowTail)(Int32 allowTail); }; -bool CHandler::Parse(const Byte *buf, UInt32 size) -{ - UInt32 i; - if (size < 512) - return false; - _peOffset = Get32(buf + 0x3C); - if (_peOffset >= 0x1000 || _peOffset + 512 > size || (_peOffset & 7) != 0) - return false; - - UInt32 pos = _peOffset; - if (!_header.Parse(buf + pos)) - return false; - if (_header.OptHeaderSize > 512 || _header.NumSections > NUM_SCAN_SECTIONS_MAX) - return false; - pos += kHeaderSize; - - if (!_optHeader.Parse(buf + pos, _header.OptHeaderSize)) - return false; - - pos += _header.OptHeaderSize; - _totalSize = pos; - - for (i = 0; i < _header.NumSections; i++, pos += kSectionSize) - { - CSection sect; - if (pos + kSectionSize > size) - return false; - sect.Parse(buf + pos); - sect.IsRealSect = true; - sect.UpdateTotalSize(_totalSize); - _sections.Add(sect); - } - - return true; -} enum { @@ -633,13 +775,15 @@ enum static const STATPROPSTG kArcProps[] = { + // { NULL, kpidWarning, VT_BSTR}, { NULL, kpidCpu, VT_BSTR}, { NULL, kpidBit64, VT_BOOL}, { NULL, kpidCharacts, VT_BSTR}, { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidPhySize, VT_UI4}, { NULL, kpidHeadersSize, VT_UI4}, { NULL, kpidChecksum, VT_UI4}, + { NULL, kpidName, VT_BSTR}, + { L"Image Size", kpidImageSize, VT_UI4}, { L"Section Alignment", kpidSectAlign, VT_UI4}, { L"File Alignment", kpidFileAlign, VT_UI4}, @@ -656,31 +800,28 @@ static const STATPROPSTG kArcProps[] = { L"Stack Commit", kpidStackCommit, VT_UI8}, { L"Heap Reserve", kpidHeapReserve, VT_UI8}, { L"Heap Commit", kpidHeapCommit, VT_UI8}, - { L"Image Base", kpidImageBase, VT_UI8} + { L"Image Base", kpidImageBase, VT_UI8}, + { NULL, kpidComment, VT_BSTR}, // { L"Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8}, // { L"Base Of Code", kpidBaseOfCode, VT_UI8}, // { L"Base Of Data", kpidBaseOfData32, VT_UI8}, }; -static const STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidCharacts, VT_BSTR}, - { NULL, kpidOffset, VT_UI8}, - { NULL, kpidVa, VT_UI8} + kpidPath, + kpidSize, + kpidPackSize, + kpidVirtualSize, + kpidCharacts, + kpidOffset, + kpidVa, }; IMP_IInArchive_Props IMP_IInArchive_ArcProps_WITH_NAME -static void VerToProp(const CVersion &v, NCOM::CPropVariant &prop) -{ - StringToProp(v.GetString(), prop); -} - -void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop) +static void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop) { if (unixTime != 0) { @@ -694,20 +835,20 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidSectAlign: prop = _optHeader.SectAlign; break; case kpidFileAlign: prop = _optHeader.FileAlign; break; case kpidLinkerVer: { CVersion v = { _optHeader.LinkerVerMajor, _optHeader.LinkerVerMinor }; - VerToProp(v, prop); + v.ToProp(prop); break; } - case kpidOsVer: VerToProp(_optHeader.OsVer, prop); break; - case kpidImageVer: VerToProp(_optHeader.ImageVer, prop); break; - case kpidSubsysVer: VerToProp(_optHeader.SubsysVer, prop); break; + case kpidOsVer: _optHeader.OsVer.ToProp(prop); break; + case kpidImageVer: _optHeader.ImageVer.ToProp(prop); break; + case kpidSubsysVer: _optHeader.SubsysVer.ToProp(prop); break; case kpidCodeSize: prop = _optHeader.CodeSize; break; case kpidInitDataSize: prop = _optHeader.InitDataSize; break; case kpidUnInitDataSize: prop = _optHeader.UninitDataSize; break; @@ -715,7 +856,27 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidPhySize: prop = _totalSize; break; case kpidHeadersSize: prop = _optHeader.HeadersSize; break; case kpidChecksum: prop = _optHeader.CheckSum; break; + case kpidComment: if (!_versionFullString.IsEmpty()) prop = _versionFullString; break; + case kpidShortComment: + if (!_versionShortString.IsEmpty()) + prop = _versionShortString; + else + { + PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); + } + break; + + case kpidName: if (!_originalFilename.IsEmpty()) prop = _originalFilename; break; + case kpidExtension: + if (_header.IsDll()) + prop = _optHeader.IsSybSystem_EFI() ? "efi" : "dll"; + break; + // case kpidIsSelfExe: prop = !_header.IsDll(); break; + + // case kpidError: + case kpidWarning: if (_checksumError) prop = "Checksum error"; break; + 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; @@ -741,6 +902,32 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) COM_TRY_END } +HRESULT CHandler::ReadString(UInt32 offset, UString &dest) const +{ + if ((offset & 1) != 0 || offset >= _buf.Size()) + return S_FALSE; + size_t rem = _buf.Size() - offset; + if (rem < 2) + return S_FALSE; + unsigned len = Get16(_buf + offset); + if ((rem - 2) / 2 < len) + return S_FALSE; + dest.Empty(); + wchar_t *destBuf = dest.GetBuffer(len); + offset += 2; + const Byte *src = _buf + offset; + unsigned i; + for (i = 0; i < len; i++) + { + wchar_t c = (wchar_t)Get16(src + i * 2); + if (c == 0) + break; + destBuf[i] = c; + } + dest.ReleaseBuffer(i); + return S_OK; +} + void CHandler::AddResNameToString(UString &s, UInt32 id) const { if ((id & kFlag) != 0) @@ -748,32 +935,33 @@ void CHandler::AddResNameToString(UString &s, UInt32 id) const UString name; if (ReadString(id & kMask, name) == S_OK) { - if (name.IsEmpty()) - s += L"[]"; - else + const wchar_t *str = L"[]"; + if (name.Len() > 1 && name[0] == '"' && name.Back() == '"') { - if (name.Length() > 1 && name[0] == '"' && name.Back() == '"') - name = name.Mid(1, name.Length() - 2); - s += name; + if (name.Len() != 2) + { + name.DeleteBack(); + str = name.Ptr(1); + } } + else if (!name.IsEmpty()) + str = name; + s += str; return; } } - wchar_t sz[32]; + wchar_t sz[16]; ConvertUInt32ToString(id, sz); s += sz; } -UString CHandler::GetLangPrefix(UInt32 lang) +void CHandler::AddLangPrefix(UString &s, UInt32 lang) const { - UString s = _resourceFileName; - s += WCHAR_PATH_SEPARATOR; if (!_oneLang) { AddResNameToString(s, lang); s += WCHAR_PATH_SEPARATOR; } - return s; } STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) @@ -784,43 +972,53 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (mixItem.StringIndex >= 0) { const CStringItem &item = _strings[mixItem.StringIndex]; - switch(propID) + switch (propID) { - case kpidPath: prop = GetLangPrefix(item.Lang) + L"string.txt"; break; + case kpidPath: + { + UString s = _resourcesPrefix; + AddLangPrefix(s, item.Lang); + s += L"string.txt"; + prop = s; + break; + } case kpidSize: case kpidPackSize: - prop = (UInt64)item.Size; break; + prop = (UInt64)item.FinalSize(); break; } } - else if (mixItem.ResourceIndex < 0) + else if (mixItem.VersionIndex >= 0) { - const CSection &item = _sections[mixItem.SectionIndex]; - switch(propID) + const CByteBuffer_WithLang &item = _versionFiles[mixItem.VersionIndex]; + switch (propID) { - case kpidPath: StringToProp(item.Name, prop); break; - case kpidSize: prop = (UInt64)item.VSize; break; - case kpidPackSize: prop = (UInt64)item.GetPackSize(); break; - case kpidOffset: prop = item.Pa; break; - case kpidVa: if (item.IsRealSect) prop = item.Va; break; - case kpidMTime: - case kpidCTime: - TimeToProp(item.IsDebug ? item.Time : _header.Time, prop); break; - case kpidCharacts: if (item.IsRealSect) FLAGS_TO_PROP(g_SectFlags, item.Flags, prop); break; + case kpidPath: + { + UString s = _resourcesPrefix; + AddLangPrefix(s, item.Lang); + s += L"version.txt"; + prop = s; + break; + } + case kpidSize: + case kpidPackSize: + prop = (UInt64)item.Size(); break; } } - else + else if (mixItem.ResourceIndex >= 0) { const CResItem &item = _items[mixItem.ResourceIndex]; - switch(propID) + switch (propID) { case kpidPath: { - UString s = GetLangPrefix(item.Lang); + UString s = _resourcesPrefix; + AddLangPrefix(s, item.Lang); { const wchar_t *p = NULL; - if (item.Type < sizeof(g_ResTypes) / sizeof(g_ResTypes[0])) + if (item.Type < ARRAY_SIZE(g_ResTypes)) p = g_ResTypes[item.Type]; - if (p != 0) + if (p) s += p; else AddResNameToString(s, item.Type); @@ -841,6 +1039,24 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidPackSize: prop = (UInt64)item.Size; break; } } + else + { + const CSection &item = _sections[mixItem.SectionIndex]; + switch (propID) + { + case kpidPath: prop = MultiByteToUnicodeString(item.Name); break; + case kpidSize: prop = (UInt64)MyMin(item.PSize, item.VSize); break; + case kpidPackSize: prop = (UInt64)item.PSize; break; + case kpidVirtualSize: prop = (UInt64)item.VSize; break; + case kpidOffset: prop = item.Pa; break; + case kpidVa: if (item.IsRealSect) prop = item.Va; break; + case kpidMTime: + case kpidCTime: + TimeToProp(item.IsDebug ? item.Time : _header.Time, prop); break; + case kpidCharacts: if (item.IsRealSect) FLAGS_TO_PROP(g_SectFlags, item.Flags, prop); break; + case kpidZerosTailIsAllowed: if (!item.IsRealSect) prop = true; break; + } + } prop.Detach(value); return S_OK; COM_TRY_END @@ -858,11 +1074,11 @@ HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection) return S_FALSE; UInt64 pa = 0; - int i; + unsigned i; for (i = 0; i < _sections.Size(); i++) { const CSection § = _sections[i]; - if (sect.Va < debugLink.Va && debugLink.Va + debugLink.Size <= sect.Va + sect.PSize) + if (sect.Va <= debugLink.Va && debugLink.Va + debugLink.Size <= sect.Va + sect.PSize) { pa = sect.Pa + (debugLink.Va - sect.Va); break; @@ -870,19 +1086,18 @@ HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection) } if (i == _sections.Size()) { - return S_OK; // Exe for ARM requires S_OK // return S_FALSE; + return S_OK; } - CByteBuffer buffer; - buffer.SetCapacity(debugLink.Size); + CByteBuffer buffer(debugLink.Size); Byte *buf = buffer; RINOK(stream->Seek(pa, STREAM_SEEK_SET, NULL)); RINOK(ReadStream_FALSE(stream, buf, debugLink.Size)); - for (i = 0; i < (int)numItems; i++) + for (i = 0; i < numItems; i++) { CDebugEntry de; de.Parse(buf); @@ -890,20 +1105,19 @@ HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection) if (de.Size == 0) continue; - CSection sect; - sect.Name = ".debug" + GetDecString(i); - - sect.IsDebug = true; - sect.Time = de.Time; - sect.Va = de.Va; - sect.Pa = de.Pa; - sect.PSize = sect.VSize = de.Size; - UInt32 totalSize = sect.Pa + sect.PSize; + UInt32 totalSize = de.Pa + de.Size; if (totalSize > _totalSize) { _totalSize = totalSize; - _sections.Add(sect); thereIsSection = true; + + CSection § = _sections.AddNew(); + sect.Name = ".debug" + GetDecString(i); + sect.IsDebug = true; + sect.Time = de.Time; + sect.Va = de.Va; + sect.Pa = de.Pa; + sect.PSize = sect.VSize = de.Size; } buf += kEntrySize; } @@ -911,31 +1125,13 @@ HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection) return S_OK; } -HRESULT CHandler::ReadString(UInt32 offset, UString &dest) const -{ - if ((offset & 1) != 0 || offset >= _buf.GetCapacity()) - return S_FALSE; - size_t rem = _buf.GetCapacity() - offset; - if (rem < 2) - return S_FALSE; - unsigned length = Get16(_buf + offset); - if ((rem - 2) / 2 < length) - return S_FALSE; - dest.Empty(); - offset += 2; - for (unsigned i = 0; i < length; i++) - dest += (wchar_t)Get16(_buf + offset + i * 2); - return S_OK; -} - HRESULT CHandler::ReadTable(UInt32 offset, CRecordVector<CTableItem> &items) { - if ((offset & 3) != 0 || offset >= _buf.GetCapacity()) + if ((offset & 3) != 0 || offset >= _buf.Size()) return S_FALSE; - size_t rem = _buf.GetCapacity() - offset; + size_t rem = _buf.Size() - offset; if (rem < 16) return S_FALSE; - items.Clear(); unsigned numNameItems = Get16(_buf + offset + 12); unsigned numIdItems = Get16(_buf + offset + 14); unsigned numItems = numNameItems + numIdItems; @@ -944,25 +1140,23 @@ HRESULT CHandler::ReadTable(UInt32 offset, CRecordVector<CTableItem> &items) if (!_usedRes.SetRange(offset, 16 + numItems * 8)) return S_FALSE; offset += 16; - _oneLang = true; - unsigned i; - for (i = 0; i < numItems; i++) + items.ClearAndReserve(numItems); + for (unsigned i = 0; i < numItems; i++, offset += 8) { - CTableItem item; const Byte *buf = _buf + offset; - offset += 8; + CTableItem item; item.ID = Get32(buf + 0); - if (((item.ID & kFlag) != 0) != (i < numNameItems)) + if ((bool)((item.ID & kFlag) != 0) != (bool)(i < numNameItems)) return S_FALSE; item.Offset = Get32(buf + 4); - items.Add(item); + items.AddInReserved(item); } return S_OK; } static const UInt32 kFileSizeMax = (UInt32)1 << 30; -static const int kNumResItemsMax = (UInt32)1 << 23; -static const int kNumStringLangsMax = 128; +static const unsigned kNumResItemsMax = (unsigned)1 << 23; +static const unsigned kNumStringLangsMax = 256; // BITMAPINFOHEADER struct CBitmapInfoHeader @@ -984,12 +1178,12 @@ bool CBitmapInfoHeader::Parse(const Byte *p, size_t size) { if (size < kBitmapInfoHeader_Size || Get32(p) != kBitmapInfoHeader_Size) return false; - XSize = Get32(p + 4); - YSize = (Int32)Get32(p + 8); - Planes = Get16(p + 12); - BitCount = Get16(p + 14); - Compression = Get32(p + 16); - SizeImage = Get32(p + 20); + G32( 4, XSize); + G32( 8, YSize); + G16(12, Planes); + G16(14, BitCount); + G32(16, Compression); + G32(20, SizeImage); return true; } @@ -1089,7 +1283,7 @@ bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 si if ((size & 1) != 0) return false; - int i; + unsigned i; for (i = 0; i < _strings.Size(); i++) if (_strings[i].Lang == lang) break; @@ -1097,10 +1291,8 @@ bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 si { if (_strings.Size() >= kNumStringLangsMax) return false; - CStringItem item; - item.Size = 0; + CStringItem &item = _strings.AddNew(); item.Lang = lang; - i = _strings.Add(item); } CStringItem &item = _strings[i]; @@ -1117,22 +1309,584 @@ bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 si if (size - pos < len * 2) return false; char temp[32]; - ConvertUInt32ToString(id + i, temp); + ConvertUInt32ToString(id + i, temp); size_t tempLen = strlen(temp); size_t j; for (j = 0; j < tempLen; j++) item.AddChar(temp[j]); item.AddChar('\t'); for (j = 0; j < len; j++, pos += 2) - item.AddWChar(Get16(src + pos)); - item.AddChar(0x0D); - item.AddChar(0x0A); + item.AddWChar_Smart(Get16(src + pos)); + item.NewLine(); + } + } + if (size == pos) + return true; + + // Some rare case files have additional ZERO. + if (size == pos + 2 && Get16(src + pos) == 0) + return true; + + return false; +} + + +// ---------- VERSION ---------- + +static const UInt32 kMy_VS_FFI_SIGNATURE = 0xFEEF04BD; + +struct CMy_VS_FIXEDFILEINFO +{ + // UInt32 Signature; + // UInt32 StrucVersion; + UInt32 VersionMS; + UInt32 VersionLS; + UInt32 ProductVersionMS; + UInt32 ProductVersionLS; + UInt32 FlagsMask; + UInt32 Flags; + UInt32 OS; + UInt32 Type; + UInt32 Subtype; + UInt32 DateMS; + UInt32 DateLS; + + bool Parse(const Byte *p); + void PrintToTextFile(CTextFile &f, CObjectVector<CStringKeyValue> &keys); +}; + +bool CMy_VS_FIXEDFILEINFO::Parse(const Byte *p) +{ + if (Get32(p) != kMy_VS_FFI_SIGNATURE) // signature; + return false; + // G32(0x04, StrucVersion); + G32(0x08, VersionMS); + G32(0x0C, VersionLS); + G32(0x10, ProductVersionMS); + G32(0x14, ProductVersionLS); + G32(0x18, FlagsMask); + G32(0x1C, Flags); + G32(0x20, OS); + G32(0x24, Type); + G32(0x28, Subtype); + G32(0x2C, DateMS); + G32(0x40, DateLS); + return true; +} + +static void PrintUInt32(CTextFile &f, UInt32 v) +{ + char s[16]; + ConvertUInt32ToString(v, s); + f.AddString(s); +} + +static void PrintUInt32(UString &dest, UInt32 v) +{ + wchar_t s[16]; + ConvertUInt32ToString(v, s); + dest += s; +} + +static void PrintHex(CTextFile &f, UInt32 val) +{ + char temp[16]; + temp[0] = '0'; + temp[1] = 'x'; + ConvertUInt32ToHex(val, temp + 2); + f.AddString(temp); +} + +static void PrintVersion(CTextFile &f, UInt32 ms, UInt32 ls) +{ + PrintUInt32(f, HIWORD(ms)); f.AddChar(','); + PrintUInt32(f, LOWORD(ms)); f.AddChar(','); + PrintUInt32(f, HIWORD(ls)); f.AddChar(','); + PrintUInt32(f, LOWORD(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, LOWORD(ls)); +} + +static const char *k_VS_FileFlags[] = +{ + "DEBUG" + , "PRERELEASE" + , "PATCHED" + , "PRIVATEBUILD" + , "INFOINFERRED" + , "SPECIALBUILD" +}; + +static const CUInt32PCharPair k_VS_FileOS[] = +{ + { 0x10001, "VOS_DOS_WINDOWS16" }, + { 0x10004, "VOS_DOS_WINDOWS32" }, + { 0x20002, "VOS_OS216_PM16" }, + { 0x30003, "VOS_OS232_PM32" }, + { 0x40004, "VOS_NT_WINDOWS32" } +}; + +static const char *k_VS_FileOS_High[] = +{ + "VOS_UNKNOWN" + , "VOS_DOS" + , "VOS_OS216" + , "VOS_OS232" + , "VOS_NT" + , "VOS_WINCE" +}; + +static const UInt32 kMY_VFT_DRV = 3; +static const UInt32 kMY_VFT_FONT = 4; + +static const char *k_VS_FileOS_Low[] = +{ + "VOS__BASE" + , "VOS__WINDOWS16" + , "VOS__PM16" + , "VOS__PM32" + , "VOS__WINDOWS32" +}; + +static const char *k_VS_FileType[] = +{ + "VFT_UNKNOWN" + , "VFT_APP" + , "VFT_DLL" + , "VFT_DRV" + , "VFT_FONT" + , "VFT_VXD" + , "0x6" + , "VFT_STATIC_LIB" +}; + +// Subtype for VFT_DRV Type +static const char *k_VS_FileSubType_DRV[] = +{ + "0" + , "PRINTER" + , "KEYBOARD" + , "LANGUAGE" + , "DISPLAY" + , "MOUSE" + , "NETWORK" + , "SYSTEM" + , "INSTALLABLE" + , "SOUND" + , "COMM" + , "INPUTMETHOD" + , "VERSIONED_PRINTER" +}; + +// Subtype for VFT_FONT Type +static const char *k_VS_FileSubType_FONT[] = +{ + "0" + , "VFT2_FONT_RASTER" + , "VFT2_FONT_VECTOR" + , "VFT2_FONT_TRUETYPE" +}; + +static int FindKey(CObjectVector<CStringKeyValue> &v, const UString &key) +{ + FOR_VECTOR (i, v) + if (v[i].Key == key) + return i; + return -1; +} + +static void AddToUniqueUStringVector(CObjectVector<CStringKeyValue> &v, const UString &key, const UString &value) +{ + bool needInsert = false; + unsigned i; + for (i = 0; i < v.Size(); i++) + { + if (v[i].Key == key) + { + if (v[i].Value == value) + return; + needInsert = true; + } + else if (needInsert) + break; + } + CStringKeyValue &pair = v.InsertNew(i); + pair.Key = key; + pair.Value = value; +} + +void CMy_VS_FIXEDFILEINFO::PrintToTextFile(CTextFile &f, CObjectVector<CStringKeyValue> &keys) +{ + f.AddString("FILEVERSION "); + PrintVersion(f, VersionMS, VersionLS); + f.NewLine(); + + f.AddString("PRODUCTVERSION "); + PrintVersion(f, ProductVersionMS, ProductVersionLS); + f.NewLine(); + + { + UString s; + PrintVersion(s, VersionMS, VersionLS); + AddToUniqueUStringVector(keys, L"FileVersion", s); + } + { + UString s; + PrintVersion(s, ProductVersionMS, ProductVersionLS); + AddToUniqueUStringVector(keys, L"ProductVersion", s); + } + + f.AddString("FILEFLAGSMASK "); + PrintHex(f, FlagsMask); + f.NewLine(); + + f.AddString("FILEFLAGS "); + { + bool wasPrinted = false; + for (unsigned i = 0; i < ARRAY_SIZE(k_VS_FileFlags); i++) + { + if ((Flags & ((UInt32)1 << i)) != 0) + { + if (wasPrinted) + f.AddString(" | "); + f.AddString("VS_FF_"); + f.AddString(k_VS_FileFlags[i]); + wasPrinted = true; + } + } + UInt32 v = Flags & ~(((UInt32)1 << ARRAY_SIZE(k_VS_FileFlags)) - 1); + if (v != 0 || !wasPrinted) + { + if (wasPrinted) + f.AddString(" | "); + PrintHex(f, v); + } + } + f.NewLine(); + + // OS = 0x111230; + f.AddString("FILEOS "); + unsigned i; + for (i = 0; i < ARRAY_SIZE(k_VS_FileOS); i++) + { + const CUInt32PCharPair &pair = k_VS_FileOS[i]; + if (OS == pair.Value) + { + // continue; + // f.AddString("VOS_"); + f.AddString(pair.Name); + break; } } - return (size == pos); + if (i == ARRAY_SIZE(k_VS_FileOS)) + { + UInt32 high = OS >> 16; + if (high < ARRAY_SIZE(k_VS_FileOS_High)) + f.AddString(k_VS_FileOS_High[high]); + else + PrintHex(f, high << 16); + UInt32 low = OS & 0xFFFF; + if (low != 0) + { + f.AddString(" | "); + if (low < ARRAY_SIZE(k_VS_FileOS_Low)) + f.AddString(k_VS_FileOS_Low[low]); + else + PrintHex(f, low); + } + } + f.NewLine(); + + f.AddString("FILETYPE "); + if (Type < ARRAY_SIZE(k_VS_FileType)) + f.AddString(k_VS_FileType[Type]); + else + PrintHex(f, Type); + f.NewLine(); + + f.AddString("FILESUBTYPE "); + bool needPrintSubType = true; + if (Type == kMY_VFT_DRV) + { + if (Subtype != 0 && Subtype < ARRAY_SIZE(k_VS_FileSubType_DRV)) + { + f.AddString("VFT2_DRV_"); + f.AddString(k_VS_FileSubType_DRV[Subtype]); + needPrintSubType = false; + } + } + else if (Type == kMY_VFT_FONT) + { + if (Subtype != 0 && Subtype < ARRAY_SIZE(k_VS_FileSubType_FONT)) + { + f.AddString(k_VS_FileSubType_FONT[Subtype]); + needPrintSubType = false; + } + } + if (needPrintSubType) + PrintHex(f, Subtype); + f.NewLine(); +} + +static void CopyToUString(const Byte *p, UString &s) +{ + for (;;) + { + wchar_t c = (wchar_t)Get16(p); + p += 2; + if (c == 0) + return; + s += c; + } } -HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpenCallback *callback) +static bool CompareWStrStrings(const Byte *p, const char *s) +{ + unsigned pos = 0; + for (;;) + { + Byte c = *s++; + if (Get16(p + pos) != c) + return false; + pos += 2; + if (c == 0) + return true; + } +} + +struct CVersionBlock +{ + UInt32 TotalLen; + UInt32 ValueLen; + bool IsTextValue; + int StrSize; + + bool Parse(const Byte *p, UInt32 size); +}; + +static int Get_Utf16Str_Len_InBytes(const Byte *p, size_t size) +{ + unsigned pos = 0; + for (;;) + { + if (pos + 1 >= size) + return -1; + if (Get16(p + pos) == 0) + return pos; + pos += 2; + } +} + +static const unsigned k_ResoureBlockHeader_Size = 6; + +bool CVersionBlock::Parse(const Byte *p, UInt32 size) +{ + if (size < k_ResoureBlockHeader_Size) + return false; + TotalLen = Get16(p); + ValueLen = Get16(p + 2); + if (TotalLen > size) + return false; + switch (Get16(p + 4)) + { + case 0: IsTextValue = false; break; + case 1: IsTextValue = true; break; + default: return false; + } + StrSize = Get_Utf16Str_Len_InBytes(p + k_ResoureBlockHeader_Size, TotalLen - k_ResoureBlockHeader_Size); + return StrSize >= 0; +} + +static void AddParamString(CTextFile &f, const Byte *p, size_t sLen) +{ + f.AddChar(' '); + f.AddChar('\"'); + f.AddBytes(p, sLen); + f.AddChar('\"'); +} + +static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector<CStringKeyValue> &keys) +{ + UInt32 pos; + { + const unsigned k_sizeof_VS_FIXEDFILEINFO = 13 * 4; + + CVersionBlock vb; + if (!vb.Parse(p, size)) + return false; + if (vb.ValueLen != k_sizeof_VS_FIXEDFILEINFO) // maybe 0 is allowed here? + return false; + if (vb.IsTextValue) + return false; + pos = k_ResoureBlockHeader_Size; + if (!CompareWStrStrings(p + pos, "VS_VERSION_INFO")) + return false; + pos += vb.StrSize + 2; + pos += (4 - pos) & 3; + if (pos + vb.ValueLen > vb.TotalLen) + return false; + /* sometimes resource contains zeros in remainder. + So we don't check that size != vb.TotalLen + // if (size != vb.TotalLen) return false; + */ + if (size > vb.TotalLen) + size = vb.TotalLen; + CMy_VS_FIXEDFILEINFO FixedFileInfo; + if (!FixedFileInfo.Parse(p + pos)) + return false; + FixedFileInfo.PrintToTextFile(f, keys); + pos += vb.ValueLen; + } + + f.OpenBlock(0); + + for (;;) + { + pos += (4 - pos) & 3; + if (pos >= size) + break; + + CVersionBlock vb; + if (!vb.Parse(p + pos, size - pos)) + return false; + if (vb.ValueLen != 0) + return false; + UInt32 endPos = pos + vb.TotalLen; + pos += k_ResoureBlockHeader_Size; + + f.AddSpaces(2); + f.AddString("BLOCK"); + AddParamString(f, p + pos, vb.StrSize); + + f.NewLine(); + f.OpenBlock(2); + + if (CompareWStrStrings(p + pos, "VarFileInfo")) + { + pos += vb.StrSize + 2; + for (;;) + { + pos += (4 - pos) & 3; + if (pos >= endPos) + break; + CVersionBlock vb2; + if (!vb2.Parse(p + pos, endPos - pos)) + return false; + UInt32 endPos2 = pos + vb2.TotalLen; + if (vb2.IsTextValue) + return false; + pos += k_ResoureBlockHeader_Size; + f.AddSpaces(4); + f.AddString("VALUE"); + AddParamString(f, p + pos, vb2.StrSize); + if (!CompareWStrStrings(p + pos, "Translation")) + return false; + pos += vb2.StrSize + 2; + pos += (4 - pos) & 3; + if (pos + vb2.ValueLen != endPos2) + return false; + if ((vb2.ValueLen & 3) != 0) + return false; + UInt32 num = (vb2.ValueLen >> 2); + for (; num != 0; num--, pos += 4) + { + UInt32 dw = Get32(p + pos); + UInt32 lang = LOWORD(dw); + UInt32 codePage = HIWORD(dw); + + f.AddString(", "); + PrintHex(f, lang); + f.AddString(", "); + PrintUInt32(f, codePage); + } + f.NewLine(); + } + } + else + { + if (!CompareWStrStrings(p + pos, "StringFileInfo")) + return false; + pos += vb.StrSize + 2; + + for (;;) + { + pos += (4 - pos) & 3; + if (pos >= endPos) + break; + CVersionBlock vb2; + if (!vb2.Parse(p + pos, endPos - pos)) + return false; + UInt32 endPos2 = pos + vb2.TotalLen; + if (vb2.ValueLen != 0) + return false; + pos += k_ResoureBlockHeader_Size; + + f.AddSpaces(4); + f.AddString("BLOCK"); + AddParamString(f, p + pos, vb2.StrSize); + pos += vb2.StrSize + 2; + + f.NewLine(); + f.OpenBlock(4); + + for (;;) + { + pos += (4 - pos) & 3; + if (pos >= endPos2) + break; + + CVersionBlock vb3; + if (!vb3.Parse(p + pos, endPos2 - pos)) + return false; + // ValueLen sometimes is a number of characters (not bytes)? + // So we don't use it. + UInt32 endPos3 = pos + vb3.TotalLen; + pos += k_ResoureBlockHeader_Size; + + // we don't write string if it's not text + if (vb3.IsTextValue) + { + f.AddSpaces(6); + f.AddString("VALUE"); + AddParamString(f, p + pos, vb3.StrSize); + UString key; + UString value; + CopyToUString(p + pos, key); + pos += vb3.StrSize + 2; + + pos += (4 - pos) & 3; + if (vb3.ValueLen > 0 && pos + 2 <= endPos3) + { + f.AddChar(','); + f.AddSpaces((34 - (int)vb3.StrSize) / 2); + int sLen = Get_Utf16Str_Len_InBytes(p + pos, endPos3 - pos); + if (sLen < 0) + return false; + AddParamString(f, p + pos, sLen); + CopyToUString(p + pos, value); + pos += sLen + 2; + } + AddToUniqueUStringVector(keys, key, value); + } + pos = endPos3; + f.NewLine(); + } + f.CloseBlock(4); + } + } + f.CloseBlock(2); + } + f.CloseBlock(0); + return true; +} + +HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchiveOpenCallback *callback) { const CSection § = _sections[sectionIndex]; size_t fileSize = sect.PSize; // Maybe we need sect.VSize here !!! @@ -1143,13 +1897,13 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe if (callback) RINOK(callback->SetTotal(NULL, &fileSize64)); RINOK(stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL)); - _buf.SetCapacity(fileSize); + _buf.Alloc(fileSize); for (size_t pos = 0; pos < fileSize;) { UInt64 offset64 = pos; if (callback) RINOK(callback->SetCompleted(NULL, &offset64)) - size_t rem = MyMin(fileSize - pos, (size_t)(1 << 20)); + size_t rem = MyMin(fileSize - pos, (size_t)(1 << 22)); RINOK(ReadStream_FALSE(stream, _buf + pos, rem)); pos += rem; } @@ -1162,7 +1916,7 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe _oneLang = true; bool stringsOk = true; size_t maxOffset = 0; - for (int i = 0; i < specItems.Size(); i++) + FOR_VECTOR (i, specItems) { const CTableItem &item1 = specItems[i]; if ((item1.Offset & kFlag) == 0) @@ -1171,7 +1925,7 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe CRecordVector<CTableItem> specItems2; RINOK(ReadTable(item1.Offset & kMask, specItems2)); - for (int j = 0; j < specItems2.Size(); j++) + FOR_VECTOR (j, specItems2) { const CTableItem &item2 = specItems2[j]; if ((item2.Offset & kFlag) == 0) @@ -1184,14 +1938,14 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe item.Type = item1.ID; item.ID = item2.ID; - for (int k = 0; k < specItems3.Size(); k++) + FOR_VECTOR (k, specItems3) { if (_items.Size() >= kNumResItemsMax) return S_FALSE; const CTableItem &item3 = specItems3[k]; if ((item3.Offset & kFlag) != 0) return S_FALSE; - if (item3.Offset >= _buf.GetCapacity() || _buf.GetCapacity() - item3.Offset < 16) + if (item3.Offset >= _buf.Size() || _buf.Size() - item3.Offset < 16) return S_FALSE; const Byte *buf = _buf + item3.Offset; item.Lang = item3.ID; @@ -1225,6 +1979,24 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe } } + if (item.IsVersion()) + { + if (offset > _buf.Size() || _buf.Size() - offset < item.Size) + continue; + CTextFile f; + if (ParseVersion((const Byte *)_buf + offset, item.Size, f, _versionKeys)) + { + CMixItem mixItem; + mixItem.VersionIndex = _versionFiles.Size(); + mixItem.SectionIndex = sectionIndex; // check it !!!! + CByteBuffer_WithLang &vf = _versionFiles.AddNew(); + vf.Lang = item.Lang; + vf.CopyFrom(f.Buf, f.Buf.GetPos()); + _mixItems.Add(mixItem); + continue; + } + // PrintError("ver.Parse error"); + } item.Enabled = true; _items.Add(item); } @@ -1233,7 +2005,7 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe if (stringsOk && !_strings.IsEmpty()) { - int i; + unsigned i; for (i = 0; i < _items.Size(); i++) { CResItem &item = _items[i]; @@ -1242,10 +2014,9 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe } for (i = 0; i < _strings.Size(); i++) { - if (_strings[i].Size == 0) + if (_strings[i].FinalSize() == 0) continue; CMixItem mixItem; - mixItem.ResourceIndex = -1; mixItem.StringIndex = i; mixItem.SectionIndex = sectionIndex; _mixItems.Add(mixItem); @@ -1259,7 +2030,8 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe { UInt32 mask = (1 << numBits) - 1; size_t end = ((maxOffset + mask) & ~mask); - if (end < sect.VSize && end <= sect.PSize) + // 9.29: we use only PSize. PSize can be larger than VSize + if (/* end < sect.VSize && */ end <= sect.PSize) { CSection sect2; sect2.Flags = 0; @@ -1274,72 +2046,158 @@ HRESULT CHandler::OpenResources(int sectionIndex, IInStream *stream, IArchiveOpe sect2.Pa = sect.Pa + (UInt32)maxOffset; sect2.Va = sect.Va + (UInt32)maxOffset; - sect2.PSize = sect.VSize - (UInt32)maxOffset; - sect2.VSize = sect2.PSize; - sect2.Name = ".rsrc_1"; - sect2.Time = 0; - sect2.IsAdditionalSection = true; - _sections.Add(sect2); + + // 9.29: we use sect.PSize instead of sect.VSize to support some CAB-SFX + // the code for .rsrc_2 is commented. + sect2.PSize = sect.PSize - (UInt32)maxOffset; + if (sect2.PSize != 0) + { + sect2.VSize = sect2.PSize; + sect2.Name = ".rsrc_1"; + sect2.Time = 0; + sect2.IsAdditionalSection = true; + _sections.Add(sect2); + } } } return S_OK; } -HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) +static inline bool CheckPeOffset(UInt32 pe) { - const UInt32 kBufSize = 1 << 18; - const UInt32 kSigSize = 2; + return (pe >= 0x40 && pe <= 0x1000 && (pe & 7) == 0); +} - _mainSubfile = -1; +static const unsigned kStartSize = 0x40; + +API_FUNC_static_IsArc IsArc_Pe(const Byte *p, size_t size) +{ + if (size < 2) + return k_IsArc_Res_NEED_MORE; + if (p[0] != 'M' || p[1] != 'Z') + return k_IsArc_Res_NO; + if (size < kStartSize) + return k_IsArc_Res_NEED_MORE; + UInt32 pe = Get32(p + 0x3C); + if (!CheckPeOffset(pe)) + return k_IsArc_Res_NO; + if (pe + kHeaderSize > size) + return k_IsArc_Res_NEED_MORE; + CHeader header; + if (!header.Parse(p + pe)) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} - CByteBuffer buffer; - buffer.SetCapacity(kBufSize); - Byte *buf = buffer; +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) +{ + { + Byte h[kStartSize]; + _mainSubfile = -1; + RINOK(ReadStream_FALSE(stream, h, kStartSize)); + if (h[0] != 'M' || h[1] != 'Z') + return S_FALSE; + /* most of PE files contain 0x0090 at offset 2. + But some rare PE files contain another values. So we don't use that check. + if (Get16(h + 2) != 0x90) return false; */ + _peOffset = Get32(h + 0x3C); + if (!CheckPeOffset(_peOffset)) + return S_FALSE; + } + { + Byte h[kHeaderSize]; + RINOK(stream->Seek(_peOffset, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, h, kHeaderSize)); + if (!_header.Parse(h)) + return S_FALSE; + } - size_t processed = kSigSize; - RINOK(ReadStream_FALSE(stream, buf, processed)); - if (buf[0] != 'M' || buf[1] != 'Z') - return S_FALSE; - processed = kBufSize - kSigSize; - RINOK(ReadStream(stream, buf + kSigSize, &processed)); - processed += kSigSize; - if (!Parse(buf, (UInt32)processed)) + UInt32 bufSize = _header.OptHeaderSize + (UInt32)_header.NumSections * kSectionSize; + _totalSize = _peOffset + kHeaderSize + bufSize; + CByteBuffer buffer(bufSize); + + RINOK(ReadStream_FALSE(stream, buffer, bufSize)); + if (!_optHeader.Parse(buffer, _header.OptHeaderSize)) return S_FALSE; + + UInt32 pos = _header.OptHeaderSize; + unsigned i; + for (i = 0; i < _header.NumSections; i++, pos += kSectionSize) + { + CSection § = _sections.AddNew(); + sect.Parse(buffer + pos); + sect.IsRealSect = true; + + /* PE pre-file in .hxs file has errors: + PSize of resource is larger tnan real size. + So it overlaps next ".its" section. + We correct it. */ + + if (i > 0) + { + CSection &prev = _sections[i - 1]; + if (prev.Pa < sect.Pa && + prev.Pa + prev.PSize > sect.Pa && + sect.PSize > 0) + { + // printf("\n !!!! Section correction: %s\n ", prev.Name); + // fflush(stdout); + prev.PSize = sect.Pa - prev.Pa; + } + } + /* last ".its" section in hxs file has incorrect sect.PSize. + So we reduce it to real sect.VSize */ + if (sect.VSize == 24 && sect.PSize == 512 && i == (unsigned)_header.NumSections - 1) + sect.PSize = sect.VSize; + } + + for (i = 0; i < _sections.Size(); i++) + _sections[i].UpdateTotalSize(_totalSize); + bool thereISDebug; RINOK(LoadDebugSections(stream, thereISDebug)); const CDirLink &certLink = _optHeader.DirItems[kDirLink_Certificate]; if (certLink.Size != 0) { - CSection sect; + CSection § = _sections.AddNew(); sect.Name = "CERTIFICATE"; sect.Va = 0; sect.Pa = certLink.Va; sect.PSize = sect.VSize = certLink.Size; sect.UpdateTotalSize(_totalSize); - _sections.Add(sect); } if (thereISDebug) { + /* sometime there is some data after debug section. + We don't see any reference in exe file to that data. + But we suppose that it's part of EXE file */ + const UInt32 kAlign = 1 << 12; UInt32 alignPos = _totalSize & (kAlign - 1); if (alignPos != 0) { UInt32 size = kAlign - alignPos; RINOK(stream->Seek(_totalSize, STREAM_SEEK_SET, NULL)); - buffer.Free(); - buffer.SetCapacity(kAlign); + buffer.Alloc(kAlign); Byte *buf = buffer; size_t processed = size; RINOK(ReadStream(stream, buf, &processed)); + + /* + if (processed != 0) + { + printf("\ndata after debug %d, %d \n", (int)size, (int)processed); + fflush(stdout); + } + */ + size_t i; for (i = 0; i < processed; i++) - { if (buf[i] != 0) break; - } if (processed < size && processed < 100) _totalSize += (UInt32)processed; else if (((_totalSize + i) & 0x1FF) == 0 || processed < size) @@ -1351,8 +2209,6 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) { if (_header.NumSymbols >= (1 << 24)) return S_FALSE; - CSection sect; - sect.Name = "COFF_SYMBOLS"; UInt32 size = _header.NumSymbols * 18; RINOK(stream->Seek((UInt64)_header.PointerToSymbolTable + size, STREAM_SEEK_SET, NULL)); Byte buf[4]; @@ -1362,38 +2218,31 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) return S_FALSE; size += size2; + CSection § = _sections.AddNew(); + sect.Name = "COFF_SYMBOLS"; sect.Va = 0; sect.Pa = _header.PointerToSymbolTable; sect.PSize = sect.VSize = size; sect.UpdateTotalSize(_totalSize); - _sections.Add(sect); } - UInt64 fileSize; - RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); - if (fileSize > _totalSize) - return S_FALSE; - _totalSizeLimited = (_totalSize < fileSize) ? _totalSize : (UInt32)fileSize; - { CObjectVector<CSection> sections = _sections; sections.Sort(); UInt32 limit = (1 << 12); - int num = 0; - int numSections = sections.Size(); - for (int i = 0; i < numSections; i++) + unsigned num = 0; + FOR_VECTOR(i, sections) { const CSection &s = sections[i]; if (s.Pa > limit) { - CSection s2; + CSection &s2 = _sections.AddNew(); s2.Pa = s2.Va = limit; s2.PSize = s2.VSize = s.Pa - limit; s2.IsAdditionalSection = true; s2.Name = '['; s2.Name += GetDecString(num++); s2.Name += ']'; - _sections.Add(s2); limit = s.Pa; } UInt32 next = s.Pa + s.PSize; @@ -1404,10 +2253,28 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) } } + + if (_optHeader.CheckSum != 0) + { + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + UInt32 checkSum = 0; + RINOK(CalcCheckSum(stream, _totalSize, _peOffset + kHeaderSize + k_CheckSum_Field_Offset, checkSum)); + _checksumError = (checkSum != _optHeader.CheckSum); + } + + + if (!_allowTail) + { + UInt64 fileSize; + RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); + if (fileSize > _totalSize) + return S_FALSE; + } + _parseResources = true; + // _parseResources = false; UInt64 mainSize = 0, mainSize2 = 0; - int i; for (i = 0; i < _sections.Size(); i++) { const CSection § = _sections[i]; @@ -1418,14 +2285,14 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) HRESULT res = OpenResources(i, stream, callback); if (res == S_OK) { - _resourceFileName = GetUnicodeString(sect.Name); - for (int j = 0; j < _items.Size(); j++) + _resourcesPrefix.SetFromAscii(sect.Name); + _resourcesPrefix += WCHAR_PATH_SEPARATOR; + FOR_VECTOR (j, _items) { const CResItem &item = _items[j]; if (item.Enabled) { mixItem.ResourceIndex = j; - mixItem.StringIndex = -1; if (item.IsRcDataOrUnknown()) { if (item.Size >= mainSize) @@ -1440,6 +2307,9 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) _mixItems.Add(mixItem); } } + // 9.29: .rsrc_2 code was commented. + // .rsrc_1 now must include that .rsrc_2 block. + /* if (sect.PSize > sect.VSize) { int numBits = _optHeader.GetNumFileAlignBits(); @@ -1450,7 +2320,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) if (sect.PSize > end) { - CSection sect2; + CSection §2 = _sections.AddNew(); sect2.Flags = 0; sect2.Pa = sect.Pa + end; sect2.Va = sect.Va + end; @@ -1459,18 +2329,16 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) sect2.Name = ".rsrc_2"; sect2.Time = 0; sect2.IsAdditionalSection = true; - _sections.Add(sect2); } } } + */ continue; } if (res != S_FALSE) return res; CloseResources(); } - mixItem.StringIndex = -1; - mixItem.ResourceIndex = -1; if (sect.IsAdditionalSection) { if (sect.PSize >= mainSize) @@ -1498,55 +2366,35 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) } } - return S_OK; -} - -HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 excludePos, UInt32 &res) -{ - // size &= ~1; - const UInt32 kBufSize = 1 << 23; - CByteBuffer buffer; - buffer.SetCapacity(kBufSize); - Byte *buf = buffer; - - UInt32 sum = 0; - UInt32 pos = 0; - for (;;) + for (i = 0; i < _versionKeys.Size(); i++) { - UInt32 rem = size - pos; - if (rem > kBufSize) - rem = kBufSize; - if (rem == 0) - break; - size_t processed = rem; - RINOK(ReadStream(stream, buf, &processed)); - - /* - for (; processed < rem; processed++) - buf[processed] = 0; - */ - - if ((processed & 1) != 0) - buf[processed] = 0; - - for (int j = 0; j < 4; j++) - { - UInt32 p = excludePos + j; - if (pos <= p && p < pos + processed) - buf[p - pos] = 0; - } + if (i != 0) + _versionFullString += L'\n'; + const CStringKeyValue &k = _versionKeys[i]; + _versionFullString += k.Key; + _versionFullString += L": "; + _versionFullString += k.Value; + } - for (size_t i = 0; i < processed; i += 2) + { + int keyIndex = FindKey(_versionKeys, L"OriginalFilename"); + if (keyIndex >= 0) + _originalFilename = _versionKeys[keyIndex].Value; + } + { + int keyIndex = FindKey(_versionKeys, L"FileDescription"); + if (keyIndex >= 0) + _versionShortString = _versionKeys[keyIndex].Value; + } + { + int keyIndex = FindKey(_versionKeys, L"FileVersion"); + if (keyIndex >= 0) { - sum += Get16(buf + i); - sum = (sum + (sum >> 16)) & 0xFFFF; + _versionShortString += L' '; + _versionShortString += _versionKeys[keyIndex].Value; } - pos += (UInt32)processed; - if (rem != processed) - break; } - sum += pos; - res = sum; + return S_OK; } @@ -1565,11 +2413,18 @@ void CHandler::CloseResources() _usedRes.Free(); _items.Clear(); _strings.Clear(); - _buf.SetCapacity(0); + _versionFiles.Clear(); + _buf.Free(); + _versionFullString.Empty(); + _versionShortString.Empty(); + _originalFilename.Empty(); + _versionKeys.Clear(); } STDMETHODIMP CHandler::Close() { + _totalSize = 0; + _checksumError = false; _stream.Release(); _sections.Clear(); _mixItems.Clear(); @@ -1587,7 +2442,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _mixItems.Size(); if (numItems == 0) @@ -1597,12 +2452,16 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, for (i = 0; i < numItems; i++) { const CMixItem &mixItem = _mixItems[allFilesMode ? i : indices[i]]; + UInt64 size; if (mixItem.StringIndex >= 0) - totalSize += _strings[mixItem.StringIndex].Size; - else if (mixItem.ResourceIndex < 0) - totalSize += _sections[mixItem.SectionIndex].GetPackSize(); + size = _strings[mixItem.StringIndex].FinalSize(); + else if (mixItem.VersionIndex >= 0) + size = _versionFiles[mixItem.VersionIndex].Size(); + else if (mixItem.ResourceIndex >= 0) + size = _items[mixItem.ResourceIndex].GetSize(); else - totalSize += _items[mixItem.ResourceIndex].GetSize(); + size = _sections[mixItem.SectionIndex].PSize; + totalSize += size; } extractCallback->SetTotal(totalSize); @@ -1616,15 +2475,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); - bool checkSumOK = true; - if (_optHeader.CheckSum != 0 && (int)numItems == _mixItems.Size()) - { - UInt32 checkSum = 0; - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - CalcCheckSum(_stream, _totalSizeLimited, _peOffset + kHeaderSize + 64, checkSum); - checkSumOK = (checkSum == _optHeader.CheckSum); - } - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr<ISequentialInStream> inStream(streamSpec); streamSpec->SetStream(_stream); @@ -1647,27 +2497,26 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (mixItem.StringIndex >= 0) { const CStringItem &item = _strings[mixItem.StringIndex]; - currentItemSize = item.Size; + currentItemSize = item.FinalSize(); if (!testMode && !outStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); if (outStream) - RINOK(WriteStream(outStream, item.Buf, item.Size)); + RINOK(WriteStream(outStream, item.Buf, item.FinalSize())); } - else if (mixItem.ResourceIndex < 0) + else if (mixItem.VersionIndex >= 0) { - currentItemSize = sect.GetPackSize(); + const CByteBuffer &item = _versionFiles[mixItem.VersionIndex]; + currentItemSize = item.Size(); if (!testMode && !outStream) continue; - + RINOK(extractCallback->PrepareOperation(askMode)); - RINOK(_stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL)); - streamSpec->Init(currentItemSize); - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); - isOk = (copyCoderSpec->TotalSize == currentItemSize); + if (outStream) + RINOK(WriteStream(outStream, item, item.Size())); } - else + else if (mixItem.ResourceIndex >= 0) { const CResItem &item = _items[mixItem.ResourceIndex]; currentItemSize = item.GetSize(); @@ -1685,12 +2534,22 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(WriteStream(outStream, _buf + offset, item.Size)); } } + else + { + currentItemSize = sect.PSize; + if (!testMode && !outStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(_stream->Seek(sect.Pa, STREAM_SEEK_SET, NULL)); + streamSpec->Init(currentItemSize); + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + isOk = (copyCoderSpec->TotalSize == currentItemSize); + } outStream.Release(); RINOK(extractCallback->SetOperationResult(isOk ? - checkSumOK ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kCRCError: + NExtract::NOperationResult::kOK : NExtract::NOperationResult::kDataError)); } return S_OK; @@ -1714,8 +2573,12 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) if (mixItem.StringIndex >= 0) { const CStringItem &item = _strings[mixItem.StringIndex]; - referenceBuf->Buf.SetCapacity(item.Size); - memcpy(referenceBuf->Buf, item.Buf, item.Size); + referenceBuf->Buf.CopyFrom(item.Buf, item.FinalSize()); + } + else if (mixItem.VersionIndex >= 0) + { + const CByteBuffer &item = _versionFiles[mixItem.VersionIndex]; + referenceBuf->Buf.CopyFrom(item, item.Size()); } else { @@ -1731,7 +2594,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) *stream = streamTemp2.Detach(); return S_OK; } - referenceBuf->Buf.SetCapacity(item.HeaderSize + item.Size); + referenceBuf->Buf.Alloc(item.HeaderSize + item.Size); memcpy(referenceBuf->Buf, item.Header, item.HeaderSize); memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size); } @@ -1742,10 +2605,20 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +STDMETHODIMP CHandler::AllowTail(Int32 allowTail) +{ + _allowTail = IntToBool(allowTail); + return S_OK; +} + +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"PE", L"exe dll sys", 0, 0xDD, { 'P', 'E', 0, 0 }, 4, false, CreateArc, 0 }; + { "PE", "exe dll sys", 0, 0xDD, + 2, { 'M', 'Z' }, + 0, + NArcInfoFlags::kPreArc, + CreateArc, NULL, IsArc_Pe }; REGISTER_ARC(Pe) @@ -1758,13 +2631,17 @@ namespace NTe { // Terse Executable (TE) image -/* struct CDataDir { UInt32 Va; UInt32 Size; + + void Parse(const Byte *p) + { + G32(0, Va); + G32(4, Size); + } }; -*/ static const UInt32 kHeaderSize = 40; @@ -1776,8 +2653,10 @@ static bool FindValue(const CUInt32PCharPair *pairs, unsigned num, UInt32 value) return false; } -#define MY_FIND_VALUE(pairs, value) FindValue(pairs, sizeof(pairs) / sizeof(pairs[0]), value) +#define MY_FIND_VALUE(pairs, value) FindValue(pairs, ARRAY_SIZE(pairs), value) +static const UInt32 kNumSection_MAX = 32; + struct CHeader { UInt16 Machine; @@ -1788,41 +2667,65 @@ struct CHeader UInt32 AddressOfEntryPoint; UInt32 BaseOfCode; UInt64 ImageBase; - CDataDir DataDir[2]; // base relocation and debug directory */ + CDataDir DataDir[2]; // base relocation and debug directory - UInt32 ConvertPa(UInt32 pa) const { return pa - StrippedSize + kHeaderSize; } + bool ConvertPa(UInt32 &pa) const + { + if (pa < StrippedSize) + return false; + pa = pa - StrippedSize + kHeaderSize; + return true; + } + bool Parse(const Byte *p); +}; - bool Parse(const Byte *p) +bool CHeader::Parse(const Byte *p) +{ + NumSections = p[4]; + if (NumSections > kNumSection_MAX) + return false; + SubSystem = p[5]; + G16(2, Machine); + G16(6, StrippedSize); + /* + G32(8, AddressOfEntryPoint); + G32(12, BaseOfCode); + G64(16, ImageBase); + */ + for (int i = 0; i < 2; i++) { - if (p[0] != 'V' || p[1] != 'Z') + CDataDir &dd = DataDir[i]; + dd.Parse(p + 24 + i * 8); + if (dd.Size >= ((UInt32)1 << 28)) return false; - Machine = Get16(p + 2); - NumSections = p[4]; - SubSystem = p[5]; - StrippedSize = Get16(p + 6); - /* - AddressOfEntryPoint = Get32(p + 8); - BaseOfCode = Get32(p + 12); - ImageBase = Get64(p + 16); - for (int i = 0; i < 2; i++) - { - const Byte *p2 = p + 24 + i * 8; - DataDir[i].Va = Get32(p2); - DataDir[i].Size = Get32(p2 + 4); - } - */ - return NumSections <= 64 && + } + return MY_FIND_VALUE(NPe::g_MachinePairs, Machine) && MY_FIND_VALUE(NPe::g_SubSystems, SubSystem); - } -}; +} + +API_FUNC_static_IsArc IsArc_Te(const Byte *p, size_t size) +{ + if (size < 2) + return k_IsArc_Res_NEED_MORE; + if (p[0] != 'V' || p[1] != 'Z') + return k_IsArc_Res_NO; + if (size < kHeaderSize) + return k_IsArc_Res_NEED_MORE; + + CHeader h; + if (!h.Parse(p)) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} + struct CSection { - Byte Name[8]; + Byte Name[NPe::kNameSize]; - // UInt32 VSize; + UInt32 VSize; UInt32 Va; UInt32 PSize; UInt32 Pa; @@ -1831,16 +2734,21 @@ struct CSection void Parse(const Byte *p) { - memcpy(Name, p, 8); - // VSize = Get32(p + 8); - Va = Get32(p + 12); - PSize = Get32(p + 16); - Pa = Get32(p + 20); - // NumRelocs = Get16(p + 32); - Flags = Get32(p + 36); + memcpy(Name, p, NPe::kNameSize); + G32(8, VSize); + G32(12, Va); + G32(16, PSize); + G32(20, Pa); + // G32(p + 32, NumRelocs); + G32(36, Flags); } - bool Check() const { return (PSize + Pa > Pa); } + bool Check() const + { + return + Pa <= ((UInt32)1 << 30) && + PSize <= ((UInt32)1 << 30); + } void UpdateTotalSize(UInt32 &totalSize) { @@ -1853,44 +2761,46 @@ struct CSection class CHandler: public IInArchive, public IInArchiveGetStream, + public IArchiveAllowTail, public CMyUnknownImp { - UInt32 _totalSize; + CRecordVector<CSection> _items; CMyComPtr<IInStream> _stream; - CObjectVector<CSection> _items; + UInt32 _totalSize; + bool _allowTail; CHeader _h; - UInt64 _fileSize; HRESULT Open2(IInStream *stream); public: - MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IArchiveAllowTail) INTERFACE_IInArchive(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(AllowTail)(Int32 allowTail); + CHandler(): _allowTail(false) {} }; -static const STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI4}, - { NULL, kpidPackSize, VT_UI4}, - { NULL, kpidCharacts, VT_BSTR}, - { NULL, kpidOffset, VT_UI4}, - { NULL, kpidVa, VT_UI8} + kpidPath, + kpidSize, + kpidVirtualSize, + kpidCharacts, + kpidOffset, + kpidVa }; enum { - kpidSubSystem + kpidSubSystem = kpidUserDefined, // , kpidImageBase }; static const STATPROPSTG kArcProps[] = { - { NULL, kpidPhySize, VT_UI4}, - // { NULL, kpidHeadersSize, VT_UI4}, + // { NULL, kpidHeadersSize, VT_UI4 }, { NULL, kpidCpu, VT_BSTR}, - { L"Subsystem", kpidSubSystem, VT_BSTR}, - // { L"Image Base", kpidImageBase, VT_UI8} + { L"Subsystem", kpidSubSystem, VT_BSTR }, + // { L"Image Base", kpidImageBase, VT_UI8 } }; IMP_IInArchive_Props @@ -1900,7 +2810,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidPhySize: prop = _totalSize; break; case kpidCpu: PAIR_TO_PROP(NPe::g_MachinePairs, _h.Machine, prop); break; @@ -1922,11 +2832,12 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val NCOM::CPropVariant prop; { const CSection &item = _items[index]; - switch(propID) + switch (propID) { - case kpidPath: StringToProp(NPe::GetName(item.Name), prop); break; + case kpidPath: prop = MultiByteToUnicodeString(NPe::GetName(item.Name)); break; case kpidSize: case kpidPackSize: prop = (UInt64)item.PSize; break; + case kpidVirtualSize: prop = (UInt64)item.VSize; break; case kpidOffset: prop = item.Pa; break; case kpidVa: prop = item.Va; break; case kpidCharacts: FLAGS_TO_PROP(NPe::g_SectFlags, item.Flags, prop); break; @@ -1941,28 +2852,41 @@ HRESULT CHandler::Open2(IInStream *stream) { Byte h[kHeaderSize]; RINOK(ReadStream_FALSE(stream, h, kHeaderSize)); + if (h[0] != 'V' || h[1] != 'Z') + return S_FALSE; if (!_h.Parse(h)) return S_FALSE; - CByteBuffer buf; - UInt32 headerSize = NPe::kSectionSize * _h.NumSections; - buf.SetCapacity(headerSize); + UInt32 headerSize = NPe::kSectionSize * (UInt32)_h.NumSections; + CByteArr buf(headerSize); RINOK(ReadStream_FALSE(stream, buf, headerSize)); + headerSize += kHeaderSize; - _totalSize = kHeaderSize + headerSize; - - for (UInt32 i = 0; i < headerSize; i += NPe::kSectionSize) + _totalSize = headerSize; + _items.ClearAndReserve(_h.NumSections); + for (UInt32 i = 0; i < _h.NumSections; i++) { CSection sect; - sect.Parse(buf + i); - sect.Pa = _h.ConvertPa(sect.Pa); - _items.Add(sect); - sect.UpdateTotalSize(_totalSize); + sect.Parse(buf + i * NPe::kSectionSize); + if (!_h.ConvertPa(sect.Pa)) + return S_FALSE; + if (sect.Pa < headerSize) + return S_FALSE; if (!sect.Check()) return S_FALSE; + _items.AddInReserved(sect); + sect.UpdateTotalSize(_totalSize); } - return stream->Seek(0, STREAM_SEEK_END, &_fileSize); + if (!_allowTail) + { + UInt64 fileSize; + RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); + if (fileSize > _totalSize) + return S_FALSE; + } + + return S_OK; } STDMETHODIMP CHandler::Open(IInStream *inStream, @@ -1984,9 +2908,9 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, STDMETHODIMP CHandler::Close() { + _totalSize = 0; _stream.Release(); _items.Clear(); - _totalSize = 0; return S_OK; } @@ -2000,7 +2924,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (numItems == 0) @@ -2041,22 +2965,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; RINOK(extractCallback->PrepareOperation(askMode)); int res = NExtract::NOperationResult::kDataError; - if (item.Pa <= _fileSize) - { - if (testMode) - { - if (item.Pa + item.PSize <= _fileSize) - res = NExtract::NOperationResult::kOK; - } - else - { - RINOK(_stream->Seek(item.Pa, STREAM_SEEK_SET, NULL)); - streamSpec->Init(item.PSize); - RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); - if (copyCoderSpec->TotalSize == item.PSize) - res = NExtract::NOperationResult::kOK; - } - } + + RINOK(_stream->Seek(item.Pa, STREAM_SEEK_SET, NULL)); + streamSpec->Init(item.PSize); + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize == item.PSize) + res = NExtract::NOperationResult::kOK; + realOutStream.Release(); RINOK(extractCallback->SetOperationResult(res)); } @@ -2072,10 +2987,20 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +STDMETHODIMP CHandler::AllowTail(Int32 allowTail) +{ + _allowTail = IntToBool(allowTail); + return S_OK; +} + +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"TE", L"te", 0, 0xCF, { 'V', 'Z' }, 2, false, CreateArc, 0 }; + { "TE", "te", 0, 0xCF, + 2, { 'V', 'Z' }, + 0, + NArcInfoFlags::kPreArc, + CreateArc, NULL, IsArc_Te }; REGISTER_ARC(TE) diff --git a/CPP/7zip/Archive/PpmdHandler.cpp b/CPP/7zip/Archive/PpmdHandler.cpp index 9b2ef048..70e9ffac 100755..100644 --- a/CPP/7zip/Archive/PpmdHandler.cpp +++ b/CPP/7zip/Archive/PpmdHandler.cpp @@ -11,12 +11,12 @@ This code is based on: #include "../../../C/Ppmd7.h" #include "../../../C/Ppmd8.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/StringConvert.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/StringConvert.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" #include "../Common/CWrappers.h" #include "../Common/ProgressUtils.h" @@ -75,11 +75,12 @@ HRESULT CItem::ReadHeader(ISequentialInStream *s, UInt32 &headerSize) return S_FALSE; Attrib = GetUi32(h + 4); Time = GetUi32(h + 12); - unsigned info = GetUi16(h + 8); Order = (info & 0xF) + 1; MemInMB = ((info >> 4) & 0xFF) + 1; Ver = info >> 12; + + if (Ver < 6 || Ver > 11) return S_FALSE; UInt32 nameLen = GetUi16(h + 10); Restor = nameLen >> 14; @@ -104,8 +105,8 @@ class CHandler: { CItem _item; UInt32 _headerSize; + bool _packSize_Defined; UInt64 _packSize; - bool _packSizeDefined; CMyComPtr<ISequentialInStream> _stream; public: @@ -114,12 +115,12 @@ public: STDMETHOD(OpenSeq)(ISequentialInStream *stream); }; -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidAttrib, VT_UI4}, - { NULL, kpidMethod, VT_BSTR} + kpidPath, + kpidMTime, + kpidAttrib, + kpidMethod }; IMP_IInArchive_Props @@ -128,9 +129,9 @@ IMP_IInArchive_ArcProps_NO_Table STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; - switch(propID) + switch (propID) { - case kpidPhySize: if (_packSizeDefined) prop = _packSize; break; + case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; } prop.Detach(value); return S_OK; @@ -151,22 +152,23 @@ static void UIntToString(AString &s, const char *prefix, unsigned value) s += temp; } -STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) + NCOM::CPropVariant prop; + switch (propID) { case kpidPath: prop = MultiByteToUnicodeString(_item.Name, CP_ACP); break; case kpidMTime: { + // time can be in Unix format ??? FILETIME utc; if (NTime::DosTimeToFileTime(_item.Time, utc)) prop = utc; break; } case kpidAttrib: prop = _item.Attrib; break; - case kpidPackSize: if (_packSizeDefined) prop = _packSize; break; + case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; case kpidMethod: { AString s = "PPMd"; @@ -209,7 +211,8 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) STDMETHODIMP CHandler::Close() { - _packSizeDefined = false; + _packSize = 0; + _packSize_Defined = false; _stream.Release(); return S_OK; } @@ -356,7 +359,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { if (numItems == 0) return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; // extractCallback->SetTotal(_packSize); @@ -388,7 +391,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CPpmdCpp ppmd(_item.Ver); if (!ppmd.Alloc(_item.MemInMB)) return E_OUTOFMEMORY; - Int32 opRes = NExtract::NOperationResult::kUnSupportedMethod; + Int32 opRes = NExtract::NOperationResult::kUnsupportedMethod; if (_item.IsSupported()) { opRes = NExtract::NOperationResult::kDataError; @@ -428,7 +431,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, outSize += i; _packSize = _headerSize + inBuf.GetProcessed(); - _packSizeDefined = true; + _packSize_Defined = true; if (realOutStream) { RINOK(WriteStream(realOutStream, outBuf.Buf, i)); @@ -446,10 +449,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, return extractCallback->SetOperationResult(opRes); } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"Ppmd", L"pmd", 0, 0xD, { 0x8F, 0xAF, 0xAC, 0x84 }, 4, false, CreateArc, 0 }; + { "Ppmd", "pmd", 0, 0xD, + 4, { 0x8F, 0xAF, 0xAC, 0x84 }, + 0, + 0, + CreateArc }; REGISTER_ARC(Ppmd) diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp index 5d072d34..c4adee41 100755..100644 --- a/CPP/7zip/Archive/Rar/RarHandler.cpp +++ b/CPP/7zip/Archive/Rar/RarHandler.cpp @@ -2,50 +2,104 @@ #include "StdAfx.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/StringConvert.h" +#include "../../../../C/CpuArch.h" -#include "Windows/PropVariant.h" -#include "Windows/PropVariantUtils.h" -#include "Windows/Time.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/UTFConvert.h" + +#include "../../../Windows/PropVariantUtils.h" +#include "../../../Windows/TimeUtils.h" #include "../../IPassword.h" #include "../../Common/CreateCoder.h" #include "../../Common/FilterCoder.h" +#include "../../Common/LimitedStreams.h" #include "../../Common/MethodId.h" #include "../../Common/ProgressUtils.h" +#include "../../Common/RegisterArc.h" +#include "../../Common/StreamUtils.h" #include "../../Compress/CopyCoder.h" #include "../../Crypto/Rar20Crypto.h" #include "../../Crypto/RarAes.h" +#include "../Common/FindSignature.h" #include "../Common/ItemNameUtils.h" #include "../Common/OutStreamWithCRC.h" #include "RarHandler.h" using namespace NWindows; -using namespace NTime; + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) namespace NArchive { namespace NRar { -static const wchar_t *kHostOS[] = +#define SIGNATURE { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 } + +static const Byte kMarker[NHeader::kMarkerSize] = SIGNATURE; + +bool CItem::IgnoreItem() const { - L"MS DOS", - L"OS/2", - L"Win32", - L"Unix", - L"Mac OS", - L"BeOS" -}; + switch (HostOS) + { + case NHeader::NFile::kHostMSDOS: + case NHeader::NFile::kHostOS2: + case NHeader::NFile::kHostWin32: + return ((Attrib & NHeader::NFile::kLabelFileAttribute) != 0); + } + return false; +} + +bool CItem::IsDir() const +{ + if (GetDictSize() == NHeader::NFile::kDictDirectoryValue) + return true; + switch (HostOS) + { + case NHeader::NFile::kHostMSDOS: + case NHeader::NFile::kHostOS2: + case NHeader::NFile::kHostWin32: + if ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) + return true; + } + return false; +} -static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]); +UInt32 CItem::GetWinAttrib() const +{ + UInt32 a; + switch (HostOS) + { + case NHeader::NFile::kHostMSDOS: + case NHeader::NFile::kHostOS2: + case NHeader::NFile::kHostWin32: + a = Attrib; + break; + default: + a = 0; // must be converted from unix value; + } + if (IsDir()) + a |= NHeader::NFile::kWinFileDirectoryAttributeMask; + return a; +} + +static const char *kHostOS[] = +{ + "MS DOS" + , "OS/2" + , "Win32" + , "Unix" + , "Mac OS" + , "BeOS" +}; -static const wchar_t *kUnknownOS = L"Unknown"; +static const char *kUnknownOS = "Unknown"; static const CUInt32PCharPair k_Flags[] = { @@ -61,75 +115,771 @@ static const CUInt32PCharPair k_Flags[] = { 9, "EncryptVer" } }; -static const STATPROPSTG kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidATime, VT_FILETIME}, - { NULL, kpidAttrib, VT_UI4}, - - { NULL, kpidEncrypted, VT_BOOL}, - { NULL, kpidSolid, VT_BOOL}, - { NULL, kpidCommented, VT_BOOL}, - { NULL, kpidSplitBefore, VT_BOOL}, - { NULL, kpidSplitAfter, VT_BOOL}, - { NULL, kpidCRC, VT_UI4}, - { NULL, kpidHostOS, VT_BSTR}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidUnpackVer, VT_UI1} +enum EErrorType +{ + k_ErrorType_OK, + k_ErrorType_Corrupted, + k_ErrorType_UnexpectedEnd, + k_ErrorType_DecryptionError }; -static const STATPROPSTG kArcProps[] = +class CInArchive { - { NULL, kpidCharacts, VT_BSTR}, - { NULL, kpidSolid, VT_BOOL}, - { NULL, kpidNumBlocks, VT_UI4}, - // { NULL, kpidEncrypted, VT_BOOL}, - { NULL, kpidIsVolume, VT_BOOL}, - { NULL, kpidNumVolumes, VT_UI4}, - { NULL, kpidPhySize, VT_UI8} - // { NULL, kpidCommented, VT_BOOL} + IInStream *m_Stream; + UInt64 m_StreamStartPosition; + CBuffer<wchar_t> _unicodeNameBuffer; + CByteBuffer _comment; + CByteBuffer m_FileHeaderData; + NHeader::NBlock::CBlock m_BlockHeader; + NCrypto::NRar29::CDecoder *m_RarAESSpec; + CMyComPtr<ICompressFilter> m_RarAES; + CBuffer<Byte> m_DecryptedData; + Byte *m_DecryptedDataAligned; + UInt32 m_DecryptedDataSize; + bool m_CryptoMode; + UInt32 m_CryptoPos; + + + HRESULT ReadBytesSpec(void *data, size_t *size); + bool ReadBytesAndTestSize(void *data, UInt32 size); + void ReadName(const Byte *p, unsigned nameSize, CItem &item); + bool ReadHeaderReal(const Byte *p, unsigned size, CItem &item); + + HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit); + + void AddToSeekValue(UInt64 addValue) + { + m_Position += addValue; + } + + void FinishCryptoBlock() + { + if (m_CryptoMode) + while ((m_CryptoPos & 0xF) != 0) + { + m_CryptoPos++; + m_Position++; + } + } + +public: + UInt64 m_Position; + CInArcInfo ArcInfo; + bool HeaderErrorWarning; + + HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit); + HRESULT GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPassword, + bool &filled, EErrorType &error); +}; + +static bool CheckHeaderCrc(const Byte *header, size_t headerSize) +{ + return Get16(header) == (UInt16)(CrcCalc(header + 2, headerSize - 2) & 0xFFFF); +} + +HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) +{ + HeaderErrorWarning = false; + m_CryptoMode = false; + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition)); + RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileSize)); + RINOK(stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL)); + m_Position = m_StreamStartPosition; + + UInt64 arcStartPos = m_StreamStartPosition; + { + Byte marker[NHeader::kMarkerSize]; + RINOK(ReadStream_FALSE(stream, marker, NHeader::kMarkerSize)); + if (memcmp(marker, kMarker, NHeader::kMarkerSize) == 0) + m_Position += NHeader::kMarkerSize; + else + { + if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) + return S_FALSE; + RINOK(stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL)); + RINOK(FindSignatureInStream(stream, kMarker, NHeader::kMarkerSize, + searchHeaderSizeLimit, arcStartPos)); + m_Position = arcStartPos + NHeader::kMarkerSize; + RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); + } + } + Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1]; + + RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize)); + AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize); + + + UInt32 blockSize = Get16(buf + 5); + + ArcInfo.EncryptVersion = 0; + ArcInfo.Flags = Get16(buf + 3); + + UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize; + if (ArcInfo.IsThereEncryptVer()) + { + if (blockSize <= headerSize) + return S_FALSE; + RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1)); + AddToSeekValue(1); + ArcInfo.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize]; + headerSize += 1; + } + if (blockSize < headerSize + || buf[2] != NHeader::NBlockType::kArchiveHeader + || !CheckHeaderCrc(buf, headerSize)) + return S_FALSE; + + size_t commentSize = blockSize - headerSize; + _comment.Alloc(commentSize); + RINOK(ReadStream_FALSE(stream, _comment, commentSize)); + AddToSeekValue(commentSize); + m_Stream = stream; + ArcInfo.StartPos = arcStartPos; + return S_OK; +} + +HRESULT CInArchive::ReadBytesSpec(void *data, size_t *resSize) +{ + if (m_CryptoMode) + { + size_t size = *resSize; + *resSize = 0; + const Byte *bufData = m_DecryptedDataAligned; + UInt32 bufSize = m_DecryptedDataSize; + size_t i; + for (i = 0; i < size && m_CryptoPos < bufSize; i++) + ((Byte *)data)[i] = bufData[m_CryptoPos++]; + *resSize = i; + return S_OK; + } + return ReadStream(m_Stream, data, resSize); +} + +bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size) +{ + size_t processed = size; + if (ReadBytesSpec(data, &processed) != S_OK) + return false; + return processed == size; +} + +static void 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++]; + while (encPos < encSize && decPos < maxDecSize) + { + if (flagBits == 0) + { + flags = encName[encPos++]; + flagBits = 8; + } + switch (flags >> 6) + { + 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; + } + flags <<= 2; + flagBits -= 2; + } + unicodeName[decPos < maxDecSize ? decPos : maxDecSize - 1] = 0; +} + +void CInArchive::ReadName(const Byte *p, unsigned nameSize, CItem &item) +{ + item.UnicodeName.Empty(); + if (nameSize > 0) + { + unsigned i; + for (i = 0; i < nameSize && p[i] != 0; i++); + item.Name.SetFrom((const char *)p, i); + + if (item.HasUnicodeName()) + { + if (i < nameSize) + { + i++; + unsigned uNameSizeMax = MyMin(nameSize, (unsigned)0x400); + _unicodeNameBuffer.AllocAtLeast(uNameSizeMax + 1); + DecodeUnicodeFileName(p, p + i, nameSize - i, _unicodeNameBuffer, uNameSizeMax); + item.UnicodeName = _unicodeNameBuffer; + } + else if (!ConvertUTF8ToUnicode(item.Name, item.UnicodeName)) + item.UnicodeName.Empty(); + } + } + else + item.Name.Empty(); +} + +static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime) +{ + rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0); + unsigned numDigits = (mask & 3); + rarTime.SubTime[0] = + rarTime.SubTime[1] = + rarTime.SubTime[2] = 0; + if (numDigits > size) + return -1; + for (unsigned i = 0; i < numDigits; i++) + rarTime.SubTime[3 - numDigits + i] = p[i]; + return numDigits; +} + +#define READ_TIME(_mask_, _ttt_) \ + { int size2 = ReadTime(p, size, _mask_, _ttt_); if (size2 < 0) return false; p += size2, size -= size2; } + +#define READ_TIME_2(_mask_, _def_, _ttt_) \ + _def_ = ((_mask_ & 8) != 0); if (_def_) \ + { if (size < 4) return false; \ + _ttt_ ## .DosTime = Get32(p); p += 4; size -= 4; \ + READ_TIME(_mask_, _ttt_); } \ + +bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item) +{ + const Byte *pStart = p; + + item.Clear(); + item.Flags = m_BlockHeader.Flags; + + const unsigned kFileHeaderSize = 25; + + if (size < kFileHeaderSize) + return false; + + item.PackSize = Get32(p); + item.Size = Get32(p + 4); + item.HostOS = p[8]; + item.FileCRC = Get32(p + 9); + item.MTime.DosTime = Get32(p + 13); + item.UnPackVersion = p[17]; + item.Method = p[18]; + unsigned nameSize = Get16(p + 19); + item.Attrib = Get32(p + 21); + + item.MTime.LowSecond = 0; + item.MTime.SubTime[0] = + item.MTime.SubTime[1] = + item.MTime.SubTime[2] = 0; + + p += kFileHeaderSize; + size -= kFileHeaderSize; + if ((item.Flags & NHeader::NFile::kSize64Bits) != 0) + { + if (size < 8) + return false; + item.PackSize |= ((UInt64)Get32(p) << 32); + item.Size |= ((UInt64)Get32(p + 4) << 32); + p += 8; + size -= 8; + } + if (nameSize > size) + return false; + ReadName(p, nameSize, item); + p += nameSize; + size -= nameSize; + + /* + // It was commented, since it's difficult to support alt Streams for solid archives. + if (m_BlockHeader.Type == NHeader::NBlockType::kSubBlock) + { + if (item.HasSalt()) + { + if (size < sizeof(item.Salt)) + return false; + size -= sizeof(item.Salt); + p += sizeof(item.Salt); + } + if (item.Name == "ACL" && size == 0) + { + item.IsAltStream = true; + item.Name.Empty(); + item.UnicodeName = L".ACL"; + } + else if (item.Name == "STM" && size != 0 && (size & 1) == 0) + { + item.IsAltStream = true; + item.Name.Empty(); + for (UInt32 i = 0; i < size; i += 2) + { + wchar_t c = Get16(p + i); + if (c == 0) + return false; + item.UnicodeName += c; + } + } + } + */ + + if (item.HasSalt()) + { + if (size < sizeof(item.Salt)) + return false; + for (unsigned i = 0; i < sizeof(item.Salt); i++) + item.Salt[i] = p[i]; + p += sizeof(item.Salt); + size -= sizeof(item.Salt); + } + + // some rar archives have HasExtTime flag without field. + if (size >= 2 && item.HasExtTime()) + { + Byte aMask = (Byte)(p[0] >> 4); + Byte b = p[1]; + p += 2; + size -= 2; + Byte mMask = (Byte)(b >> 4); + Byte cMask = (Byte)(b & 0xF); + if ((mMask & 8) != 0) + { + READ_TIME(mMask, item.MTime); + } + READ_TIME_2(cMask, item.CTimeDefined, item.CTime); + READ_TIME_2(aMask, item.ATimeDefined, item.ATime); + } + + unsigned fileHeaderWithNameSize = 7 + (unsigned)(p - pStart); + + item.Position = m_Position; + item.MainPartSize = fileHeaderWithNameSize; + item.CommentSize = (UInt16)(m_BlockHeader.HeadSize - fileHeaderWithNameSize); + + if (m_CryptoMode) + item.AlignSize = (UInt16)((16 - ((m_BlockHeader.HeadSize) & 0xF)) & 0xF); + else + item.AlignSize = 0; + AddToSeekValue(m_BlockHeader.HeadSize); + + // return (m_BlockHeader.Type != NHeader::NBlockType::kSubBlock || item.IsAltStream); + return true; +} + +HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPassword, bool &filled, EErrorType &error) +{ + filled = false; + error = k_ErrorType_OK; + for (;;) + { + m_Stream->Seek(m_Position, STREAM_SEEK_SET, NULL); + ArcInfo.EndPos = m_Position; + if (!m_CryptoMode && (ArcInfo.Flags & + NHeader::NArchive::kBlockHeadersAreEncrypted) != 0) + { + m_CryptoMode = false; + if (getTextPassword == 0) + { + error = k_ErrorType_DecryptionError; + return S_OK; // return S_FALSE; + } + if (!m_RarAES) + { + m_RarAESSpec = new NCrypto::NRar29::CDecoder; + m_RarAES = m_RarAESSpec; + } + m_RarAESSpec->SetRar350Mode(ArcInfo.IsEncryptOld()); + + // Salt + const UInt32 kSaltSize = 8; + Byte salt[kSaltSize]; + if (!ReadBytesAndTestSize(salt, kSaltSize)) + return S_FALSE; + m_Position += kSaltSize; + RINOK(m_RarAESSpec->SetDecoderProperties2(salt, kSaltSize)) + // Password + CMyComBSTR password; + RINOK(getTextPassword->CryptoGetTextPassword(&password)) + unsigned len = 0; + if (password) + len = MyStringLen((BSTR)password); + CByteBuffer buffer(len * 2); + for (unsigned i = 0; i < len; i++) + { + wchar_t c = password[i]; + ((Byte *)buffer)[i * 2] = (Byte)c; + ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); + } + + RINOK(m_RarAESSpec->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size())); + + const UInt32 kDecryptedBufferSize = (1 << 12); + if (m_DecryptedData.Size() == 0) + { + const UInt32 kAlign = 16; + m_DecryptedData.Alloc(kDecryptedBufferSize + kAlign); + m_DecryptedDataAligned = (Byte *)((ptrdiff_t)((Byte *)m_DecryptedData + kAlign - 1) & ~(ptrdiff_t)(kAlign - 1)); + } + RINOK(m_RarAES->Init()); + size_t decryptedDataSizeT = kDecryptedBufferSize; + RINOK(ReadStream(m_Stream, m_DecryptedDataAligned, &decryptedDataSizeT)); + m_DecryptedDataSize = (UInt32)decryptedDataSizeT; + m_DecryptedDataSize = m_RarAES->Filter(m_DecryptedDataAligned, m_DecryptedDataSize); + + m_CryptoMode = true; + m_CryptoPos = 0; + } + + m_FileHeaderData.AllocAtLeast(7); + size_t processed = 7; + RINOK(ReadBytesSpec((Byte *)m_FileHeaderData, &processed)); + if (processed != 7) + { + if (processed != 0) + error = k_ErrorType_UnexpectedEnd; + ArcInfo.EndPos = m_Position + processed; // test it + return S_OK; + } + + const Byte *p = m_FileHeaderData; + m_BlockHeader.CRC = Get16(p + 0); + m_BlockHeader.Type = p[2]; + m_BlockHeader.Flags = Get16(p + 3); + m_BlockHeader.HeadSize = Get16(p + 5); + + if (m_BlockHeader.HeadSize < 7) + { + error = k_ErrorType_Corrupted; + return S_OK; + // ThrowExceptionWithCode(CInArchiveException::kIncorrectArchive); + } + + if (m_BlockHeader.Type < NHeader::NBlockType::kFileHeader || + m_BlockHeader.Type > NHeader::NBlockType::kEndOfArchive) + { + error = m_CryptoMode ? + k_ErrorType_DecryptionError : + k_ErrorType_Corrupted; + return S_OK; + } + + if (m_BlockHeader.Type == NHeader::NBlockType::kEndOfArchive) + { + bool footerError = false; + + unsigned expectHeadLen = 7; + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) + expectHeadLen += 4; + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) + expectHeadLen += 2; + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_RevSpace) + expectHeadLen += 7; + + // rar 5.0 beta 1 writes incorrect RevSpace and headSize + + if (m_BlockHeader.HeadSize < expectHeadLen) + HeaderErrorWarning = true; + + if (m_BlockHeader.HeadSize > 7) + { + /* We suppose that EndOfArchive header is always small. + It's only 20 bytes for multivolume + Fix the limit, if larger footers are possible */ + if (m_BlockHeader.HeadSize > (1 << 8)) + footerError = true; + else + { + if (m_FileHeaderData.Size() < m_BlockHeader.HeadSize) + m_FileHeaderData.ChangeSize_KeepData(m_BlockHeader.HeadSize, 7); + UInt32 afterSize = m_BlockHeader.HeadSize - 7; + if (ReadBytesAndTestSize(m_FileHeaderData + 7, afterSize)) + processed += afterSize; + else + { + if (!m_CryptoMode) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + footerError = true; + } + } + } + + if (footerError || !CheckHeaderCrc(m_FileHeaderData, m_BlockHeader.HeadSize)) + { + error = m_CryptoMode ? + k_ErrorType_DecryptionError : + k_ErrorType_Corrupted; + } + else + { + ArcInfo.EndFlags = m_BlockHeader.Flags; + UInt32 offset = 7; + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) + { + if (processed < offset + 4) + error = k_ErrorType_Corrupted; + else + ArcInfo.DataCRC = Get32(m_FileHeaderData + offset); + offset += 4; + } + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) + { + if (processed < offset + 2) + error = k_ErrorType_Corrupted; + ArcInfo.VolNumber = (UInt32)Get16(m_FileHeaderData + offset); + } + } + m_Position += processed; + FinishCryptoBlock(); + ArcInfo.EndPos = m_Position; + return S_OK; + } + + if (m_BlockHeader.Type == NHeader::NBlockType::kFileHeader + /* || m_BlockHeader.Type == NHeader::NBlockType::kSubBlock */) + { + if (m_FileHeaderData.Size() < m_BlockHeader.HeadSize) + m_FileHeaderData.ChangeSize_KeepData(m_BlockHeader.HeadSize, 7); + // m_CurData = (Byte *)m_FileHeaderData; + // m_PosLimit = m_BlockHeader.HeadSize; + if (!ReadBytesAndTestSize(m_FileHeaderData + 7, m_BlockHeader.HeadSize - 7)) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + + bool okItem = ReadHeaderReal(m_FileHeaderData + 7, m_BlockHeader.HeadSize - 7, item); + if (okItem) + { + if (!CheckHeaderCrc(m_FileHeaderData, m_BlockHeader.HeadSize - item.CommentSize)) + { + error = k_ErrorType_Corrupted; // ThrowExceptionWithCode(CInArchiveException::kFileHeaderCRCError); + return S_OK; + } + filled = true; + } + + FinishCryptoBlock(); + m_CryptoMode = false; + // Move Position to compressed Data; + m_Stream->Seek(m_Position, STREAM_SEEK_SET, NULL); + AddToSeekValue(item.PackSize); // m_Position points to next header; + // if (okItem) + return S_OK; + /* + else + continue; + */ + } + if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 10)) + { + error = k_ErrorType_DecryptionError; + return S_OK; + } + if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0) + { + if (m_FileHeaderData.Size() < 7 + 4) + m_FileHeaderData.ChangeSize_KeepData(7 + 4, 7); + if (!ReadBytesAndTestSize(m_FileHeaderData + 7, 4)) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + UInt32 dataSize = Get32(m_FileHeaderData + 7); + AddToSeekValue(dataSize); + if (m_CryptoMode && dataSize > (1 << 27)) + { + error = k_ErrorType_DecryptionError; + return S_OK; + } + m_CryptoPos = m_BlockHeader.HeadSize; + } + else + m_CryptoPos = 0; + + { + UInt64 newPos = m_Position + m_BlockHeader.HeadSize; + if (newPos > ArcInfo.FileSize) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + } + AddToSeekValue(m_BlockHeader.HeadSize); + FinishCryptoBlock(); + m_CryptoMode = false; + } +} + + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidAttrib, + + kpidEncrypted, + kpidSolid, + kpidCommented, + kpidSplitBefore, + kpidSplitAfter, + kpidCRC, + kpidHostOS, + kpidMethod, + kpidUnpackVer +}; + +static const Byte kArcProps[] = +{ + kpidTotalPhySize, + kpidCharacts, + kpidSolid, + kpidNumBlocks, + // kpidEncrypted, + kpidIsVolume, + kpidVolumeIndex, + kpidNumVolumes + // kpidCommented }; IMP_IInArchive_Props IMP_IInArchive_ArcProps -UInt64 CHandler::GetPackSize(int refIndex) const +UInt64 CHandler::GetPackSize(unsigned refIndex) const { const CRefItem &refItem = _refItems[refIndex]; UInt64 totalPackSize = 0; - for (int i = 0; i < refItem.NumItems; i++) + for (unsigned i = 0; i < refItem.NumItems; i++) totalPackSize += _items[refItem.ItemIndex + i].PackSize; return totalPackSize; } +bool CHandler::IsSolid(unsigned refIndex) const +{ + const CItem &item = _items[_refItems[refIndex].ItemIndex]; + if (item.UnPackVersion < 20) + { + if (_arcInfo.IsSolid()) + return (refIndex > 0); + return false; + } + return item.IsSolid(); +} + STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) + NCOM::CPropVariant prop; + switch (propID) { - case kpidSolid: prop = _archiveInfo.IsSolid(); break; - case kpidCharacts: FLAGS_TO_PROP(k_Flags, _archiveInfo.Flags, prop); break; - // case kpidEncrypted: prop = _archiveInfo.IsEncrypted(); break; // it's for encrypted names. - case kpidIsVolume: prop = _archiveInfo.IsVolume(); break; - case kpidNumVolumes: prop = (UInt32)_archives.Size(); break; - case kpidOffset: if (_archiveInfo.StartPosition != 0) prop = _archiveInfo.StartPosition; break; - // case kpidCommented: prop = _archiveInfo.IsCommented(); break; + case kpidVolumeIndex: if (_arcInfo.Is_VolNumber_Defined()) prop = (UInt32)_arcInfo.VolNumber; break; + case kpidSolid: prop = _arcInfo.IsSolid(); break; + case kpidCharacts: + { + AString s = FlagsToString(k_Flags, ARRAY_SIZE(k_Flags), _arcInfo.Flags); + // FLAGS_TO_PROP(k_Flags, _arcInfo.Flags, prop); + if (_arcInfo.Is_DataCRC_Defined()) + { + if (!s.IsEmpty()) + s += ' '; + s += "VolCRC"; + } + prop = s; + break; + } + // case kpidEncrypted: prop = _arcInfo.IsEncrypted(); break; // it's for encrypted names. + case kpidIsVolume: prop = _arcInfo.IsVolume(); break; + case kpidNumVolumes: prop = (UInt32)_arcs.Size(); break; + case kpidOffset: if (_arcs.Size() == 1 && _arcInfo.StartPos != 0) prop = _arcInfo.StartPos; break; + + case kpidTotalPhySize: + { + if (_arcs.Size() > 1) + { + UInt64 sum = 0; + FOR_VECTOR (v, _arcs) + sum += _arcs[v].PhySize; + prop = sum; + } + break; + } + + case kpidPhySize: + { + if (_arcs.Size() != 0) + prop = _arcInfo.GetPhySize(); + break; + } + + // case kpidCommented: prop = _arcInfo.IsCommented(); break; + case kpidNumBlocks: { UInt32 numBlocks = 0; - for (int i = 0; i < _refItems.Size(); i++) + FOR_VECTOR (i, _refItems) if (!IsSolid(i)) numBlocks++; prop = (UInt32)numBlocks; break; } - case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + + // case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + + case kpidErrorFlags: + { + UInt32 v = _errorFlags; + if (!_isArc) + v |= kpv_ErrorFlags_IsNotArc; + prop = v; + break; + } + + case kpidWarningFlags: + { + if (_warningFlags != 0) + prop = _warningFlags; + break; + } + + case kpidExtension: + if (_arcs.Size() == 1) + { + 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++) + s += '0'; + s += sz; + s += ".rar"; + prop = s; + } + } + break; } prop.Detach(value); return S_OK; @@ -144,7 +894,7 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result) { - if (!DosTimeToFileTime(rarTime.DosTime, result)) + if (!NTime::DosTimeToFileTime(rarTime.DosTime, result)) return false; UInt64 value = (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime; value += (UInt64)rarTime.LowSecond * 10000000; @@ -156,7 +906,7 @@ static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result) return true; } -static void RarTimeToProp(const CRarTime &rarTime, NWindows::NCOM::CPropVariant &prop) +static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop) { FILETIME localFileTime, utcFileTime; if (RarTimeToFileTime(rarTime, localFileTime)) @@ -169,22 +919,28 @@ static void RarTimeToProp(const CRarTime &rarTime, NWindows::NCOM::CPropVariant prop = utcFileTime; } -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; const CRefItem &refItem = _refItems[index]; - const CItemEx &item = _items[refItem.ItemIndex]; + const CItem &item = _items[refItem.ItemIndex]; + /* + const CItem *mainItem = &item; + if (item.BaseFileIndex >= 0) + mainItem = &_items[_refItems[item.BaseFileIndex].ItemIndex]; + */ switch(propID) { case kpidPath: { + /* UString u; - if (item.HasUnicodeName() && !item.UnicodeName.IsEmpty()) - u = item.UnicodeName; - else - u = MultiByteToUnicodeString(item.Name, CP_OEMCP); - prop = (const wchar_t *)NItemName::WinNameToOSName(u); + if (item.BaseFileIndex >= 0) + u = mainItem->GetName(); + u += item.GetName(); + */ + prop = (const wchar_t *)NItemName::WinNameToOSName(item.GetName()); break; } case kpidIsDir: prop = item.IsDir(); break; @@ -193,7 +949,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va case kpidMTime: RarTimeToProp(item.MTime, prop); break; case kpidCTime: if (item.CTimeDefined) RarTimeToProp(item.CTime, prop); break; case kpidATime: if (item.ATimeDefined) RarTimeToProp(item.ATime, prop); break; - case kpidAttrib: prop = item.GetWinAttributes(); break; + case kpidAttrib: prop = item.GetWinAttrib(); break; case kpidEncrypted: prop = item.IsEncrypted(); break; case kpidSolid: prop = IsSolid(index); break; case kpidCommented: prop = item.IsCommented(); break; @@ -201,43 +957,44 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va case kpidSplitAfter: prop = _items[refItem.ItemIndex + refItem.NumItems - 1].IsSplitAfter(); break; case kpidCRC: { - const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1]; + const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1]; prop = ((lastItem.IsSplitAfter()) ? item.FileCRC : lastItem.FileCRC); break; } case kpidUnpackVer: prop = item.UnPackVersion; break; case kpidMethod: { - UString method; - if (item.Method >= Byte('0') && item.Method <= Byte('5')) + char temp[16]; + char *s = temp; + if (item.Method >= (Byte)'0' && item.Method <= (Byte)'5') { - method = L"m"; - wchar_t temp[32]; - ConvertUInt64ToString(item.Method - Byte('0'), temp); - method += temp; + *s++ = 'm'; + *s++ = (char)item.Method; if (!item.IsDir()) { - method += L":"; - ConvertUInt64ToString(16 + item.GetDictSize(), temp); - method += temp; + *s++ = ':'; + ConvertUInt32ToString(16 + item.GetDictSize(), s); } } else - { - wchar_t temp[32]; - ConvertUInt64ToString(item.Method, temp); - method += temp; - } - prop = method; + ConvertUInt32ToString(item.Method, s); + s += MyStringLen(s); + *s = 0; + prop = s; break; } - case kpidHostOS: prop = (item.HostOS < kNumHostOSes) ? (kHostOS[item.HostOS]) : kUnknownOS; break; + case kpidHostOS: prop = (item.HostOS < ARRAY_SIZE(kHostOS)) ? kHostOS[item.HostOS] : kUnknownOS; break; } prop.Detach(value); return S_OK; COM_TRY_END } +static bool IsDigit(wchar_t c) +{ + return c >= L'0' && c <= L'9'; +} + class CVolumeName { bool _first; @@ -256,23 +1013,23 @@ public: UString basePart = name; if (dotPos >= 0) { - UString ext = name.Mid(dotPos + 1); - if (ext.CompareNoCase(L"rar") == 0) + UString ext = name.Ptr(dotPos + 1); + if (ext.IsEqualToNoCase(L"rar")) { - _afterPart = name.Mid(dotPos); + _afterPart = name.Ptr(dotPos); basePart = name.Left(dotPos); } - else if (ext.CompareNoCase(L"exe") == 0) + else if (ext.IsEqualToNoCase(L"exe")) { _afterPart = L".rar"; basePart = name.Left(dotPos); } else if (!_newStyle) { - if (ext.CompareNoCase(L"000") == 0 || - ext.CompareNoCase(L"001") == 0 || - ext.CompareNoCase(L"r00") == 0 || - ext.CompareNoCase(L"r01") == 0) + if (ext.IsEqualToNoCase(L"000") || + ext.IsEqualToNoCase(L"001") || + ext.IsEqualToNoCase(L"r00") || + ext.IsEqualToNoCase(L"r01")) { _afterPart.Empty(); _first = false; @@ -291,46 +1048,49 @@ public: return true; } - int numLetters = 1; - if (basePart.Right(numLetters) == L"1" || basePart.Right(numLetters) == L"0") - { - while (numLetters < basePart.Length()) - { - if (basePart[basePart.Length() - numLetters - 1] != '0') - break; - numLetters++; - } - } - else + if (basePart.IsEmpty()) return false; - _unchangedPart = basePart.Left(basePart.Length() - numLetters); - _changedPart = basePart.Right(numLetters); + unsigned i = basePart.Len(); + do + if (!IsDigit(basePart[i - 1])) + break; + while (--i); + _unchangedPart = basePart.Left(i); + _changedPart = basePart.Ptr(i); return true; } + /* + void MakeBeforeFirstName() + { + unsigned len = _changedPart.Len(); + _changedPart.Empty(); + for (unsigned i = 0; i < len; i++) + _changedPart += L'0'; + } + */ + UString GetNextName() { UString newName; if (_newStyle || !_first) { - int i; - int numLetters = _changedPart.Length(); - for (i = numLetters - 1; i >= 0; i--) + for (int i = (int)_changedPart.Len() - 1; i >= 0; i--) { wchar_t c = _changedPart[i]; if (c == L'9') { c = L'0'; - newName = c + newName; + newName.InsertAtFront(c); if (i == 0) - newName = UString(L'1') + newName; + newName.InsertAtFront(L'1'); continue; } c++; newName = UString(c) + newName; i--; for (; i >= 0; i--) - newName = _changedPart[i] + newName; + newName.InsertAtFront(_changedPart[i]); break; } _changedPart = newName; @@ -360,17 +1120,18 @@ HRESULT CHandler::Open2(IInStream *stream, openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); } + CInArchive archive; for (;;) { CMyComPtr<IInStream> inStream; - if (!_archives.IsEmpty()) + if (!_arcs.IsEmpty()) { if (!openVolumeCallback) break; - if (_archives.Size() == 1) + if (_arcs.Size() == 1) { - if (!_archiveInfo.IsVolume()) + if (!_arcInfo.IsVolume()) break; UString baseName; { @@ -380,7 +1141,14 @@ HRESULT CHandler::Open2(IInStream *stream, break; baseName = prop.bstrVal; } - seqName.InitName(baseName, _archiveInfo.HaveNewVolumeName()); + if (!seqName.InitName(baseName, _arcInfo.HaveNewVolumeName())) + break; + /* + if (_arcInfo.HaveNewVolumeName() && !_arcInfo.IsFirstVolume()) + { + seqName.MakeBeforeFirstName(); + } + */ } UString fullName = seqName.GetNextName(); @@ -389,47 +1157,54 @@ HRESULT CHandler::Open2(IInStream *stream, break; if (result != S_OK) return result; - if (!stream) + if (!inStream) break; } else inStream = stream; UInt64 endPos = 0; - RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); - RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); if (openCallback) { totalBytes += endPos; RINOK(openCallback->SetTotal(NULL, &totalBytes)); } - NArchive::NRar::CInArchive archive; RINOK(archive.Open(inStream, maxCheckStartPosition)); - - if (_archives.IsEmpty()) - archive.GetArchiveInfo(_archiveInfo); - - CItemEx item; + _isArc = true; + CItem item; for (;;) { if (archive.m_Position > endPos) { - AddErrorMessage("Unexpected end of archive"); + _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; break; } - bool decryptionError; - AString errorMessageLoc; - HRESULT result = archive.GetNextItem(item, getTextPassword, decryptionError, errorMessageLoc); - if (errorMessageLoc) - AddErrorMessage(errorMessageLoc); - if (result == S_FALSE) + EErrorType error; + // bool decryptionError; + // AString errorMessageLoc; + bool filled; + HRESULT result = archive.GetNextItem(item, getTextPassword, filled, error); + if (error != k_ErrorType_OK) + { + if (error == k_ErrorType_UnexpectedEnd) + _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; + else if (error == k_ErrorType_Corrupted) + _errorFlags |= kpv_ErrorFlags_HeadersError; + else if (error == k_ErrorType_DecryptionError) + _errorFlags |= kpv_ErrorFlags_EncryptedHeadersError; + + // AddErrorMessage(errorMessageLoc); + } + RINOK(result); + if (!filled) { - if (decryptionError && _items.IsEmpty()) + if (error == k_ErrorType_DecryptionError && _items.IsEmpty()) return S_FALSE; break; } - RINOK(result); if (item.IgnoreItem()) continue; @@ -448,7 +1223,7 @@ HRESULT CHandler::Open2(IInStream *stream, CRefItem refItem; refItem.ItemIndex = _items.Size(); refItem.NumItems = 1; - refItem.VolumeIndex = _archives.Size(); + refItem.VolumeIndex = _arcs.Size(); _refItems.Add(refItem); } _items.Add(item); @@ -459,10 +1234,38 @@ HRESULT CHandler::Open2(IInStream *stream, RINOK(openCallback->SetCompleted(&numFiles, &numBytes)); } } + + if (archive.HeaderErrorWarning) + _warningFlags |= kpv_ErrorFlags_HeadersError; + + /* + if (archive.m_Position < endPos) + _warningFlags |= kpv_ErrorFlags_DataAfterEnd; + */ + if (_arcs.IsEmpty()) + _arcInfo = archive.ArcInfo; + // _arcInfo.EndPos = archive.EndPos; + curBytes += endPos; - _archives.Add(archive); + { + CArc &arc = _arcs.AddNew(); + arc.PhySize = archive.ArcInfo.GetPhySize(); + arc.Stream = inStream; + } } } + + /* + int baseFileIndex = -1; + for (int i = 0; i < _refItems.Size(); i++) + { + CItem &item = _items[_refItems[i].ItemIndex]; + if (item.IsAltStream) + item.BaseFileIndex = baseFileIndex; + else + baseFileIndex = i; + } + */ return S_OK; } @@ -472,25 +1275,31 @@ STDMETHODIMP CHandler::Open(IInStream *stream, { COM_TRY_BEGIN Close(); - try + // try { HRESULT res = Open2(stream, maxCheckStartPosition, openCallback); + /* if (res != S_OK) Close(); + */ + return res; } - catch(const CInArchiveException &) { Close(); return S_FALSE; } - catch(...) { Close(); throw; } + // catch(const CInArchiveException &) { Close(); return S_FALSE; } + // catch(...) { Close(); throw; } COM_TRY_END } STDMETHODIMP CHandler::Close() { COM_TRY_BEGIN - _errorMessage.Empty(); + // _errorMessage.Empty(); + _errorFlags = 0; + _warningFlags = 0; + _isArc = false; _refItems.Clear(); _items.Clear(); - _archives.Clear(); + _arcs.Clear(); return S_OK; COM_TRY_END } @@ -502,6 +1311,111 @@ struct CMethodItem }; +class CFolderInStream: + public ISequentialInStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + +private: + const CObjectVector<CArc> *_archives; + const CObjectVector<CItem> *_items; + CRefItem _refItem; + unsigned _curIndex; + UInt32 _crc; + bool _fileIsOpen; + CMyComPtr<ISequentialInStream> _stream; + + HRESULT OpenStream(); + HRESULT CloseStream(); +public: + void Init(const CObjectVector<CArc> *archives, + const CObjectVector<CItem> *items, + const CRefItem &refItem); + + CRecordVector<UInt32> CRCs; +}; + + +ISequentialInStream* CArc::CreateLimitedStream(UInt64 offset, UInt64 size) const +{ + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream(streamSpec); + Stream->Seek(offset, STREAM_SEEK_SET, NULL); + streamSpec->SetStream(Stream); + streamSpec->Init(size); + return inStream.Detach(); +} + +void CFolderInStream::Init( + const CObjectVector<CArc> *archives, + const CObjectVector<CItem> *items, + const CRefItem &refItem) +{ + _archives = archives; + _items = items; + _refItem = refItem; + _curIndex = 0; + CRCs.Clear(); + _fileIsOpen = false; +} + +HRESULT CFolderInStream::OpenStream() +{ + while (_curIndex < _refItem.NumItems) + { + const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex]; + _stream.Attach((*_archives)[_refItem.VolumeIndex + _curIndex]. + CreateLimitedStream(item.GetDataPosition(), item.PackSize)); + _curIndex++; + _fileIsOpen = true; + _crc = CRC_INIT_VAL; + return S_OK; + } + return S_OK; +} + +HRESULT CFolderInStream::CloseStream() +{ + CRCs.Add(CRC_GET_DIGEST(_crc)); + _stream.Release(); + _fileIsOpen = false; + return S_OK; +} + +STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 realProcessedSize = 0; + while ((_curIndex < _refItem.NumItems || _fileIsOpen) && size > 0) + { + if (_fileIsOpen) + { + UInt32 localProcessedSize; + RINOK(_stream->Read( + ((Byte *)data) + realProcessedSize, size, &localProcessedSize)); + _crc = CrcUpdate(_crc, ((Byte *)data) + realProcessedSize, localProcessedSize); + if (localProcessedSize == 0) + { + RINOK(CloseStream()); + continue; + } + realProcessedSize += localProcessedSize; + size -= localProcessedSize; + break; + } + else + { + RINOK(OpenStream()); + } + } + if (processedSize != 0) + *processedSize = realProcessedSize; + return S_OK; +} + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { @@ -511,23 +1425,23 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, // censoredTotalPacked = 0, importantTotalUnPacked = 0; // importantTotalPacked = 0; - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _refItems.Size(); if (numItems == 0) return S_OK; - int lastIndex = 0; + unsigned lastIndex = 0; CRecordVector<int> importantIndexes; CRecordVector<bool> extractStatuses; for (UInt32 t = 0; t < numItems; t++) { - int index = allFilesMode ? t : indices[t]; + unsigned index = allFilesMode ? t : indices[t]; const CRefItem &refItem = _refItems[index]; - const CItemEx &item = _items[refItem.ItemIndex]; + const CItem &item = _items[refItem.ItemIndex]; censoredTotalUnPacked += item.Size; // censoredTotalPacked += item.PackSize; - int j; + unsigned j; for (j = lastIndex; j <= index; j++) // if (!_items[_refItems[j].ItemIndex].IsSolid()) if (!IsSolid(j)) @@ -535,9 +1449,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, for (j = lastIndex; j <= index; j++) { const CRefItem &refItem = _refItems[j]; - const CItemEx &item = _items[refItem.ItemIndex]; + const CItem &item = _items[refItem.ItemIndex]; - // const CItemEx &item = _items[j]; + // const CItem &item = _items[j]; importantTotalUnPacked += item.Size; // importantTotalPacked += item.PackSize; @@ -573,7 +1487,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, lps->Init(extractCallback, false); bool solidStart = true; - for (int i = 0; i < importantIndexes.Size(); i++, + for (unsigned i = 0; i < importantIndexes.Size(); i++, currentImportantTotalUnPacked += currentUnPackSize, currentImportantTotalPacked += currentPackSize) { @@ -593,7 +1507,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt32 index = importantIndexes[i]; const CRefItem &refItem = _refItems[index]; - const CItemEx &item = _items[refItem.ItemIndex]; + const CItem &item = _items[refItem.ItemIndex]; currentUnPackSize = item.Size; @@ -617,7 +1531,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (i < importantIndexes.Size() - 1) { // const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]]; - // const CItemEx &nextItemInfo = _items[nextRefItem.ItemIndex]; + // const CItem &nextItemInfo = _items[nextRefItem.ItemIndex]; // mustBeProcessedAnywhere = nextItemInfo.IsSolid(); mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]); } @@ -637,14 +1551,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, realOutStream.Release(); /* - for (int partIndex = 0; partIndex < 1; partIndex++) + for (unsigned partIndex = 0; partIndex < 1; partIndex++) { CMyComPtr<ISequentialInStream> inStream; // item redefinition - const CItemEx &item = _items[refItem.ItemIndex + partIndex]; + const CItem &item = _items[refItem.ItemIndex + partIndex]; - NArchive::NRar::CInArchive &archive = _archives[refItem.VolumeIndex + partIndex]; + CInArchive &archive = _arcs[refItem.VolumeIndex + partIndex]; inStream.Attach(archive.CreateLimitedStream(item.GetDataPosition(), item.PackSize)); @@ -655,7 +1569,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, folderInStream = folderInStreamSpec; } - folderInStreamSpec->Init(&_archives, &_items, refItem); + folderInStreamSpec->Init(&_arcs, &_items, refItem); UInt64 packSize = currentPackSize; @@ -694,7 +1608,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, else { outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); continue; } RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, @@ -708,25 +1622,25 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(getTextPassword->CryptoGetTextPassword(&password)); if (item.UnPackVersion >= 29) { - CByteBuffer buffer; - UString unicodePassword(password); - const UInt32 sizeInBytes = unicodePassword.Length() * 2; - buffer.SetCapacity(sizeInBytes); - for (int i = 0; i < unicodePassword.Length(); i++) + UString unicodePassword; + unsigned len = 0; + if (password) + len = MyStringLen((BSTR)password); + CByteBuffer buffer(len * 2); + for (unsigned i = 0; i < len; i++) { - wchar_t c = unicodePassword[i]; + wchar_t c = password[i]; ((Byte *)buffer)[i * 2] = (Byte)c; ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); } - RINOK(cryptoSetPassword->CryptoSetPassword( - (const Byte *)buffer, sizeInBytes)); + RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size())); } else { - AString oemPassword = UnicodeStringToMultiByte( - (const wchar_t *)password, CP_OEMCP); - RINOK(cryptoSetPassword->CryptoSetPassword( - (const Byte *)(const char *)oemPassword, oemPassword.Length())); + AString oemPassword; + if (password) + oemPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP); + RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len())); } } else @@ -754,15 +1668,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, case '4': case '5': { - /* - if (item.UnPackVersion >= 29) - { - outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); - continue; - } - */ - int m; + unsigned m; for (m = 0; m < methodItems.Size(); m++) if (methodItems[m].RarUnPackVersion == item.UnPackVersion) break; @@ -772,7 +1678,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, mi.RarUnPackVersion = item.UnPackVersion; mi.Coder.Release(); - if (item.UnPackVersion <= 30) + if (item.UnPackVersion <= 40) { UInt32 methodID = 0x040300; if (item.UnPackVersion < 20) @@ -787,7 +1693,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (mi.Coder == 0) { outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); continue; } @@ -814,7 +1720,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } default: outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); continue; } HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &item.Size, progress); @@ -834,7 +1740,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, !item.IsSplitBefore() && !item.IsSplitAfter()) */ { - const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1]; + const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1]; bool crcOK = outStreamSpec->GetCRC() == lastItem.FileCRC; outStream.Release(); RINOK(extractCallback->SetOperationResult(crcOK ? @@ -845,9 +1751,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, else { bool crcOK = true; - for (int partIndex = 0; partIndex < refItem.NumItems; partIndex++) + for (unsigned partIndex = 0; partIndex < refItem.NumItems; partIndex++) { - const CItemEx &item = _items[refItem.ItemIndex + partIndex]; + const CItem &item = _items[refItem.ItemIndex + partIndex]; if (item.FileCRC != folderInStreamSpec->CRCs[partIndex]) { crcOK = false; @@ -866,4 +1772,15 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, IMPL_ISetCompressCodecsInfo +IMP_CreateArcIn + +static CArcInfo g_ArcInfo = + { "Rar", "rar r00", 0, 3, + NHeader::kMarkerSize, SIGNATURE, + 0, + NArcInfoFlags::kFindSignature, + CreateArc }; + +REGISTER_ARC(Rar) + }} diff --git a/CPP/7zip/Archive/Rar/RarHandler.h b/CPP/7zip/Archive/Rar/RarHandler.h index 79266827..81191be9 100755..100644 --- a/CPP/7zip/Archive/Rar/RarHandler.h +++ b/CPP/7zip/Archive/Rar/RarHandler.h @@ -7,44 +7,85 @@ #include "../../Common/CreateCoder.h" -#include "RarIn.h" -#include "RarVolumeInStream.h" +#include "RarItem.h" namespace NArchive { namespace NRar { +struct CInArcInfo +{ + UInt32 Flags; + Byte EncryptVersion; + + UInt64 StartPos; + UInt64 EndPos; + UInt64 FileSize; + + UInt32 EndFlags; + UInt32 VolNumber; + UInt32 DataCRC; + + CInArcInfo(): EndFlags(0) {} + + UInt64 GetPhySize() const { return EndPos - StartPos; } + + bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; } + bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; } + bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; } + bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 0; } + bool IsFirstVolume() const { return (Flags & NHeader::NArchive::kFirstVolume) != 0; } + bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; } + bool IsThereEncryptVer() const { return (Flags & NHeader::NArchive::kEncryptVer) != 0; } + bool IsEncryptOld() const { return (!IsThereEncryptVer() || EncryptVersion < 36); } + + bool Is_VolNumber_Defined() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) != 0; } + bool Is_DataCRC_Defined() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) != 0; } +}; + +struct CArc +{ + CMyComPtr<IInStream> Stream; + UInt64 PhySize; + // CByteBuffer Comment; + + CArc(): PhySize(0) {} + ISequentialInStream *CreateLimitedStream(UInt64 offset, UInt64 size) const; +}; + +struct CRefItem +{ + unsigned VolumeIndex; + unsigned ItemIndex; + unsigned NumItems; +}; + class CHandler: public IInArchive, PUBLIC_ISetCompressCodecsInfo public CMyUnknownImp { CRecordVector<CRefItem> _refItems; - CObjectVector<CItemEx> _items; - CObjectVector<CInArchive> _archives; - NArchive::NRar::CInArchiveInfo _archiveInfo; - AString _errorMessage; + CObjectVector<CItem> _items; + CObjectVector<CArc> _arcs; + NArchive::NRar::CInArcInfo _arcInfo; + // AString _errorMessage; + UInt32 _errorFlags; + UInt32 _warningFlags; + bool _isArc; DECL_EXTERNAL_CODECS_VARS - UInt64 GetPackSize(int refIndex) const; - - bool IsSolid(int refIndex) - { - const CItemEx &item = _items[_refItems[refIndex].ItemIndex]; - if (item.UnPackVersion < 20) - { - if (_archiveInfo.IsSolid()) - return (refIndex > 0); - return false; - } - return item.IsSolid(); - } + UInt64 GetPackSize(unsigned refIndex) const; + bool IsSolid(unsigned refIndex) const; + + /* void AddErrorMessage(const AString &s) { if (!_errorMessage.IsEmpty()) _errorMessage += '\n'; _errorMessage += s; } + */ HRESULT Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, diff --git a/CPP/7zip/Archive/Rar/RarHeader.cpp b/CPP/7zip/Archive/Rar/RarHeader.cpp deleted file mode 100755 index 94481e02..00000000 --- a/CPP/7zip/Archive/Rar/RarHeader.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Archive/Rar/Headers.cpp - -#include "StdAfx.h" - -#include "RarHeader.h" - -namespace NArchive{ -namespace NRar{ -namespace NHeader{ - -Byte kMarker[kMarkerSize] = {0x52 + 1, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00}; - -class CMarkerInitializer -{ -public: - CMarkerInitializer() { kMarker[0]--; }; -}; - -static CMarkerInitializer markerInitializer; - -}}} diff --git a/CPP/7zip/Archive/Rar/RarHeader.h b/CPP/7zip/Archive/Rar/RarHeader.h index 5c21a2ac..b518338a 100755..100644 --- a/CPP/7zip/Archive/Rar/RarHeader.h +++ b/CPP/7zip/Archive/Rar/RarHeader.h @@ -3,16 +3,15 @@ #ifndef __ARCHIVE_RAR_HEADER_H #define __ARCHIVE_RAR_HEADER_H -#include "Common/Types.h" +#include "../../../Common/MyTypes.h" namespace NArchive { namespace NRar { namespace NHeader { -const int kMarkerSize = 7; -extern Byte kMarker[kMarkerSize]; +const unsigned kMarkerSize = 7; -const int kArchiveSolid = 0x1; +const unsigned kArchiveSolid = 0x1; namespace NBlockType { @@ -44,36 +43,40 @@ namespace NArchive const UInt16 kFirstVolume = 0x100; // (set only by RAR 3.0 and later) const UInt16 kEncryptVer = 0x200; // RAR 3.6 there is EncryptVer Byte in End of MainHeader - const int kHeaderSizeMin = 7; - - const int kArchiveHeaderSize = 13; + const UInt16 kEndOfArc_Flags_NextVol = 1; + const UInt16 kEndOfArc_Flags_DataCRC = 2; + const UInt16 kEndOfArc_Flags_RevSpace = 4; + const UInt16 kEndOfArc_Flags_VolNumber = 8; - const int kBlockHeadersAreEncrypted = 0x80; + const unsigned kHeaderSizeMin = 7; + + const unsigned kArchiveHeaderSize = 13; + const unsigned kBlockHeadersAreEncrypted = 0x80; } namespace NFile { - const int kSplitBefore = 1 << 0; - const int kSplitAfter = 1 << 1; - const int kEncrypted = 1 << 2; - const int kComment = 1 << 3; - const int kSolid = 1 << 4; + const unsigned kSplitBefore = 1 << 0; + const unsigned kSplitAfter = 1 << 1; + const unsigned kEncrypted = 1 << 2; + const unsigned kComment = 1 << 3; + const unsigned kSolid = 1 << 4; - const int kDictBitStart = 5; - const int kNumDictBits = 3; - const int kDictMask = (1 << kNumDictBits) - 1; - const int kDictDirectoryValue = 0x7; + const unsigned kDictBitStart = 5; + const unsigned kNumDictBits = 3; + const unsigned kDictMask = (1 << kNumDictBits) - 1; + const unsigned kDictDirectoryValue = 0x7; - const int kSize64Bits = 1 << 8; - const int kUnicodeName = 1 << 9; - const int kSalt = 1 << 10; - const int kOldVersion = 1 << 11; - const int kExtTime = 1 << 12; - // const int kExtFlags = 1 << 13; - // const int kSkipIfUnknown = 1 << 14; - - const int kLongBlock = 1 << 15; + const unsigned kSize64Bits = 1 << 8; + const unsigned kUnicodeName = 1 << 9; + const unsigned kSalt = 1 << 10; + const unsigned kOldVersion = 1 << 11; + const unsigned kExtTime = 1 << 12; + // const unsigned kExtFlags = 1 << 13; + // const unsigned kSkipIfUnknown = 1 << 14; + + const unsigned kLongBlock = 1 << 15; /* struct CBlock @@ -134,17 +137,17 @@ namespace NFile }; */ - const int kLabelFileAttribute = 0x08; - const int kWinFileDirectoryAttributeMask = 0x10; + const unsigned kLabelFileAttribute = 0x08; + const unsigned kWinFileDirectoryAttributeMask = 0x10; enum CHostOS { kHostMSDOS = 0, - kHostOS2 = 1, - kHostWin32 = 2, - kHostUnix = 3, - kHostMacOS = 4, - kHostBeOS = 5 + kHostOS2 = 1, + kHostWin32 = 2, + kHostUnix = 3, + kHostMacOS = 4, + kHostBeOS = 5 }; } diff --git a/CPP/7zip/Archive/Rar/RarIn.cpp b/CPP/7zip/Archive/Rar/RarIn.cpp deleted file mode 100755 index a7d018ff..00000000 --- a/CPP/7zip/Archive/Rar/RarIn.cpp +++ /dev/null @@ -1,478 +0,0 @@ -// Archive/RarIn.cpp - -#include "StdAfx.h" - -#include "../../../../C/7zCrc.h" -#include "../../../../C/CpuArch.h" - -#include "Common/StringConvert.h" -#include "Common/UTFConvert.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/StreamUtils.h" - -#include "../Common/FindSignature.h" - -#include "RarIn.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -namespace NArchive { -namespace NRar { - -static const char *k_UnexpectedEnd = "Unexpected end of archive"; -static const char *k_DecryptionError = "Decryption Error"; - -void CInArchive::ThrowExceptionWithCode( - CInArchiveException::CCauseType cause) -{ - throw CInArchiveException(cause); -} - -HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit) -{ - try - { - Close(); - HRESULT res = Open2(inStream, searchHeaderSizeLimit); - if (res == S_OK) - return res; - Close(); - return res; - } - catch(...) { Close(); throw; } -} - -void CInArchive::Close() -{ - m_Stream.Release(); -} - -HRESULT CInArchive::ReadBytesSpec(void *data, size_t *resSize) -{ - if (m_CryptoMode) - { - size_t size = *resSize; - *resSize = 0; - const Byte *bufData = m_DecryptedDataAligned; - UInt32 bufSize = m_DecryptedDataSize; - size_t i; - for (i = 0; i < size && m_CryptoPos < bufSize; i++) - ((Byte *)data)[i] = bufData[m_CryptoPos++]; - *resSize = i; - return S_OK; - } - return ReadStream(m_Stream, data, resSize); -} - -bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size) -{ - size_t processed = size; - if (ReadBytesSpec(data, &processed) != S_OK) - return false; - return processed == size; -} - -HRESULT CInArchive::Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit) -{ - m_CryptoMode = false; - RINOK(stream->Seek(0, STREAM_SEEK_SET, &m_StreamStartPosition)); - m_Position = m_StreamStartPosition; - - UInt64 arcStartPos; - RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize, - searchHeaderSizeLimit, arcStartPos)); - m_Position = arcStartPos + NHeader::kMarkerSize; - RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); - Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1]; - - RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize)); - AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize); - - - UInt32 blockSize = Get16(buf + 5); - - _header.EncryptVersion = 0; - _header.Flags = Get16(buf + 3); - - UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize; - if (_header.IsThereEncryptVer()) - { - if (blockSize <= headerSize) - return S_FALSE; - RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1)); - AddToSeekValue(1); - _header.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize]; - headerSize += 1; - } - if (blockSize < headerSize || - buf[2] != NHeader::NBlockType::kArchiveHeader || - (UInt32)Get16(buf) != (CrcCalc(buf + 2, headerSize - 2) & 0xFFFF)) - return S_FALSE; - - size_t commentSize = blockSize - headerSize; - _comment.SetCapacity(commentSize); - RINOK(ReadStream_FALSE(stream, _comment, commentSize)); - AddToSeekValue(commentSize); - m_Stream = stream; - _header.StartPosition = arcStartPos; - return S_OK; -} - -void CInArchive::GetArchiveInfo(CInArchiveInfo &archiveInfo) const -{ - archiveInfo = _header; -} - -static void DecodeUnicodeFileName(const char *name, const Byte *encName, - int encSize, wchar_t *unicodeName, int maxDecSize) -{ - int encPos = 0; - int decPos = 0; - int flagBits = 0; - Byte flags = 0; - Byte highByte = encName[encPos++]; - while (encPos < encSize && decPos < maxDecSize) - { - if (flagBits == 0) - { - flags = encName[encPos++]; - flagBits = 8; - } - switch(flags >> 6) - { - 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: - { - int length = encName[encPos++]; - if (length & 0x80) - { - Byte correction = encName[encPos++]; - for (length = (length & 0x7f) + 2; - length > 0 && decPos < maxDecSize; length--, decPos++) - unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + (highByte << 8)); - } - else - for (length += 2; length > 0 && decPos < maxDecSize; length--, decPos++) - unicodeName[decPos] = name[decPos]; - } - break; - } - flags <<= 2; - flagBits -= 2; - } - unicodeName[decPos < maxDecSize ? decPos : maxDecSize - 1] = 0; -} - -void CInArchive::ReadName(CItemEx &item, int nameSize) -{ - item.UnicodeName.Empty(); - if (nameSize > 0) - { - m_NameBuffer.EnsureCapacity(nameSize + 1); - char *buffer = (char *)m_NameBuffer; - - for (int i = 0; i < nameSize; i++) - buffer[i] = ReadByte(); - - int mainLen; - for (mainLen = 0; mainLen < nameSize; mainLen++) - if (buffer[mainLen] == '\0') - break; - buffer[mainLen] = '\0'; - item.Name = buffer; - - if(item.HasUnicodeName()) - { - if(mainLen < nameSize) - { - int unicodeNameSizeMax = MyMin(nameSize, (0x400)); - _unicodeNameBuffer.EnsureCapacity(unicodeNameSizeMax + 1); - DecodeUnicodeFileName(buffer, (const Byte *)buffer + mainLen + 1, - nameSize - (mainLen + 1), _unicodeNameBuffer, unicodeNameSizeMax); - item.UnicodeName = _unicodeNameBuffer; - } - else if (!ConvertUTF8ToUnicode(item.Name, item.UnicodeName)) - item.UnicodeName.Empty(); - } - } - else - item.Name.Empty(); -} - -Byte CInArchive::ReadByte() -{ - if (m_CurPos >= m_PosLimit) - throw CInArchiveException(CInArchiveException::kIncorrectArchive); - return m_CurData[m_CurPos++]; -} - -UInt16 CInArchive::ReadUInt16() -{ - UInt16 value = 0; - for (int i = 0; i < 2; i++) - { - Byte b = ReadByte(); - value |= (UInt16(b) << (8 * i)); - } - return value; -} - -UInt32 CInArchive::ReadUInt32() -{ - UInt32 value = 0; - for (int i = 0; i < 4; i++) - { - Byte b = ReadByte(); - value |= (UInt32(b) << (8 * i)); - } - return value; -} - -void CInArchive::ReadTime(Byte mask, CRarTime &rarTime) -{ - rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0); - int numDigits = (mask & 3); - rarTime.SubTime[0] = rarTime.SubTime[1] = rarTime.SubTime[2] = 0; - for (int i = 0; i < numDigits; i++) - rarTime.SubTime[3 - numDigits + i] = ReadByte(); -} - -void CInArchive::ReadHeaderReal(CItemEx &item) -{ - item.Flags = m_BlockHeader.Flags; - item.PackSize = ReadUInt32(); - item.Size = ReadUInt32(); - item.HostOS = ReadByte(); - item.FileCRC = ReadUInt32(); - item.MTime.DosTime = ReadUInt32(); - item.UnPackVersion = ReadByte(); - item.Method = ReadByte(); - int nameSize = ReadUInt16(); - item.Attrib = ReadUInt32(); - - item.MTime.LowSecond = 0; - item.MTime.SubTime[0] = - item.MTime.SubTime[1] = - item.MTime.SubTime[2] = 0; - - if((item.Flags & NHeader::NFile::kSize64Bits) != 0) - { - item.PackSize |= ((UInt64)ReadUInt32() << 32); - item.Size |= ((UInt64)ReadUInt32() << 32); - } - - ReadName(item, nameSize); - - if (item.HasSalt()) - for (int i = 0; i < sizeof(item.Salt); i++) - item.Salt[i] = ReadByte(); - - // some rar archives have HasExtTime flag without field. - if (m_CurPos < m_PosLimit && item.HasExtTime()) - { - Byte accessMask = (Byte)(ReadByte() >> 4); - Byte b = ReadByte(); - Byte modifMask = (Byte)(b >> 4); - Byte createMask = (Byte)(b & 0xF); - if ((modifMask & 8) != 0) - ReadTime(modifMask, item.MTime); - item.CTimeDefined = ((createMask & 8) != 0); - if (item.CTimeDefined) - { - item.CTime.DosTime = ReadUInt32(); - ReadTime(createMask, item.CTime); - } - item.ATimeDefined = ((accessMask & 8) != 0); - if (item.ATimeDefined) - { - item.ATime.DosTime = ReadUInt32(); - ReadTime(accessMask, item.ATime); - } - } - - UInt16 fileHeaderWithNameSize = (UInt16)m_CurPos; - - item.Position = m_Position; - item.MainPartSize = fileHeaderWithNameSize; - item.CommentSize = (UInt16)(m_BlockHeader.HeadSize - fileHeaderWithNameSize); - - if (m_CryptoMode) - item.AlignSize = (UInt16)((16 - ((m_BlockHeader.HeadSize) & 0xF)) & 0xF); - else - item.AlignSize = 0; - AddToSeekValue(m_BlockHeader.HeadSize); -} - -void CInArchive::AddToSeekValue(UInt64 addValue) -{ - m_Position += addValue; -} - -HRESULT CInArchive::GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage) -{ - decryptionError = false; - for (;;) - { - SeekInArchive(m_Position); - if (!m_CryptoMode && (_header.Flags & - NHeader::NArchive::kBlockHeadersAreEncrypted) != 0) - { - m_CryptoMode = false; - if (getTextPassword == 0) - return S_FALSE; - if (!m_RarAES) - { - m_RarAESSpec = new NCrypto::NRar29::CDecoder; - m_RarAES = m_RarAESSpec; - } - m_RarAESSpec->SetRar350Mode(_header.IsEncryptOld()); - - // Salt - const UInt32 kSaltSize = 8; - Byte salt[kSaltSize]; - if(!ReadBytesAndTestSize(salt, kSaltSize)) - return S_FALSE; - m_Position += kSaltSize; - RINOK(m_RarAESSpec->SetDecoderProperties2(salt, kSaltSize)) - // Password - CMyComBSTR password; - RINOK(getTextPassword->CryptoGetTextPassword(&password)) - UString unicodePassword(password); - - CByteBuffer buffer; - const UInt32 sizeInBytes = unicodePassword.Length() * 2; - buffer.SetCapacity(sizeInBytes); - for (int i = 0; i < unicodePassword.Length(); i++) - { - wchar_t c = unicodePassword[i]; - ((Byte *)buffer)[i * 2] = (Byte)c; - ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); - } - - RINOK(m_RarAESSpec->CryptoSetPassword((const Byte *)buffer, sizeInBytes)); - - const UInt32 kDecryptedBufferSize = (1 << 12); - if (m_DecryptedData.GetCapacity() == 0) - { - const UInt32 kAlign = 16; - m_DecryptedData.SetCapacity(kDecryptedBufferSize + kAlign); - m_DecryptedDataAligned = (Byte *)((ptrdiff_t)((Byte *)m_DecryptedData + kAlign - 1) & ~(ptrdiff_t)(kAlign - 1)); - } - RINOK(m_RarAES->Init()); - size_t decryptedDataSizeT = kDecryptedBufferSize; - RINOK(ReadStream(m_Stream, m_DecryptedDataAligned, &decryptedDataSizeT)); - m_DecryptedDataSize = (UInt32)decryptedDataSizeT; - m_DecryptedDataSize = m_RarAES->Filter(m_DecryptedDataAligned, m_DecryptedDataSize); - - m_CryptoMode = true; - m_CryptoPos = 0; - } - - m_FileHeaderData.EnsureCapacity(7); - size_t processed = 7; - RINOK(ReadBytesSpec((Byte *)m_FileHeaderData, &processed)); - if (processed != 7) - { - if (processed != 0) - errorMessage = k_UnexpectedEnd; - return S_FALSE; - } - - m_CurData = (Byte *)m_FileHeaderData; - m_CurPos = 0; - m_PosLimit = 7; - m_BlockHeader.CRC = ReadUInt16(); - m_BlockHeader.Type = ReadByte(); - m_BlockHeader.Flags = ReadUInt16(); - m_BlockHeader.HeadSize = ReadUInt16(); - - if (m_BlockHeader.HeadSize < 7) - ThrowExceptionWithCode(CInArchiveException::kIncorrectArchive); - - if (m_BlockHeader.Type == NHeader::NBlockType::kEndOfArchive) - return S_FALSE; - - if (m_BlockHeader.Type == NHeader::NBlockType::kFileHeader) - { - m_FileHeaderData.EnsureCapacity(m_BlockHeader.HeadSize); - m_CurData = (Byte *)m_FileHeaderData; - m_PosLimit = m_BlockHeader.HeadSize; - if (!ReadBytesAndTestSize(m_CurData + m_CurPos, m_BlockHeader.HeadSize - 7)) - { - errorMessage = k_UnexpectedEnd; - return S_FALSE; - } - - ReadHeaderReal(item); - if ((CrcCalc(m_CurData + 2, - m_BlockHeader.HeadSize - item.CommentSize - 2) & 0xFFFF) != m_BlockHeader.CRC) - ThrowExceptionWithCode(CInArchiveException::kFileHeaderCRCError); - - FinishCryptoBlock(); - m_CryptoMode = false; - SeekInArchive(m_Position); // Move Position to compressed Data; - AddToSeekValue(item.PackSize); // m_Position points to next header; - return S_OK; - } - if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 10)) - { - decryptionError = true; - errorMessage = k_DecryptionError; - return S_FALSE; - } - if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0) - { - m_FileHeaderData.EnsureCapacity(7 + 4); - m_CurData = (Byte *)m_FileHeaderData; - if (!ReadBytesAndTestSize(m_CurData + m_CurPos, 4)) - { - errorMessage = k_UnexpectedEnd; - return S_FALSE; - } - m_PosLimit = 7 + 4; - UInt32 dataSize = ReadUInt32(); - AddToSeekValue(dataSize); - if (m_CryptoMode && dataSize > (1 << 27)) - { - decryptionError = true; - errorMessage = k_DecryptionError; - return S_FALSE; - } - m_CryptoPos = m_BlockHeader.HeadSize; - } - else - m_CryptoPos = 0; - AddToSeekValue(m_BlockHeader.HeadSize); - FinishCryptoBlock(); - m_CryptoMode = false; - } -} - -void CInArchive::SeekInArchive(UInt64 position) -{ - m_Stream->Seek(position, STREAM_SEEK_SET, NULL); -} - -ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size) -{ - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr<ISequentialInStream> inStream(streamSpec); - SeekInArchive(position); - streamSpec->SetStream(m_Stream); - streamSpec->Init(size); - return inStream.Detach(); -} - -}} diff --git a/CPP/7zip/Archive/Rar/RarIn.h b/CPP/7zip/Archive/Rar/RarIn.h deleted file mode 100755 index a6998db2..00000000 --- a/CPP/7zip/Archive/Rar/RarIn.h +++ /dev/null @@ -1,123 +0,0 @@ -// RarIn.h - -#ifndef __ARCHIVE_RAR_IN_H -#define __ARCHIVE_RAR_IN_H - -#include "Common/DynamicBuffer.h" -#include "Common/MyCom.h" - -#include "../../ICoder.h" -#include "../../IStream.h" - -#include "../../Common/StreamObjects.h" - -#include "../../Crypto/RarAes.h" - -#include "RarHeader.h" -#include "RarItem.h" - -namespace NArchive { -namespace NRar { - -class CInArchiveException -{ -public: - enum CCauseType - { - kUnexpectedEndOfArchive = 0, - kArchiveHeaderCRCError, - kFileHeaderCRCError, - kIncorrectArchive - } - Cause; - CInArchiveException(CCauseType cause) : Cause(cause) {} -}; - - -struct CInArchiveInfo -{ - UInt32 Flags; - Byte EncryptVersion; - UInt64 StartPosition; - - bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; } - bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; } - bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; } - bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 0; } - bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; } - bool IsThereEncryptVer() const { return (Flags & NHeader::NArchive::kEncryptVer) != 0; } - bool IsEncryptOld() const { return (!IsThereEncryptVer() || EncryptVersion < 36); } -}; - -class CInArchive -{ - CMyComPtr<IInStream> m_Stream; - - UInt64 m_StreamStartPosition; - - CInArchiveInfo _header; - CDynamicBuffer<char> m_NameBuffer; - CDynamicBuffer<wchar_t> _unicodeNameBuffer; - - CByteBuffer _comment; - - void ReadName(CItemEx &item, int nameSize); - void ReadHeaderReal(CItemEx &item); - - HRESULT ReadBytesSpec(void *data, size_t *size); - bool ReadBytesAndTestSize(void *data, UInt32 size); - - HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit); - - void ThrowExceptionWithCode(CInArchiveException::CCauseType cause); - void ThrowUnexpectedEndOfArchiveException(); - - void AddToSeekValue(UInt64 addValue); - - CDynamicBuffer<Byte> m_FileHeaderData; - - NHeader::NBlock::CBlock m_BlockHeader; - - NCrypto::NRar29::CDecoder *m_RarAESSpec; - CMyComPtr<ICompressFilter> m_RarAES; - - Byte *m_CurData; // it must point to start of Rar::Block - UInt32 m_CurPos; - UInt32 m_PosLimit; - Byte ReadByte(); - UInt16 ReadUInt16(); - UInt32 ReadUInt32(); - void ReadTime(Byte mask, CRarTime &rarTime); - - CBuffer<Byte> m_DecryptedData; - Byte *m_DecryptedDataAligned; - UInt32 m_DecryptedDataSize; - - bool m_CryptoMode; - UInt32 m_CryptoPos; - void FinishCryptoBlock() - { - if (m_CryptoMode) - while ((m_CryptoPos & 0xF) != 0) - { - m_CryptoPos++; - m_Position++; - } - } - -public: - UInt64 m_Position; - - HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit); - void Close(); - HRESULT GetNextItem(CItemEx &item, ICryptoGetTextPassword *getTextPassword, bool &decryptionError, AString &errorMessage); - - void GetArchiveInfo(CInArchiveInfo &archiveInfo) const; - - void SeekInArchive(UInt64 position); - ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size); -}; - -}} - -#endif diff --git a/CPP/7zip/Archive/Rar/RarItem.cpp b/CPP/7zip/Archive/Rar/RarItem.cpp deleted file mode 100755 index 9216ae57..00000000 --- a/CPP/7zip/Archive/Rar/RarItem.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// RarItem.cpp - -#include "StdAfx.h" - -#include "RarItem.h" - -namespace NArchive{ -namespace NRar{ - -bool CItem::IgnoreItem() const -{ - switch(HostOS) - { - case NHeader::NFile::kHostMSDOS: - case NHeader::NFile::kHostOS2: - case NHeader::NFile::kHostWin32: - return ((Attrib & NHeader::NFile::kLabelFileAttribute) != 0); - } - return false; -} - -bool CItem::IsDir() const -{ - if (GetDictSize() == NHeader::NFile::kDictDirectoryValue) - return true; - switch(HostOS) - { - case NHeader::NFile::kHostMSDOS: - case NHeader::NFile::kHostOS2: - case NHeader::NFile::kHostWin32: - if ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) - return true; - } - return false; -} - -UInt32 CItem::GetWinAttributes() const -{ - UInt32 winAttributes; - switch(HostOS) - { - case NHeader::NFile::kHostMSDOS: - case NHeader::NFile::kHostOS2: - case NHeader::NFile::kHostWin32: - winAttributes = Attrib; - break; - default: - winAttributes = 0; // must be converted from unix value; - } - if (IsDir()) - winAttributes |= NHeader::NFile::kWinFileDirectoryAttributeMask; - return winAttributes; -} - -}} diff --git a/CPP/7zip/Archive/Rar/RarItem.h b/CPP/7zip/Archive/Rar/RarItem.h index 4aa4d866..56d25f2c 100755..100644 --- a/CPP/7zip/Archive/Rar/RarItem.h +++ b/CPP/7zip/Archive/Rar/RarItem.h @@ -3,13 +3,12 @@ #ifndef __ARCHIVE_RAR_ITEM_H #define __ARCHIVE_RAR_ITEM_H -#include "Common/Types.h" -#include "Common/MyString.h" +#include "../../../Common/StringConvert.h" #include "RarHeader.h" -namespace NArchive{ -namespace NRar{ +namespace NArchive { +namespace NRar { struct CRarTime { @@ -56,18 +55,35 @@ struct CItem UInt32 GetDictSize() const { return (Flags >> NHeader::NFile::kDictBitStart) & NHeader::NFile::kDictMask; } bool IsDir() const; bool IgnoreItem() const; - UInt32 GetWinAttributes() const; - - CItem(): CTimeDefined(false), ATimeDefined(false) {} -}; + UInt32 GetWinAttrib() const; -class CItemEx: public CItem -{ -public: UInt64 Position; - UInt16 MainPartSize; + unsigned MainPartSize; UInt16 CommentSize; UInt16 AlignSize; + + // int BaseFileIndex; + // bool IsAltStream; + + UString GetName() const + { + if (( /* IsAltStream || */ HasUnicodeName()) && !UnicodeName.IsEmpty()) + return UnicodeName; + return MultiByteToUnicodeString(Name, CP_OEMCP); + } + + void Clear() + { + CTimeDefined = false; + ATimeDefined = false; + Name.Empty(); + UnicodeName.Empty(); + // IsAltStream = false; + // BaseFileIndex = -1; + } + + CItem() { Clear(); } + UInt64 GetFullSize() const { return MainPartSize + CommentSize + AlignSize + PackSize; }; // DWORD GetHeaderWithCommentSize() const { return MainPartSize + CommentSize; }; UInt64 GetCommentPosition() const { return Position + MainPartSize; }; diff --git a/CPP/7zip/Archive/Rar/RarRegister.cpp b/CPP/7zip/Archive/Rar/RarRegister.cpp deleted file mode 100755 index 2bcf569e..00000000 --- a/CPP/7zip/Archive/Rar/RarRegister.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// RarRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "RarHandler.h" -static IInArchive *CreateArc() { return new NArchive::NRar::CHandler; } - -static CArcInfo g_ArcInfo = - { L"Rar", L"rar r00", 0, 3, {0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00}, 7, false, CreateArc, 0, }; - -REGISTER_ARC(Rar) diff --git a/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp b/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp deleted file mode 100755 index 25194f91..00000000 --- a/CPP/7zip/Archive/Rar/RarVolumeInStream.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// RarVolumeInStream.cpp - -#include "StdAfx.h" - -#include "../../../../C/7zCrc.h" - -#include "RarVolumeInStream.h" - -namespace NArchive { -namespace NRar { - -void CFolderInStream::Init( - CObjectVector<CInArchive> *archives, - const CObjectVector<CItemEx> *items, - const CRefItem &refItem) -{ - _archives = archives; - _items = items; - _refItem = refItem; - _curIndex = 0; - CRCs.Clear(); - _fileIsOpen = false; -} - -HRESULT CFolderInStream::OpenStream() -{ - while (_curIndex < _refItem.NumItems) - { - const CItemEx &item = (*_items)[_refItem.ItemIndex + _curIndex]; - _stream.Attach((*_archives)[_refItem.VolumeIndex + _curIndex]. - CreateLimitedStream(item.GetDataPosition(), item.PackSize)); - _curIndex++; - _fileIsOpen = true; - _crc = CRC_INIT_VAL; - return S_OK; - } - return S_OK; -} - -HRESULT CFolderInStream::CloseStream() -{ - CRCs.Add(CRC_GET_DIGEST(_crc)); - _stream.Release(); - _fileIsOpen = false; - return S_OK; -} - -STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) -{ - UInt32 realProcessedSize = 0; - while ((_curIndex < _refItem.NumItems || _fileIsOpen) && size > 0) - { - if (_fileIsOpen) - { - UInt32 localProcessedSize; - RINOK(_stream->Read( - ((Byte *)data) + realProcessedSize, size, &localProcessedSize)); - _crc = CrcUpdate(_crc, ((Byte *)data) + realProcessedSize, localProcessedSize); - if (localProcessedSize == 0) - { - RINOK(CloseStream()); - continue; - } - realProcessedSize += localProcessedSize; - size -= localProcessedSize; - break; - } - else - { - RINOK(OpenStream()); - } - } - if (processedSize != 0) - *processedSize = realProcessedSize; - return S_OK; -} - -}} diff --git a/CPP/7zip/Archive/Rar/RarVolumeInStream.h b/CPP/7zip/Archive/Rar/RarVolumeInStream.h deleted file mode 100755 index 78d95b10..00000000 --- a/CPP/7zip/Archive/Rar/RarVolumeInStream.h +++ /dev/null @@ -1,49 +0,0 @@ -// RarVolumeInStream.h - -#ifndef __RAR_VOLUME_IN_STREAM_H -#define __RAR_VOLUME_IN_STREAM_H - -#include "../../IStream.h" -#include "RarIn.h" - -namespace NArchive { -namespace NRar { - -struct CRefItem -{ - int VolumeIndex; - int ItemIndex; - int NumItems; -}; - -class CFolderInStream: - public ISequentialInStream, - public CMyUnknownImp -{ -public: - MY_UNKNOWN_IMP - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - -private: - CObjectVector<CInArchive> *_archives; - const CObjectVector<CItemEx> *_items; - CRefItem _refItem; - int _curIndex; - UInt32 _crc; - bool _fileIsOpen; - CMyComPtr<ISequentialInStream> _stream; - - HRESULT OpenStream(); - HRESULT CloseStream(); -public: - void Init(CObjectVector<CInArchive> *archives, - const CObjectVector<CItemEx> *items, - const CRefItem &refItem); - - CRecordVector<UInt32> CRCs; -}; - -}} - -#endif diff --git a/CPP/7zip/Archive/Rar/StdAfx.cpp b/CPP/7zip/Archive/Rar/StdAfx.cpp index d0feea85..d0feea85 100755..100644 --- a/CPP/7zip/Archive/Rar/StdAfx.cpp +++ b/CPP/7zip/Archive/Rar/StdAfx.cpp diff --git a/CPP/7zip/Archive/Rar/StdAfx.h b/CPP/7zip/Archive/Rar/StdAfx.h index e7fb6986..2854ff3e 100755..100644 --- a/CPP/7zip/Archive/Rar/StdAfx.h +++ b/CPP/7zip/Archive/Rar/StdAfx.h @@ -3,6 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" +#include "../../../Common/Common.h" #endif diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp index 1d31d451..220bc650 100755..100644 --- a/CPP/7zip/Archive/RpmHandler.cpp +++ b/CPP/7zip/Archive/RpmHandler.cpp @@ -4,10 +4,14 @@ #include "../../../C/CpuArch.h" -#include "Common/ComTry.h" -#include "Common/MyString.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyString.h" +#include "../../Common/StringConvert.h" +#include "../../Common/UTFConvert.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -16,6 +20,8 @@ #include "../Compress/CopyCoder.h" +// #define _SHOW_RPM_METADATA + using namespace NWindows; #define Get16(p) GetBe16(p) @@ -24,130 +30,144 @@ using namespace NWindows; namespace NArchive { namespace NRpm { -/* Reference: lib/signature.h of rpm package */ -#define RPMSIG_NONE 0 /* Do not change! */ -/* The following types are no longer generated */ -#define RPMSIG_PGP262_1024 1 /* No longer generated */ /* 256 byte */ -/* These are the new-style signatures. They are Header structures. */ -/* Inside them we can put any number of any type of signature we like. */ +static const unsigned kNameSize = 66; +static const unsigned kLeadSize = kNameSize + 30; +static const unsigned k_HeaderSig_Size = 16; +static const unsigned k_Entry_Size = 16; -#define RPMSIG_HEADERSIG 5 /* New Header style signature */ +#define RPMSIG_NONE 0 // Old signature +#define RPMSIG_PGP262_1024 1 // Old signature +#define RPMSIG_HEADERSIG 5 // New signature -const UInt32 kLeadSize = 96; -struct CLead +enum { - unsigned char Magic[4]; - unsigned char Major; // not supported ver1, only support 2,3 and lator - unsigned char Minor; - UInt16 Type; - UInt16 ArchNum; - char Name[66]; - UInt16 OSNum; - UInt16 SignatureType; - char Reserved[16]; // pad to 96 bytes -- 8 byte aligned - bool MagicCheck() const - { return Magic[0] == 0xed && Magic[1] == 0xab && Magic[2] == 0xee && Magic[3] == 0xdb; }; + kRpmType_Bin = 0, + kRpmType_Src = 1 }; - -const UInt32 kEntryInfoSize = 16; -/* -struct CEntryInfo + +// There are two sets of TAGs: signature tags and header tags + +// ----- Signature TAGs ----- + +#define RPMSIGTAG_SIZE 1000 // Header + Payload size (32bit) + +// ----- Header TAGs ----- + +#define RPMTAG_NAME 1000 +#define RPMTAG_VERSION 1001 +#define RPMTAG_RELEASE 1002 +#define RPMTAG_BUILDTIME 1006 +#define RPMTAG_OS 1021 // string (old version used int?) +#define RPMTAG_ARCH 1022 // string (old version used int?) +#define RPMTAG_PAYLOADFORMAT 1124 +#define RPMTAG_PAYLOADCOMPRESSOR 1125 +// #define RPMTAG_PAYLOADFLAGS 1126 + +enum { - int Tag; - int Type; - int Offset; // Offset from beginning of data segment, only defined on disk - int Count; + k_EntryType_NULL, + k_EntryType_CHAR, + k_EntryType_INT8, + k_EntryType_INT16, + k_EntryType_INT32, + k_EntryType_INT64, + k_EntryType_STRING, + k_EntryType_BIN, + k_EntryType_STRING_ARRAY, + k_EntryType_I18NSTRING }; -*/ -// case: SignatureType == RPMSIG_HEADERSIG -const UInt32 kCSigHeaderSigSize = 16; -struct CSigHeaderSig +static const char *k_CPUs[] = { - unsigned char Magic[4]; - UInt32 Reserved; - UInt32 IndexLen; // count of index entries - UInt32 DataLen; // number of bytes - bool MagicCheck() - { return Magic[0] == 0x8e && Magic[1] == 0xad && Magic[2] == 0xe8 && Magic[3] == 0x01; }; - UInt32 GetLostHeaderLen() - { return IndexLen * kEntryInfoSize + DataLen; }; + "noarch" + , "i386" + , "alpha" + , "sparc" + , "mips" + , "ppc" + , "m68k" + , "sgi" + , "rs6000" + , "ia64" + , "sparc64" // 10 ??? + , "mipsel" + , "arm" + , "m68kmint" + , "s390" + , "s390x" + , "ppc64" + , "sh" + , "xtensa" + , "aarch64" // 19 }; -static HRESULT RedSigHeaderSig(IInStream *inStream, CSigHeaderSig &h) +static const char *k_OS[] = { - char dat[kCSigHeaderSigSize]; - char *cur = dat; - RINOK(ReadStream_FALSE(inStream, dat, kCSigHeaderSigSize)); - memcpy(h.Magic, cur, 4); - cur += 4; - cur += 4; - h.IndexLen = Get32(cur); - cur += 4; - h.DataLen = Get32(cur); - return S_OK; -} + "0" + , "Linux" + , "Irix" + , "solaris" + , "SunOS" + , "AmigaOS" // AIX + , "HP-UX" + , "osf" + , "FreeBSD" + , "SCO_SV" + , "Irix64" + , "NextStep" + , "bsdi" + , "machten" + , "cygwin32-NT" + , "cygwin32-95" + , "MP_RAS" + , "MiNT" + , "OS/390" + , "VM/ESA" + , "Linux/390" // "Linux/ESA" + , "Darwin" // "MacOSX" 21 +}; -HRESULT OpenArchive(IInStream *inStream) +struct CLead { - UInt64 pos; - char leadData[kLeadSize]; - char *cur = leadData; - CLead lead; - RINOK(ReadStream_FALSE(inStream, leadData, kLeadSize)); - memcpy(lead.Magic, cur, 4); - cur += 4; - lead.Major = *cur++; - lead.Minor = *cur++; - lead.Type = Get16(cur); - cur += 2; - lead.ArchNum = Get16(cur); - cur += 2; - memcpy(lead.Name, cur, sizeof(lead.Name)); - cur += sizeof(lead.Name); - lead.OSNum = Get16(cur); - cur += 2; - lead.SignatureType = Get16(cur); - cur += 2; - - if (!lead.MagicCheck() || lead.Major < 3) - return S_FALSE; + unsigned char Major; + unsigned char Minor; + UInt16 Type; + UInt16 Cpu; + UInt16 Os; + UInt16 SignatureType; + char Name[kNameSize]; + // char Reserved[16]; - CSigHeaderSig sigHeader, header; - if (lead.SignatureType == RPMSIG_NONE) - { - ; - } - else if (lead.SignatureType == RPMSIG_PGP262_1024) + void Parse(const Byte *p) { - UInt64 pos; - RINOK(inStream->Seek(256, STREAM_SEEK_CUR, &pos)); + Major = p[4]; + Minor = p[5]; + Type = Get16(p + 6); + Cpu= Get16(p + 8); + memcpy(Name, p + 10, kNameSize); + p += 10 + kNameSize; + Os = Get16(p); + SignatureType = Get16(p + 2); } - else if (lead.SignatureType == RPMSIG_HEADERSIG) + + bool IsSupported() const { return Major >= 3 && Type <= 1; } +}; + +struct CEntry +{ + UInt32 Tag; + UInt32 Type; + UInt32 Offset; + UInt32 Count; + + void Parse(const Byte *p) { - RINOK(RedSigHeaderSig(inStream, sigHeader)); - if (!sigHeader.MagicCheck()) - return S_FALSE; - UInt32 len = sigHeader.GetLostHeaderLen(); - RINOK(inStream->Seek(len, STREAM_SEEK_CUR, &pos)); - if ((pos % 8) != 0) - { - RINOK(inStream->Seek((pos / 8 + 1) * 8 - pos, - STREAM_SEEK_CUR, &pos)); - } + Tag = Get32(p + 0); + Type = Get32(p + 4); + Offset = Get32(p + 8); + Count = Get32(p + 12); } - else - return S_FALSE; - - RINOK(RedSigHeaderSig(inStream, header)); - if (!header.MagicCheck()) - return S_FALSE; - int headerLen = header.GetLostHeaderLen(); - if (headerLen == -1) - return S_FALSE; - RINOK(inStream->Seek(headerLen, STREAM_SEEK_CUR, &pos)); - return S_OK; -} +}; class CHandler: public IInArchive, @@ -155,104 +175,575 @@ class CHandler: public CMyUnknownImp { CMyComPtr<IInStream> _stream; - UInt64 _pos; + + UInt64 _headersSize; // is equal to start offset of payload data + UInt64 _payloadSize; UInt64 _size; - Byte _sig[4]; + // _size = _payloadSize, if (_payloadSize_Defined) + // _size = (fileSize - _headersSize), if (!_payloadSize_Defined) + UInt64 _phySize; // _headersSize + _payloadSize, if (_phySize_Defined) + UInt32 _headerPlusPayload_Size; + UInt32 _buildTime; + + bool _payloadSize_Defined; + bool _phySize_Defined; + bool _headerPlusPayload_Size_Defined; + bool _time_Defined; + + Byte _payloadSig[6]; // start data of payload + + AString _name; // p7zip + AString _version; // 9.20.1 + AString _release; // 8.1.1 + AString _arch; // x86_64 + AString _os; // linux + + AString _format; // cpio + AString _compressor; // xz, gzip, bzip2 + + CLead _lead; + + #ifdef _SHOW_RPM_METADATA + AString _metadata; + #endif + + void SetTime(NCOM::CPropVariant &prop) const + { + if (_time_Defined && _buildTime != 0) + { + FILETIME ft; + if (NTime::UnixTime64ToFileTime(_buildTime, ft)) + prop = ft; + } + } + + void SetStringProp(const AString &s, NCOM::CPropVariant &prop) const + { + UString us; + if (!ConvertUTF8ToUnicode(s, us)) + us = GetUnicodeString(s); + if (!us.IsEmpty()) + prop = us; + } + + void AddCPU(AString &s) const; + AString GetBaseName() const; + void AddSubFileExtension(AString &res) const; + + HRESULT ReadHeader(ISequentialInStream *stream, bool isMainHeader); + HRESULT Open2(ISequentialInStream *stream); public: MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; -STATPROPSTG kProps[] = +static const Byte kArcProps[] = { - { NULL, kpidSize, VT_UI8} + kpidHeadersSize, + kpidCpu, + kpidHostOS, + kpidCTime + #ifdef _SHOW_RPM_METADATA + , kpidComment + #endif +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidCTime }; IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table +IMP_IInArchive_ArcProps -STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +void CHandler::AddCPU(AString &s) const { - NCOM::CPropVariant prop; - switch(propID) { case kpidMainSubfile: prop = (UInt32)0; break; } - prop.Detach(value); - return S_OK; + if (!_arch.IsEmpty()) + s += _arch; + else + { + if (_lead.Type == kRpmType_Bin) + { + char temp[16]; + const char *p; + if (_lead.Cpu < ARRAY_SIZE(k_CPUs)) + p = k_CPUs[_lead.Cpu]; + else + { + ConvertUInt32ToString(_lead.Cpu, temp); + p = temp; + } + s += p; + } + } } -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) +AString CHandler::GetBaseName() const { - COM_TRY_BEGIN - try + AString s; + if (!_name.IsEmpty()) { - Close(); - if (OpenArchive(inStream) != S_OK) - return S_FALSE; - RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_pos)); - RINOK(ReadStream_FALSE(inStream, _sig, sizeof(_sig) / sizeof(_sig[0]))); - UInt64 endPosition; - RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPosition)); - _size = endPosition - _pos; - _stream = inStream; - return S_OK; + s = _name; + if (!_version.IsEmpty()) + { + s += '-'; + s += _version; + } + if (!_release.IsEmpty()) + { + s += '-'; + s += _release; + } } - catch(...) { return S_FALSE; } - COM_TRY_END + else + { + char *p = s.GetBuffer(kNameSize); + memcpy(p, _lead.Name, kNameSize); + p[kNameSize] = 0; + s.ReleaseBuffer(); + } + + s += '.'; + if (_lead.Type == kRpmType_Src) + s += "src"; + else + AddCPU(s); + return s; } -STDMETHODIMP CHandler::Close() +void CHandler::AddSubFileExtension(AString &res) const { - _stream.Release(); - return S_OK; + if (!_format.IsEmpty()) + res += _format; + else + res += "cpio"; + res += '.'; + + const char *s; + + if (!_compressor.IsEmpty()) + { + s = _compressor; + if (_compressor == "bzip2") + s = "bz2"; + else if (_compressor == "gzip") + s = "gz"; + } + else + { + const Byte *p = _payloadSig; + if (p[0] == 0x1F && p[1] == 0x8B) + s = "gz"; + else if (p[0] == 0xFD && p[1] == '7' && p[2] == 'z' && p[3] == 'X' && p[4] == 'Z' && p[5] == 0) + s = "xz"; + else if (p[0] == 'B' && p[1] == 'Z' && p[2] == 'h' && p[3] >= '1' && p[3] <= '9') + s = "bz2"; + else + s = "lzma"; + } + + res += s; } -STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { - *numItems = 1; + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + + case kpidHeadersSize: prop = _headersSize; break; + case kpidPhySize: if (_phySize_Defined) prop = _phySize; break; + + case kpidMTime: + case kpidCTime: + SetTime(prop); + break; + + case kpidCpu: + { + AString s; + AddCPU(s); + /* + if (_lead.Type == kRpmType_Src) + s = "src"; + */ + SetStringProp(s, prop); + break; + } + + case kpidHostOS: + { + if (!_os.IsEmpty()) + 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; + } + break; + } + + #ifdef _SHOW_RPM_METADATA + case kpidComment: SetStringProp(_metadata, prop); break; + #endif + + case kpidName: + { + AString s = GetBaseName(); + s += ".rpm"; + SetStringProp(s, prop); + break; + } + } + prop.Detach(value); return S_OK; + COM_TRY_END } + STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { NWindows::NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidSize: case kpidPackSize: prop = _size; break; + + case kpidMTime: + case kpidCTime: + SetTime(prop); + break; + + case kpidPath: + { + AString s = GetBaseName(); + s += '.'; + AddSubFileExtension(s); + SetStringProp(s, prop); + break; + } + + /* case kpidExtension: { - char s[32]; - MyStringCopy(s, "cpio."); - const char *ext; - if (_sig[0] == 0x1F && _sig[1] == 0x8B) - ext = "gz"; - else if (_sig[0] == 'B' && _sig[1] == 'Z' && _sig[2] == 'h') - ext = "bz2"; - else - ext = "lzma"; - MyStringCopy(s + MyStringLen(s), ext); - prop = s; + prop = GetSubFileExtension(); break; } + */ } prop.Detach(value); return S_OK; } +#ifdef _SHOW_RPM_METADATA +static inline char GetHex(unsigned value) +{ + return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); +} +#endif + +HRESULT CHandler::ReadHeader(ISequentialInStream *stream, bool isMainHeader) +{ + UInt32 numEntries; + UInt32 dataLen; + { + char buf[k_HeaderSig_Size]; + RINOK(ReadStream_FALSE(stream, buf, k_HeaderSig_Size)); + if (Get32(buf) != 0x8EADE801) // buf[3] = 0x01 - is version + return S_FALSE; + // reserved = Get32(buf + 4); + numEntries = Get32(buf + 8); + dataLen = Get32(buf + 12); + if (numEntries >= 1 << 24) + return S_FALSE; + } + size_t indexSize = (size_t)numEntries * k_Entry_Size; + size_t headerSize = indexSize + dataLen; + if (headerSize < dataLen) + return S_FALSE; + CByteBuffer buffer(headerSize); + RINOK(ReadStream_FALSE(stream, buffer, headerSize)); + + for (UInt32 i = 0; i < numEntries; i++) + { + CEntry entry; + + entry.Parse(buffer + (size_t)i * k_Entry_Size); + if (entry.Offset > dataLen) + return S_FALSE; + + const Byte *p = buffer + indexSize + entry.Offset; + size_t rem = dataLen - entry.Offset; + + if (!isMainHeader) + { + if (entry.Tag == RPMSIGTAG_SIZE && + entry.Type == k_EntryType_INT32) + { + if (rem < 4 || entry.Count != 1) + return S_FALSE; + _headerPlusPayload_Size = Get32(p); + _headerPlusPayload_Size_Defined = true; + } + } + else + { + #ifdef _SHOW_RPM_METADATA + { + char temp[16]; + ConvertUInt32ToString(entry.Tag, temp); + + _metadata += temp; + _metadata += ": "; + } + #endif + + if (entry.Type == k_EntryType_STRING) + { + if (entry.Count != 1) + return S_FALSE; + size_t j; + for (j = 0; j < rem && p[j] != 0; j++); + if (j == rem) + return S_FALSE; + AString s = (const char *)p; + switch (entry.Tag) + { + case RPMTAG_NAME: _name = s; break; + case RPMTAG_VERSION: _version = s; break; + case RPMTAG_RELEASE: _release = s; break; + case RPMTAG_ARCH: _arch = s; break; + case RPMTAG_OS: _os = s; break; + case RPMTAG_PAYLOADFORMAT: _format = s; break; + case RPMTAG_PAYLOADCOMPRESSOR: _compressor = s; break; + } + + #ifdef _SHOW_RPM_METADATA + _metadata += s; + #endif + } + else if (entry.Type == k_EntryType_INT32) + { + if (rem / 4 < entry.Count) + return S_FALSE; + if (entry.Tag == RPMTAG_BUILDTIME) + { + if (entry.Count != 1) + return S_FALSE; + _buildTime = Get32(p); + _time_Defined = true; + } + + #ifdef _SHOW_RPM_METADATA + for (UInt32 t = 0; t < entry.Count; t++) + { + if (t != 0) + _metadata += ' '; + char temp[16]; + ConvertUInt32ToString(Get32(p + t * 4), temp); + _metadata += temp; + } + #endif + } + + #ifdef _SHOW_RPM_METADATA + + else if ( + entry.Type == k_EntryType_STRING_ARRAY || + entry.Type == k_EntryType_I18NSTRING) + { + const Byte *p2 = p; + size_t rem2 = rem; + for (UInt32 t = 0; t < entry.Count; t++) + { + if (rem2 == 0) + return S_FALSE; + if (t != 0) + _metadata += '\n'; + size_t j; + for (j = 0; j < rem2 && p2[j] != 0; j++); + if (j == rem2) + return S_FALSE; + _metadata += (const char *)p2; + j++; + p2 += j; + rem2 -= j; + } + } + else if (entry.Type == k_EntryType_INT16) + { + if (rem / 2 < entry.Count) + return S_FALSE; + for (UInt32 t = 0; t < entry.Count; t++) + { + if (t != 0) + _metadata += ' '; + char temp[16]; + ConvertUInt32ToString(Get16(p + t * 2), temp); + _metadata += temp; + } + } + else if (entry.Type == k_EntryType_BIN) + { + if (rem < entry.Count) + return S_FALSE; + for (UInt32 t = 0; t < entry.Count; t++) + { + const unsigned b = p[t]; + _metadata += GetHex((b >> 4) & 0xF); + _metadata += GetHex(b & 0xF); + } + } + else + { + // p = p; + } + _metadata += '\n'; + #endif + } + } + + headerSize += k_HeaderSig_Size; + _headersSize += headerSize; + if (isMainHeader && _headerPlusPayload_Size_Defined) + { + if (_headerPlusPayload_Size < headerSize) + return S_FALSE; + _payloadSize = _headerPlusPayload_Size - headerSize; + _size = _payloadSize; + _phySize = _headersSize + _payloadSize; + _payloadSize_Defined = true; + _phySize_Defined = true; + } + return S_OK; +} + +HRESULT CHandler::Open2(ISequentialInStream *stream) +{ + { + Byte buf[kLeadSize]; + RINOK(ReadStream_FALSE(stream, buf, kLeadSize)); + if (Get32(buf) != 0xEDABEEDB) + return S_FALSE; + _lead.Parse(buf); + if (!_lead.IsSupported()) + return S_FALSE; + } + + _headersSize = kLeadSize; + + if (_lead.SignatureType == RPMSIG_NONE) + { + ; + } + else if (_lead.SignatureType == RPMSIG_PGP262_1024) + { + Byte temp[256]; + RINOK(ReadStream_FALSE(stream, temp, sizeof(temp))); + } + else if (_lead.SignatureType == RPMSIG_HEADERSIG) + { + RINOK(ReadHeader(stream, false)); + unsigned pos = (unsigned)_headersSize & 7; + if (pos != 0) + { + Byte temp[8]; + unsigned num = 8 - pos; + RINOK(ReadStream_FALSE(stream, temp, num)); + _headersSize += num; + } + } + else + return S_FALSE; + + return ReadHeader(stream, true); +} + + +STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *) +{ + COM_TRY_BEGIN + { + Close(); + RINOK(Open2(inStream)); + + // start of payload is allowed to be unaligned + RINOK(ReadStream_FALSE(inStream, _payloadSig, sizeof(_payloadSig))); + + if (!_payloadSize_Defined) + { + UInt64 endPos; + RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); + _size = endPos - _headersSize; + } + _stream = inStream; + return S_OK; + } + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _headersSize = 0; + _payloadSize = 0; + _size = 0; + _phySize = 0; + _headerPlusPayload_Size = 0; + + _payloadSize_Defined = false; + _phySize_Defined = false; + _headerPlusPayload_Size_Defined = false; + _time_Defined = false; + + _name.Empty(); + _version.Empty(); + _release.Empty(); + _arch.Empty(); + _os.Empty(); + + _format.Empty(); + _compressor.Empty(); + + #ifdef _SHOW_RPM_METADATA + _metadata.Empty(); + #endif + + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN if (numItems == 0) return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; RINOK(extractCallback->SetTotal(_size)); + CMyComPtr<ISequentialOutStream> outStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : @@ -262,30 +753,38 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, return S_OK; RINOK(extractCallback->PrepareOperation(askMode)); - CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder; + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); - RINOK(_stream->Seek(_pos, STREAM_SEEK_SET, NULL)); - RINOK(copyCoder->Code(_stream, outStream, NULL, NULL, progress)); + RINOK(_stream->Seek(_headersSize, STREAM_SEEK_SET, NULL)); + RINOK(copyCoder->Code(_stream, outStream, NULL, &_size, progress)); outStream.Release(); - return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK); + Int32 opRes = NExtract::NOperationResult::kOK; + if (copyCoderSpec->TotalSize < _size) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + return extractCallback->SetOperationResult(opRes); COM_TRY_END } STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) { COM_TRY_BEGIN - return CreateLimitedInStream(_stream, _pos, _size, stream); + return CreateLimitedInStream(_stream, _headersSize, _size, stream); COM_TRY_END } -static IInArchive *CreateArc() { return new NArchive::NRpm::CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"Rpm", L"rpm", 0, 0xEB, { 0xED, 0xAB, 0xEE, 0xDB}, 4, false, CreateArc, 0 }; + { "Rpm", "rpm", 0, 0xEB, + 4, { 0xED, 0xAB, 0xEE, 0xDB}, + 0, + 0, + CreateArc }; REGISTER_ARC(Rpm) diff --git a/CPP/7zip/Archive/SplitHandler.cpp b/CPP/7zip/Archive/SplitHandler.cpp index 5d84de4e..19dc1b47 100755..100644 --- a/CPP/7zip/Archive/SplitHandler.cpp +++ b/CPP/7zip/Archive/SplitHandler.cpp @@ -2,10 +2,10 @@ #include "StdAfx.h" -#include "Common/ComTry.h" -#include "Common/MyString.h" +#include "../../Common/ComTry.h" +#include "../../Common/MyString.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" @@ -19,15 +19,16 @@ using namespace NWindows; namespace NArchive { namespace NSplit { -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8} + kpidPath, + kpidSize }; -STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidNumVolumes, VT_UI4} + kpidNumVolumes, + kpidTotalPhySize }; class CHandler: @@ -35,10 +36,12 @@ class CHandler: public IInArchiveGetStream, public CMyUnknownImp { - UString _subName; CObjectVector<CMyComPtr<IInStream> > _streams; CRecordVector<UInt64> _sizes; + UString _subName; UInt64 _totalSize; + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); public: MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) @@ -51,9 +54,11 @@ IMP_IInArchive_ArcProps STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidMainSubfile: prop = (UInt32)0; break; + case kpidPhySize: if (!_sizes.IsEmpty()) prop = _sizes[0]; break; + case kpidTotalPhySize: prop = _totalSize; break; case kpidNumVolumes: prop = (UInt32)_streams.Size(); break; } prop.Detach(value); @@ -72,20 +77,18 @@ struct CSeqName if (_splitStyle) { int i; - int numLetters = _changedPart.Length(); + int numLetters = _changedPart.Len(); for (i = numLetters - 1; i >= 0; i--) { wchar_t c = _changedPart[i]; if (c == 'z') { - c = 'a'; - newName = c + newName; + newName.InsertAtFront('a'); continue; } else if (c == 'Z') { - c = 'A'; - newName = c + newName; + newName.InsertAtFront('A'); continue; } c++; @@ -99,33 +102,32 @@ struct CSeqName newName += newChar; break; } - newName = c + newName; + newName.InsertAtFront(c); i--; for (; i >= 0; i--) - newName = _changedPart[i] + newName; + newName.InsertAtFront(_changedPart[i]); break; } } else { int i; - int numLetters = _changedPart.Length(); + int numLetters = _changedPart.Len(); for (i = numLetters - 1; i >= 0; i--) { wchar_t c = _changedPart[i]; - if (c == L'9') + if (c == '9') { - c = L'0'; - newName = c + newName; + newName.InsertAtFront('0'); if (i == 0) - newName = UString(L'1') + newName; + newName.InsertAtFront('1'); continue; } c++; - newName = c + newName; + newName.InsertAtFront(c); i--; for (; i >= 0; i--) - newName = _changedPart[i] + newName; + newName.InsertAtFront(_changedPart[i]); break; } } @@ -134,142 +136,139 @@ struct CSeqName } }; -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback *openArchiveCallback) +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) { - COM_TRY_BEGIN Close(); - if (openArchiveCallback == 0) + if (!callback) return S_FALSE; - // try + + CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback; + callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback); + if (!volumeCallback) + return S_FALSE; + + UString name; { - CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; - CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openArchiveCallback; - if (openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, - &openVolumeCallback) != S_OK) + NCOM::CPropVariant prop; + RINOK(volumeCallback->GetProperty(kpidName, &prop)); + if (prop.vt != VT_BSTR) return S_FALSE; - - UString name; - { - NCOM::CPropVariant prop; - RINOK(openVolumeCallback->GetProperty(kpidName, &prop)); - if (prop.vt != VT_BSTR) - return S_FALSE; - name = prop.bstrVal; - } - - int dotPos = name.ReverseFind('.'); - UString prefix, ext; - if (dotPos >= 0) - { - prefix = name.Left(dotPos + 1); - ext = name.Mid(dotPos + 1); - } - else - ext = name; - UString extBig = ext; - extBig.MakeUpper(); - - CSeqName seqName; - - int numLetters = 2; - bool splitStyle = false; - if (extBig.Right(2) == L"AA") + name = prop.bstrVal; + } + + int dotPos = name.ReverseFind('.'); + const UString prefix = name.Left(dotPos + 1); + const UString ext = name.Ptr(dotPos + 1); + UString ext2 = ext; + ext2.MakeLower_Ascii(); + + CSeqName seqName; + + unsigned numLetters = 2; + bool splitStyle = false; + + if (ext2.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "aa")) + { + splitStyle = true; + while (numLetters < ext2.Len()) { - splitStyle = true; - while (numLetters < extBig.Length()) - { - if (extBig[extBig.Length() - numLetters - 1] != 'A') - break; - numLetters++; - } + if (ext2[ext2.Len() - numLetters - 1] != 'a') + break; + numLetters++; } - else if (ext.Right(2) == L"01") + } + else if (ext.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "01")) + { + while (numLetters < ext2.Len()) { - while (numLetters < extBig.Length()) - { - if (extBig[extBig.Length() - numLetters - 1] != '0') - break; - numLetters++; - } - if (numLetters != ext.Length()) - return S_FALSE; + if (ext2[ext2.Len() - numLetters - 1] != '0') + break; + numLetters++; } - else + if (numLetters != ext.Len()) return S_FALSE; - - _streams.Add(stream); - - seqName._unchangedPart = prefix + ext.Left(extBig.Length() - numLetters); - seqName._changedPart = ext.Right(numLetters); - seqName._splitStyle = splitStyle; - - if (prefix.Length() < 1) - _subName = L"file"; - else - _subName = prefix.Left(prefix.Length() - 1); - - _totalSize = 0; - UInt64 size; + } + else + return S_FALSE; + + seqName._unchangedPart = prefix + ext.Left(ext2.Len() - numLetters); + seqName._changedPart = ext.RightPtr(numLetters); + seqName._splitStyle = splitStyle; + + if (prefix.Len() < 1) + _subName = L"file"; + else + _subName.SetFrom(prefix, prefix.Len() - 1); + + UInt64 size; + { + NCOM::CPropVariant prop; + RINOK(volumeCallback->GetProperty(kpidSize, &prop)); + if (prop.vt != VT_UI8) + return E_INVALIDARG; + size = prop.uhVal.QuadPart; + } + + _totalSize += size; + _sizes.Add(size); + _streams.Add(stream); + + { + UInt64 numFiles = _streams.Size(); + RINOK(callback->SetCompleted(&numFiles, NULL)); + } + + for (;;) + { + const UString fullName = seqName.GetNextName(); + CMyComPtr<IInStream> nextStream; + HRESULT result = volumeCallback->GetStream(fullName, &nextStream); + if (result == S_FALSE) + break; + if (result != S_OK) + return result; + if (!stream) + break; { NCOM::CPropVariant prop; - RINOK(openVolumeCallback->GetProperty(kpidSize, &prop)); + RINOK(volumeCallback->GetProperty(kpidSize, &prop)); if (prop.vt != VT_UI8) return E_INVALIDARG; size = prop.uhVal.QuadPart; } _totalSize += size; _sizes.Add(size); - - if (openArchiveCallback != NULL) + _streams.Add(nextStream); { UInt64 numFiles = _streams.Size(); - RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL)); - } - - for (;;) - { - UString fullName = seqName.GetNextName(); - CMyComPtr<IInStream> nextStream; - HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream); - if (result == S_FALSE) - break; - if (result != S_OK) - return result; - if (!stream) - break; - { - NCOM::CPropVariant prop; - RINOK(openVolumeCallback->GetProperty(kpidSize, &prop)); - if (prop.vt != VT_UI8) - return E_INVALIDARG; - size = prop.uhVal.QuadPart; - } - _totalSize += size; - _sizes.Add(size); - _streams.Add(nextStream); - if (openArchiveCallback != NULL) - { - UInt64 numFiles = _streams.Size(); - RINOK(openArchiveCallback->SetCompleted(&numFiles, NULL)); - } + RINOK(callback->SetCompleted(&numFiles, NULL)); } } - /* - catch(...) + + if (_streams.Size() == 1) { - return S_FALSE; + if (splitStyle) + return S_FALSE; } - */ return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + HRESULT res = Open2(stream, callback); + if (res != S_OK) + Close(); + return res; COM_TRY_END } STDMETHODIMP CHandler::Close() { - _sizes.Clear(); + _totalSize = 0; + _subName.Empty(); _streams.Clear(); + _sizes.Clear(); return S_OK; } @@ -281,8 +280,8 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { - NWindows::NCOM::CPropVariant prop; - switch(propID) + NCOM::CPropVariant prop; + switch (propID) { case kpidPath: prop = _subName; break; case kpidSize: @@ -300,7 +299,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_BEGIN if (numItems == 0) return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; UInt64 currentTotalSize = 0; @@ -321,7 +320,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); - for (int i = 0; i < _streams.Size(); i++) + FOR_VECTOR (i, _streams) { lps->InSize = lps->OutSize = currentTotalSize; RINOK(lps->SetCur()); @@ -343,7 +342,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) *stream = 0; CMultiStream *streamSpec = new CMultiStream; CMyComPtr<ISequentialInStream> streamTemp = streamSpec; - for (int i = 0; i < _streams.Size(); i++) + FOR_VECTOR (i, _streams) { CMultiStream::CSubStreamInfo subStreamInfo; subStreamInfo.Stream = _streams[i]; @@ -356,10 +355,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = -{ L"Split", L"001", 0, 0xEA, { 0 }, 0, false, CreateArc, 0 }; + { "Split", "001", 0, 0xEA, + 0, { 0 }, + 0, + 0, + CreateArc }; REGISTER_ARC(Split) diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp index efaffed1..617a1d66 100755..100644 --- a/CPP/7zip/Archive/SquashfsHandler.cpp +++ b/CPP/7zip/Archive/SquashfsHandler.cpp @@ -7,12 +7,12 @@ #include "../../../C/CpuArch.h" #include "../../../C/Xz.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/StringConvert.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/StringConvert.h" -#include "Windows/PropVariantUtils.h" -#include "Windows/Time.h" +#include "../../Windows/PropVariantUtils.h" +#include "../../Windows/TimeUtils.h" #include "../Common/CWrappers.h" #include "../Common/LimitedStreams.h" @@ -59,8 +59,6 @@ UInt64 Get64b(const Byte *p, bool be) { return be ? GetBe64(p) : GetUi64(p); } #define GET_32(offs, dest) dest = Get32(p + (offs)); #define GET_64(offs, dest) dest = Get64(p + (offs)); -static const UInt32 kSignatureSize = 4; -#define SIGNATURE { 'h', 's', 'q', 's' } static const UInt32 kSignature32_LE = 0x73717368; static const UInt32 kSignature32_BE = 0x68737173; static const UInt32 kSignature32_LZ = 0x71736873; @@ -72,11 +70,11 @@ static const UInt32 kSignature32_LZ = 0x71736873; static const char *k_Methods[] = { - "Unknown", - "ZLIB", - "LZMA", - "LZO", - "XZ" + "Unknown" + , "ZLIB" + , "LZMA" + , "LZO" + , "XZ" }; static const UInt32 kMetadataBlockSizeLog = 13; @@ -315,17 +313,17 @@ UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h) UInt16 t = Get16(p); if (be) { - Type = t >> 12; - Mode = t & 0xFFF; - Uid = p[2] >> 4; - Gid = p[2] & 0xF; + Type = (UInt16)(t >> 12); + Mode = (UInt16)(t & 0xFFF); + Uid = (UInt16)(p[2] >> 4); + Gid = (UInt16)(p[2] & 0xF); } else { - Type = t & 0xF; - Mode = t >> 4; - Uid = p[2] & 0xF; - Gid = p[2] >> 4; + Type = (UInt16)(t & 0xF); + Mode = (UInt16)(t >> 4); + Uid = (UInt16)(p[2] & 0xF); + Gid = (UInt16)(p[2] >> 4); } // Xattr = kXattr_Empty; @@ -339,20 +337,20 @@ UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h) Byte t = p[3]; if (be) { - Type = t >> 4; - Offset = t & 0xF; + Type = (UInt16)(t >> 4); + Offset = (UInt16)(t & 0xF); } else { - Type = t & 0xF; - Offset = t >> 4; + Type = (UInt16)(t & 0xF); + Offset = (UInt16)(t >> 4); } return (Type == kType_FIFO || Type == kType_SOCK) ? 4 : 0; } Type--; - Uid += (Type / 5) * 16; - Type = (Type % 5) + 1; + Uid = (UInt16)(Uid + (Type / 5) * 16); + Type = (UInt16)((Type % 5) + 1); if (Type == kType_FILE) { @@ -418,13 +416,13 @@ UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h) UInt16 t = Get16(p); if (be) { - Type = t >> 12; - Mode = t & 0xFFF; + Type = (UInt16)(t >> 12); + Mode = (UInt16)(t & 0xFFF); } else { - Type = t & 0xF; - Mode = t >> 4; + Type = (UInt16)(t & 0xF); + Mode = (UInt16)(t >> 4); } Uid = p[2]; Gid = p[3]; @@ -548,13 +546,13 @@ UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h) UInt16 t = Get16(p); if (be) { - Type = t >> 12; - Mode = t & 0xFFF; + Type = (UInt16)(t >> 12); + Mode = (UInt16)(t & 0xFFF); } else { - Type = t & 0xF; - Mode = t >> 4; + Type = (UInt16)(t & 0xF); + Mode = (UInt16)(t >> 4); } Uid = p[2]; Gid = p[3]; @@ -841,6 +839,8 @@ class CHandler: // CByteBuffer _uids; // CByteBuffer _gids; CHeader _h; + bool _noPropsLZMA; + bool _needCheckLzma; CMyComPtr<IInStream> _stream; UInt64 _sizeCalculated; @@ -922,31 +922,30 @@ CHandler::CHandler() _dynOutStream = _dynOutStreamSpec; } -static const STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidPosixAttrib, VT_UI4} - // { NULL, kpidUser, VT_BSTR}, - // { NULL, kpidGroup, VT_BSTR}, - // { NULL, kpidLinks, VT_UI4}, - // { NULL, kpidOffset, VT_UI4} + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidPosixAttrib + // kpidUser, + // kpidGroup, + // kpidLinks, + // kpidOffset }; -static const STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidFileSystem, VT_BSTR}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidBlock, VT_UI4}, - { NULL, kpidPhySize, VT_UI8}, - { NULL, kpidHeadersSize, VT_UI8}, - { NULL, kpidBigEndian, VT_BOOL}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidCharacts, VT_BSTR} - // { NULL, kpidNumBlocks, VT_UI4} + kpidHeadersSize, + kpidFileSystem, + kpidMethod, + kpidBlock, + kpidBigEndian, + kpidCTime, + kpidCharacts + // kpidNumBlocks }; IMP_IInArchive_Props @@ -1115,12 +1114,25 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool UInt32 method = _h.Method; if (_h.SeveralMethods) { - Byte props[1]; - RINOK(ReadStream_FALSE(_stream, props, 1)); - method = (props[0] == 0x5D ? kMethod_LZMA : kMethod_ZLIB); + Byte b; + RINOK(ReadStream_FALSE(_stream, &b, 1)); RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL)); + method = (b == 0x5D ? kMethod_LZMA : kMethod_ZLIB); } + if (method == kMethod_ZLIB && _needCheckLzma) + { + Byte b; + RINOK(ReadStream_FALSE(_stream, &b, 1)); + RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL)); + if (b == 0) + { + _noPropsLZMA = true; + method = _h.Method = kMethod_LZMA; + } + _needCheckLzma = false; + } + if (method == kMethod_ZLIB) { if (!_zlibDecoder) @@ -1140,24 +1152,34 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool _lzmaDecoderSpec->FinishStream = true; _lzmaDecoder = _lzmaDecoderSpec; } - const UInt32 kPropsSize = 5 + 8; + const UInt32 kPropsSize = LZMA_PROPS_SIZE + 8; Byte props[kPropsSize]; - ReadStream_FALSE(_limitedInStream, props, kPropsSize); - RINOK(_lzmaDecoderSpec->SetDecoderProperties2(props, 5)); - UInt64 outSize = GetUi64(props + 5); - if (outSize > outSizeMax) - return S_FALSE; + UInt32 propsSize; + UInt64 outSize; + if (_noPropsLZMA) + { + props[0] = 0x5D; + SetUi32(&props[1], _h.BlockSize); + propsSize = 0; + outSize = outSizeMax; + } + else + { + RINOK(ReadStream_FALSE(_limitedInStream, props, kPropsSize)); + propsSize = kPropsSize; + outSize = GetUi64(&props[LZMA_PROPS_SIZE]); + if (outSize > outSizeMax) + return S_FALSE; + } + RINOK(_lzmaDecoderSpec->SetDecoderProperties2(props, LZMA_PROPS_SIZE)); RINOK(_lzmaDecoder->Code(_limitedInStream, outStream, NULL, &outSize, NULL)); - if (inSize != kPropsSize + _lzmaDecoderSpec->GetInputProcessedSize()) + if (inSize != propsSize + _lzmaDecoderSpec->GetInputProcessedSize()) return S_FALSE; } else { - if (_inputBuffer.GetCapacity() < inSize) - { - _inputBuffer.Free(); - _inputBuffer.SetCapacity(inSize); - } + if (_inputBuffer.Size() < inSize) + _inputBuffer.Alloc(inSize); RINOK(ReadStream_FALSE(_stream, _inputBuffer, inSize)); Byte *dest = outBuf; @@ -1287,22 +1309,23 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned if (blockIndex < 0) return S_FALSE; unpackPos = _dirs.UnpackPos[blockIndex] + n.Offset; - if (unpackPos < n.Offset || unpackPos > _dirs.Data.GetCapacity()) + if (unpackPos < n.Offset || unpackPos > _dirs.Data.Size()) return S_FALSE; - UInt32 rem = (UInt32)_dirs.Data.GetCapacity() - unpackPos; + UInt32 rem = (UInt32)_dirs.Data.Size() - unpackPos; const Byte *p = _dirs.Data + unpackPos; UInt32 fileSize = (UInt32)n.FileSize; - if (fileSize > rem) - return S_FALSE; - rem = fileSize; + // for some squashfs files: fileSize = rem + 3 !!! if (_h.Major >= 3) { - if (rem < 3) + if (fileSize < 3) return S_FALSE; - rem -= 3; + fileSize -= 3; } + if (fileSize > rem) + return S_FALSE; + rem = fileSize; CRecordVector<CTempItem> tempItems; while (rem != 0) @@ -1412,7 +1435,7 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned } int startItemIndex = _items.Size() - tempItems.Size(); - for (int i = 0; i < tempItems.Size(); i++) + FOR_VECTOR (i, tempItems) { const CTempItem &tempItem = tempItems[i]; int index = startItemIndex + i; @@ -1443,9 +1466,11 @@ HRESULT CHandler::Open2(IInStream *inStream) if (!_h.IsSupported()) return E_NOTIMPL; + _noPropsLZMA = false; + _needCheckLzma = false; switch (_h.Method) { - case kMethod_ZLIB: + case kMethod_ZLIB: _needCheckLzma = true; break; case kMethod_LZMA: case kMethod_LZO: case kMethod_XZ: @@ -1461,14 +1486,13 @@ HRESULT CHandler::Open2(IInStream *inStream) { if (_h.NumFrags > kNumFilesMax) return S_FALSE; - _frags.Reserve(_h.NumFrags); - CByteBuffer data; + _frags.ClearAndReserve(_h.NumFrags); unsigned bigFrag = (_h.Major > 2); unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag); UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog; size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag); - data.SetCapacity(numBlocksBytes); + CByteBuffer data(numBlocksBytes); RINOK(inStream->Seek(_h.FragTable, STREAM_SEEK_SET, NULL)); RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); bool be = _h.be; @@ -1518,11 +1542,11 @@ HRESULT CHandler::Open2(IInStream *inStream) return S_FALSE; { UInt32 pos = 0; - UInt32 totalSize = (UInt32)_inodesData.Data.GetCapacity(); - _nodesPos.Reserve(_h.NumInodes); - _nodes.Reserve(_h.NumInodes); + UInt32 totalSize = (UInt32)_inodesData.Data.Size(); + _nodesPos.ClearAndReserve(_h.NumInodes); + _nodes.ClearAndReserve(_h.NumInodes); // we use _blockToNode for binary search seed optimizations - _blockToNode.Reserve(_inodesData.GetNumBlocks() + 1); + _blockToNode.ClearAndReserve(_inodesData.GetNumBlocks() + 1); int curBlock = 0; for (UInt32 i = 0; i < _h.NumInodes; i++) { @@ -1544,8 +1568,8 @@ HRESULT CHandler::Open2(IInStream *inStream) _blockToNode.Add(_nodesPos.Size()); curBlock++; } - _nodesPos.Add(pos); - _nodes.Add(n); + _nodesPos.AddInReserved(pos); + _nodes.AddInReserved(n); pos += size; } _blockToNode.Add(_nodesPos.Size()); @@ -1657,7 +1681,6 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb HRESULT res; try { - RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); _openCallback = callback; res = Open2(stream); } @@ -1679,6 +1702,8 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb STDMETHODIMP CHandler::Close() { + _sizeCalculated = 0; + _limitedInStreamSpec->ReleaseStream(); _stream.Release(); @@ -1801,12 +1826,14 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidMethod: { const char *s; - if (_h.SeveralMethods) + if (_noPropsLZMA) + s = "LZMA Spec"; + else if (_h.SeveralMethods) s = "LZMA ZLIB"; else { s = k_Methods[0]; - if (_h.Method < sizeof(k_Methods) / sizeof(k_Methods[0])) + if (_h.Method < ARRAY_SIZE(k_Methods)) s = k_Methods[_h.Method]; } prop = s; @@ -1906,7 +1933,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } case kpidPosixAttrib: { - if (node.Type != 0 && node.Type < sizeof(k_TypeToMode) / sizeof(k_TypeToMode[0])) + if (node.Type != 0 && node.Type < ARRAY_SIZE(k_TypeToMode)) prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type]; break; } @@ -1914,7 +1941,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidUser: { UInt32 offset = node.Uid * 4; - if (offset < _uids.GetCapacity()) + if (offset < _uids.Size()) prop = (UInt32)Get32(_uids + offset); break; } @@ -1923,13 +1950,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (_h.Major == 4 || node.Gid == _h.GetSpecGuidIndex()) { UInt32 offset = node.Uid * 4; - if (offset < _uids.GetCapacity()) + if (offset < _uids.Size()) prop = (UInt32)Get32(_uids + offset); } else { UInt32 offset = node.Gid * 4; - if (offset < _gids.GetCapacity()) + if (offset < _gids.Size()) prop = (UInt32)Get32(_gids + offset); } break; @@ -2028,7 +2055,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (numItems == 0) @@ -2095,7 +2122,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { if (hres == E_OUTOFMEMORY) return hres; - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; } else { @@ -2110,7 +2137,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } else if (hres == E_NOTIMPL) { - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; } else if(hres != S_FALSE) { @@ -2157,10 +2184,10 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) _nodeIndex = item.Node; size_t cacheSize = _h.BlockSize; - if (_cachedBlock.GetCapacity() != cacheSize) + if (_cachedBlock.Size() != cacheSize) { ClearCache(); - _cachedBlock.SetCapacity(cacheSize); + _cachedBlock.Alloc(cacheSize); } CSquashfsInStream *streamSpec = new CSquashfsInStream; @@ -2179,10 +2206,19 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -static IInArchive *CreateArc() { return new NArchive::NSquashfs::CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"SquashFS", L"squashfs", 0, 0xD2, SIGNATURE, kSignatureSize, false, CreateArc, 0 }; + { "SquashFS", "squashfs", 0, 0xD2, + 3 * (1 + 4), + { + 4, 'h', 's', 'q', 's', + 4, 's', 'q', 's', 'h', + 4, 's', 'h', 's', 'q', + }, + 0, + NArcInfoFlags::kMultiSignature, + CreateArc }; REGISTER_ARC(Cramfs) diff --git a/CPP/7zip/Archive/StdAfx.h b/CPP/7zip/Archive/StdAfx.h index ef555ec1..1cbd7fea 100755..100644 --- a/CPP/7zip/Archive/StdAfx.h +++ b/CPP/7zip/Archive/StdAfx.h @@ -3,7 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../Common/MyWindows.h" -#include "../../Common/NewHandler.h" +#include "../../Common/Common.h" #endif diff --git a/CPP/7zip/Archive/SwfHandler.cpp b/CPP/7zip/Archive/SwfHandler.cpp index d7d9537e..7cfea330 100755..100644 --- a/CPP/7zip/Archive/SwfHandler.cpp +++ b/CPP/7zip/Archive/SwfHandler.cpp @@ -4,19 +4,23 @@ #include "../../../C/CpuArch.h" -#include "Common/Buffer.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/MyString.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/MyString.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" #include "../Common/InBuffer.h" +#include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" #include "../Common/StreamUtils.h" #include "../Compress/CopyCoder.h" +#include "../Compress/LzmaDecoder.h" +#include "../Compress/LzmaEncoder.h" #include "../Compress/ZlibDecoder.h" #include "../Compress/ZlibEncoder.h" @@ -26,33 +30,120 @@ using namespace NWindows; namespace NArchive { + +static const UInt32 kFileSizeMax = (UInt32)1 << 29; + namespace NSwfc { -static const UInt32 kHeaderSize = 8; +static const unsigned kHeaderBaseSize = 8; +static const unsigned kHeaderLzmaSize = 17; static const Byte SWF_UNCOMPRESSED = 'F'; -static const Byte SWF_COMPRESSED = 'C'; -static const Byte SWF_MIN_COMPRESSED_VER = 6; +static const Byte SWF_COMPRESSED_ZLIB = 'C'; +static const Byte SWF_COMPRESSED_LZMA = 'Z'; + +static const Byte SWF_MIN_COMPRESSED_ZLIB_VER = 6; +static const Byte SWF_MIN_COMPRESSED_LZMA_VER = 13; + +static const Byte kVerLim = 20; + +API_FUNC_static_IsArc IsArc_Swf(const Byte *p, size_t size) +{ + if (size < kHeaderBaseSize) + return k_IsArc_Res_NEED_MORE; + if (p[0] != SWF_UNCOMPRESSED || + p[1] != 'W' || + p[2] != 'S' || + p[3] >= kVerLim) + return k_IsArc_Res_NO; + UInt32 uncompressedSize = GetUi32(p + 4); + if (uncompressedSize > kFileSizeMax) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} + +API_FUNC_static_IsArc IsArc_Swfc(const Byte *p, size_t size) +{ + if (size < kHeaderBaseSize + 2 + 1) // 2 + 1 (for zlib check) + return k_IsArc_Res_NEED_MORE; + if ((p[0] != SWF_COMPRESSED_ZLIB && + p[0] != SWF_COMPRESSED_LZMA) || + p[1] != 'W' || + p[2] != 'S' || + p[3] >= kVerLim) + return k_IsArc_Res_NO; + UInt32 uncompressedSize = GetUi32(p + 4); + if (uncompressedSize > kFileSizeMax) + return k_IsArc_Res_NO; + + if (p[0] == SWF_COMPRESSED_ZLIB) + { + if (!NCompress::NZlib::IsZlib_3bytes(p + 8)) + return k_IsArc_Res_NO; + } + else + { + if (size < kHeaderLzmaSize + 2) + return k_IsArc_Res_NEED_MORE; + if (p[kHeaderLzmaSize] != 0 || + (p[kHeaderLzmaSize + 1] & 0x80) != 0) + return k_IsArc_Res_NO; + UInt32 lzmaPackSize = GetUi32(p + 8); + UInt32 lzmaProp = p[12]; + UInt32 lzmaDicSize = GetUi32(p + 13); + if (lzmaProp > 5 * 5 * 9 || + lzmaDicSize > ((UInt32)1 << 28) || + lzmaPackSize < 5 || + lzmaPackSize > ((UInt32)1 << 28)) + return k_IsArc_Res_NO; + } + + return k_IsArc_Res_YES; +} struct CItem { - Byte Buf[kHeaderSize]; + Byte Buf[kHeaderLzmaSize]; + unsigned HeaderSize; UInt32 GetSize() const { return GetUi32(Buf + 4); } - bool IsSwf(Byte c) const { return (Buf[0] == c && Buf[1] == 'W' && Buf[2] == 'S' && Buf[3] < 32); } - bool IsUncompressed() const { return IsSwf(SWF_UNCOMPRESSED); } - bool IsCompressed() const { return IsSwf(SWF_COMPRESSED); } + UInt32 GetLzmaPackSize() const { return GetUi32(Buf + 8); } + UInt32 GetLzmaDicSize() const { return GetUi32(Buf + 13); } - void MakeUncompressed() { Buf[0] = SWF_UNCOMPRESSED; } - void MakeCompressed() + bool IsSwf() const { return (Buf[1] == 'W' && Buf[2] == 'S' && Buf[3] < kVerLim); } + bool IsUncompressed() const { return Buf[0] == SWF_UNCOMPRESSED; } + bool IsZlib() const { return Buf[0] == SWF_COMPRESSED_ZLIB; } + bool IsLzma() const { return Buf[0] == SWF_COMPRESSED_LZMA; } + + void MakeUncompressed() + { + Buf[0] = SWF_UNCOMPRESSED; + HeaderSize = kHeaderBaseSize; + } + void MakeZlib() + { + Buf[0] = SWF_COMPRESSED_ZLIB; + if (Buf[3] < SWF_MIN_COMPRESSED_ZLIB_VER) + Buf[3] = SWF_MIN_COMPRESSED_ZLIB_VER; + } + void MakeLzma(UInt32 packSize) { - Buf[0] = SWF_COMPRESSED; - if (Buf[3] < SWF_MIN_COMPRESSED_VER) - Buf[3] = SWF_MIN_COMPRESSED_VER; + Buf[0] = SWF_COMPRESSED_LZMA; + if (Buf[3] < SWF_MIN_COMPRESSED_LZMA_VER) + Buf[3] = SWF_MIN_COMPRESSED_LZMA_VER; + SetUi32(Buf + 8, packSize); + HeaderSize = kHeaderLzmaSize; } - HRESULT ReadHeader(ISequentialInStream *stream) { return ReadStream_FALSE(stream, Buf, kHeaderSize); } - HRESULT WriteHeader(ISequentialOutStream *stream) { return WriteStream(stream, Buf, kHeaderSize); } + HRESULT ReadHeader(ISequentialInStream *stream) + { + HeaderSize = kHeaderBaseSize; + return ReadStream_FALSE(stream, Buf, kHeaderBaseSize); + } + HRESULT WriteHeader(ISequentialOutStream *stream) + { + return WriteStream(stream, Buf, HeaderSize); + } }; class CHandler: @@ -69,19 +160,22 @@ class CHandler: CMyComPtr<IInStream> _stream; CSingleMethodProps _props; + bool _lzmaMode; public: + CHandler(): _lzmaMode(false) {} MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties) INTERFACE_IInArchive(;) INTERFACE_IOutArchive(;) STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps); + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); }; -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8} + kpidSize, + kpidPackSize, + kpidMethod }; IMP_IInArchive_Props @@ -90,9 +184,10 @@ IMP_IInArchive_ArcProps_NO_Table STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; - switch(propID) + switch (propID) { - case kpidPhySize: if (_packSizeDefined) prop = _packSize; break; + case kpidPhySize: if (_packSizeDefined) prop = _item.HeaderSize + _packSize; break; + case kpidIsNotArcType: prop = true; break; } prop.Detach(value); return S_OK; @@ -104,13 +199,48 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } +static void DicSizeToString(char *s, UInt32 val) +{ + char c = 0; + unsigned i; + for (i = 0; i <= 31; i++) + if (((UInt32)1 << i) == val) + { + val = i; + break; + } + if (i == 32) + { + c = 'b'; + if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } + else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } + } + ::ConvertUInt32ToString(val, s); + int pos = MyStringLen(s); + s[pos++] = c; + s[pos] = 0; +} + STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { NWindows::NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidSize: prop = (UInt64)_item.GetSize(); break; - case kpidPackSize: if (_packSizeDefined) prop = _packSize; break; + case kpidPackSize: if (_packSizeDefined) prop = _item.HeaderSize + _packSize; break; + case kpidMethod: + { + char s[32]; + if (_item.IsZlib()) + MyStringCopy(s, "zlib"); + else + { + MyStringCopy(s, "LZMA:"); + DicSizeToString(s + 5, _item.GetLzmaDicSize()); + } + prop = s; + break; + } } prop.Detach(value); return S_OK; @@ -126,30 +256,63 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) { Close(); - HRESULT res = _item.ReadHeader(stream); - if (res == S_OK) - if (_item.IsCompressed()) - _seqStream = stream; - else - res = S_FALSE; - return res; + RINOK(_item.ReadHeader(stream)); + if (!_item.IsSwf()) + return S_FALSE; + if (_item.IsLzma()) + { + RINOK(ReadStream_FALSE(stream, _item.Buf + kHeaderBaseSize, kHeaderLzmaSize - kHeaderBaseSize)); + _item.HeaderSize = kHeaderLzmaSize; + _packSize = _item.GetLzmaPackSize(); + _packSizeDefined = true; + } + else if (!_item.IsZlib()) + return S_FALSE; + if (_item.GetSize() < _item.HeaderSize) + return S_FALSE; + _seqStream = stream; + return S_OK; } STDMETHODIMP CHandler::Close() { + _packSize = 0; _packSizeDefined = false; _seqStream.Release(); _stream.Release(); return S_OK; } +class CCompressProgressInfoImp: + public ICompressProgressInfo, + public CMyUnknownImp +{ + CMyComPtr<IArchiveOpenCallback> Callback; +public: + UInt64 Offset; + MY_UNKNOWN_IMP1(ICompressProgressInfo) + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); + void Init(IArchiveOpenCallback *callback) { Callback = callback; } +}; + +STDMETHODIMP CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */) +{ + if (Callback) + { + UInt64 files = 0; + UInt64 value = Offset + *inSize; + return Callback->SetCompleted(&files, &value); + } + return S_OK; +} + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN if (numItems == 0) return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; extractCallback->SetTotal(_item.GetSize()); @@ -163,9 +326,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, extractCallback->PrepareOperation(askMode); - NCompress::NZlib::CDecoder *_decoderSpec = new NCompress::NZlib::CDecoder; - CMyComPtr<ICompressCoder> _decoder = _decoderSpec; - CDummyOutStream *outStreamSpec = new CDummyOutStream; CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); outStreamSpec->SetStream(realOutStream); @@ -176,24 +336,73 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); - lps->InSize = kHeaderSize; + lps->InSize = _item.HeaderSize; lps->OutSize = outStreamSpec->GetSize(); RINOK(lps->SetCur()); CItem item = _item; item.MakeUncompressed(); - RINOK(item.WriteHeader(outStream)); if (_stream) - RINOK(_stream->Seek(kHeaderSize, STREAM_SEEK_SET, NULL)); - HRESULT result = _decoderSpec->Code(_seqStream, outStream, NULL, NULL, progress); + RINOK(_stream->Seek(_item.HeaderSize, STREAM_SEEK_SET, NULL)); + NCompress::NZlib::CDecoder *_decoderZlibSpec = NULL; + NCompress::NLzma::CDecoder *_decoderLzmaSpec = NULL; + CMyComPtr<ICompressCoder> _decoder; + + CMyComPtr<ISequentialInStream> inStream2; + + UInt64 unpackSize = _item.GetSize() - (UInt32)8; + if (_item.IsZlib()) + { + _decoderZlibSpec = new NCompress::NZlib::CDecoder; + _decoder = _decoderZlibSpec; + inStream2 = _seqStream; + } + else + { + /* Some .swf files with lzma contain additional 8 bytes at the end + in uncompressed stream. + What does that data mean ??? + We don't decompress these additional 8 bytes */ + + // unpackSize = _item.GetSize(); + // SetUi32(item.Buf + 4, (UInt32)(unpackSize + 8)); + CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream; + inStream2 = limitedStreamSpec; + limitedStreamSpec->SetStream(_seqStream); + limitedStreamSpec->Init(_item.GetLzmaPackSize()); + + _decoderLzmaSpec = new NCompress::NLzma::CDecoder; + _decoder = _decoderLzmaSpec; + // _decoderLzmaSpec->FinishStream = true; + + Byte props[5]; + memcpy(props, _item.Buf + 12, 5); + UInt32 dicSize = _item.GetLzmaDicSize(); + if (dicSize > (UInt32)unpackSize) + { + dicSize = (UInt32)unpackSize; + SetUi32(props + 1, dicSize); + } + RINOK(_decoderLzmaSpec->SetDecoderProperties2(props, 5)); + } + RINOK(item.WriteHeader(outStream)); + HRESULT result = _decoder->Code(inStream2, outStream, NULL, &unpackSize, progress); Int32 opRes = NExtract::NOperationResult::kDataError; if (result == S_OK) { - if (_item.GetSize() == outStreamSpec->GetSize()) + if (item.GetSize() == outStreamSpec->GetSize()) { - _packSizeDefined = true; - _packSize = _decoderSpec->GetInputProcessedSize() + kHeaderSize; - opRes = NExtract::NOperationResult::kOK; + if (_item.IsZlib()) + { + _packSizeDefined = true; + _packSize = _decoderZlibSpec->GetInputProcessedSize(); + opRes = NExtract::NOperationResult::kOK; + } + else + { + // if (_decoderLzmaSpec->GetInputProcessedSize() == _packSize) + opRes = NExtract::NOperationResult::kOK; + } } } else if (result != S_FALSE) @@ -204,8 +413,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -static HRESULT UpdateArchive(ISequentialOutStream *outStream, - UInt64 size, const CSingleMethodProps &props, +static HRESULT UpdateArchive(ISequentialOutStream *outStream, UInt64 size, + bool lzmaMode, const CSingleMethodProps &props, IArchiveUpdateCallback *updateCallback) { UInt64 complexity = 0; @@ -215,27 +424,73 @@ static HRESULT UpdateArchive(ISequentialOutStream *outStream, CMyComPtr<ISequentialInStream> fileInStream; RINOK(updateCallback->GetStream(0, &fileInStream)); + /* + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + realOutStream.Release(); + */ + CItem item; HRESULT res = item.ReadHeader(fileInStream); if (res == S_FALSE) return E_INVALIDARG; RINOK(res); - if (!item.IsUncompressed() || size != item.GetSize()) + if (!item.IsSwf() || !item.IsUncompressed() || size != item.GetSize()) return E_INVALIDARG; - item.MakeCompressed(); - item.WriteHeader(outStream); + NCompress::NZlib::CEncoder *encoderZlibSpec = NULL; + NCompress::NLzma::CEncoder *encoderLzmaSpec = NULL; + CMyComPtr<ICompressCoder> encoder; + CMyComPtr<IOutStream> outSeekStream; + if (lzmaMode) + { + outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream); + if (!outSeekStream) + return E_NOTIMPL; + encoderLzmaSpec = new NCompress::NLzma::CEncoder; + encoder = encoderLzmaSpec; + RINOK(props.SetCoderProps(encoderLzmaSpec, &size)); + item.MakeLzma((UInt32)0xFFFFFFFF); + CBufPtrSeqOutStream *propStreamSpec = new CBufPtrSeqOutStream; + CMyComPtr<ISequentialOutStream> propStream = propStreamSpec; + propStreamSpec->Init(item.Buf + 12, 5); + RINOK(encoderLzmaSpec->WriteCoderProperties(propStream)); + } + else + { + encoderZlibSpec = new NCompress::NZlib::CEncoder; + encoder = encoderZlibSpec; + encoderZlibSpec->Create(); + RINOK(props.SetCoderProps(encoderZlibSpec->DeflateEncoderSpec, NULL)); + item.MakeZlib(); + } + RINOK(item.WriteHeader(outStream)); CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(updateCallback, true); - NCompress::NZlib::CEncoder *encoderSpec = new NCompress::NZlib::CEncoder; - CMyComPtr<ICompressCoder> encoder = encoderSpec; - encoderSpec->Create(); - RINOK(props.SetCoderProps(encoderSpec->DeflateEncoderSpec, NULL)); RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, progress)); - if (encoderSpec->GetInputProcessedSize() + kHeaderSize != size) + UInt64 inputProcessed; + if (lzmaMode) + { + UInt64 curPos = 0; + RINOK(outSeekStream->Seek(0, STREAM_SEEK_CUR, &curPos)); + UInt64 packSize = curPos - kHeaderLzmaSize; + if (packSize > (UInt32)0xFFFFFFFF) + return E_INVALIDARG; + item.MakeLzma((UInt32)packSize); + RINOK(outSeekStream->Seek(0, STREAM_SEEK_SET, NULL)); + item.WriteHeader(outStream); + inputProcessed = encoderLzmaSpec->GetInputProcessedSize(); + } + else + { + inputProcessed = encoderZlibSpec->GetInputProcessedSize(); + } + if (inputProcessed + kHeaderBaseSize != size) return E_INVALIDARG; return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK); } @@ -283,7 +538,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return E_INVALIDARG; size = prop.uhVal.QuadPart; } - return UpdateArchive(outStream, size, _props, updateCallback); + return UpdateArchive(outStream, size, _lzmaMode, _props, updateCallback); } if (indexInArchive != 0) @@ -301,20 +556,37 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return NCompress::CopyStream(_seqStream, outStream, NULL); } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { - return _props.SetProperties(names, values, numProps); + _lzmaMode = false; + RINOK(_props.SetProperties(names, values, numProps)); + UString m = _props.MethodName; + m.MakeLower_Ascii(); + if (m.IsEqualTo("lzma")) + { + return E_NOTIMPL; + // _lzmaMode = true; + } + else if (m.IsEqualTo("deflate") || m.IsEmpty()) + _lzmaMode = false; + else + return E_INVALIDARG; + return S_OK; } -static IInArchive *CreateArc() { return new CHandler; } -#ifndef EXTRACT_ONLY -static IOutArchive *CreateArcOut() { return new CHandler; } -#else -#define CreateArcOut 0 -#endif +IMP_CreateArcIn +IMP_CreateArcOut static CArcInfo g_ArcInfo = - { L"SWFc", L"swf", L"~.swf", 0xD8, { 'C', 'W', 'S' }, 3, true, CreateArc, CreateArcOut }; + { "SWFc", "swf", "~.swf", 0xD8, + 2 + 3 + 3, + { + 3, 'C', 'W', 'S', + 3, 'Z', 'W', 'S', + }, + 0, + NArcInfoFlags::kMultiSignature, + REF_CreateArc_Pair, IsArc_Swfc }; REGISTER_ARC(Swfc) @@ -322,8 +594,7 @@ REGISTER_ARC(Swfc) namespace NSwf { -static const UInt32 kFileSizeMax = (UInt32)1 << 30; -static const int kNumTagsMax = (UInt32)1 << 23; +static const unsigned kNumTagsMax = 1 << 23; struct CTag { @@ -338,7 +609,7 @@ class CHandler: { CObjectVector<CTag> _tags; NSwfc::CItem _item; - UInt64 _packSize; + UInt64 _phySize; HRESULT OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback); HRESULT OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback); @@ -349,11 +620,11 @@ public: STDMETHOD(OpenSeq)(ISequentialInStream *stream); }; -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidComment, VT_BSTR} + kpidPath, + kpidSize, + kpidComment, }; IMP_IInArchive_Props @@ -362,9 +633,10 @@ IMP_IInArchive_ArcProps_NO_Table STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; - switch(propID) + switch (propID) { - case kpidPhySize: prop = _packSize; break; + case kpidPhySize: prop = _phySize; break; + case kpidIsNotArcType: prop = true; break; } prop.Detach(value); return S_OK; @@ -379,105 +651,105 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) static const char *g_TagDesc[92] = { - "End", - "ShowFrame", - "DefineShape", - NULL, - "PlaceObject", - "RemoveObject", - "DefineBits", - "DefineButton", - "JPEGTables", - "SetBackgroundColor", - "DefineFont", - "DefineText", - "DoAction", - "DefineFontInfo", - "DefineSound", - "StartSound", - NULL, - "DefineButtonSound", - "SoundStreamHead", - "SoundStreamBlock", - "DefineBitsLossless", - "DefineBitsJPEG2", - "DefineShape2", - "DefineButtonCxform", - "Protect", - NULL, - "PlaceObject2", - NULL, - "RemoveObject2", - NULL, - NULL, - NULL, - "DefineShape3", - "DefineText2", - "DefineButton2", - "DefineBitsJPEG3", - "DefineBitsLossless2", - "DefineEditText", - NULL, - "DefineSprite", - NULL, - "41", - NULL, - "FrameLabel", - NULL, - "SoundStreamHead2", - "DefineMorphShape", - NULL, - "DefineFont2", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "ExportAssets", - "ImportAssets", - "EnableDebugger", - "DoInitAction", - "DefineVideoStream", - "VideoFrame", - "DefineFontInfo2", - NULL, - "EnableDebugger2", - "ScriptLimits", - "SetTabIndex", - NULL, - NULL, - "FileAttributes", - "PlaceObject3", - "ImportAssets2", - NULL, - "DefineFontAlignZones", - "CSMTextSettings", - "DefineFont3", - "SymbolClass", - "Metadata", - "DefineScalingGrid", - NULL, - NULL, - NULL, - "DoABC", - "DefineShape4", - "DefineMorphShape2", - NULL, - "DefineSceneAndFrameLabelData", - "DefineBinaryData", - "DefineFontName", - "StartSound2", - "DefineBitsJPEG4", - "DefineFont4" + "End" + , "ShowFrame" + , "DefineShape" + , NULL + , "PlaceObject" + , "RemoveObject" + , "DefineBits" + , "DefineButton" + , "JPEGTables" + , "SetBackgroundColor" + , "DefineFont" + , "DefineText" + , "DoAction" + , "DefineFontInfo" + , "DefineSound" + , "StartSound" + , NULL + , "DefineButtonSound" + , "SoundStreamHead" + , "SoundStreamBlock" + , "DefineBitsLossless" + , "DefineBitsJPEG2" + , "DefineShape2" + , "DefineButtonCxform" + , "Protect" + , NULL + , "PlaceObject2" + , NULL + , "RemoveObject2" + , NULL + , NULL + , NULL + , "DefineShape3" + , "DefineText2" + , "DefineButton2" + , "DefineBitsJPEG3" + , "DefineBitsLossless2" + , "DefineEditText" + , NULL + , "DefineSprite" + , NULL + , "41" + , NULL + , "FrameLabel" + , NULL + , "SoundStreamHead2" + , "DefineMorphShape" + , NULL + , "DefineFont2" + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , "ExportAssets" + , "ImportAssets" + , "EnableDebugger" + , "DoInitAction" + , "DefineVideoStream" + , "VideoFrame" + , "DefineFontInfo2" + , NULL + , "EnableDebugger2" + , "ScriptLimits" + , "SetTabIndex" + , NULL + , NULL + , "FileAttributes" + , "PlaceObject3" + , "ImportAssets2" + , NULL + , "DefineFontAlignZones" + , "CSMTextSettings" + , "DefineFont3" + , "SymbolClass" + , "Metadata" + , "DefineScalingGrid" + , NULL + , NULL + , NULL + , "DoABC" + , "DefineShape4" + , "DefineMorphShape2" + , NULL + , "DefineSceneAndFrameLabelData" + , "DefineBinaryData" + , "DefineFontName" + , "StartSound2" + , "DefineBitsJPEG4" + , "DefineFont4" }; STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { NWindows::NCOM::CPropVariant prop; const CTag &tag = _tags[index]; - switch(propID) + switch (propID) { case kpidPath: { @@ -491,9 +763,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } case kpidSize: case kpidPackSize: - prop = (UInt64)tag.Buf.GetCapacity(); break; + prop = (UInt64)tag.Buf.Size(); break; case kpidComment: - if (tag.Type < sizeof(g_TagDesc) / sizeof(g_TagDesc[0])) + if (tag.Type < ARRAY_SIZE(g_TagDesc)) { const char *s = g_TagDesc[tag.Type]; if (s != NULL) @@ -579,8 +851,12 @@ UInt32 CBitReader::ReadBits(unsigned numBits) HRESULT CHandler::OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback) { RINOK(_item.ReadHeader(stream)) - if (!_item.IsUncompressed()) + if (!_item.IsSwf() || !_item.IsUncompressed()) + return S_FALSE; + UInt32 uncompressedSize = _item.GetSize(); + if (uncompressedSize > kFileSizeMax) return S_FALSE; + CInBuffer s; if (!s.Create(1 << 20)) @@ -610,13 +886,12 @@ HRESULT CHandler::OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *ca length = Read32(s); if (type == 0) break; - UInt64 offset = s.GetProcessedSize() + NSwfc::kHeaderSize + length; - if (offset > kFileSizeMax || _tags.Size() >= kNumTagsMax) + UInt64 offset = s.GetProcessedSize() + NSwfc::kHeaderBaseSize + length; + if (offset > uncompressedSize || _tags.Size() >= kNumTagsMax) return S_FALSE; - _tags.Add(CTag()); - CTag &tag = _tags.Back(); + CTag &tag = _tags.AddNew(); tag.Type = type; - tag.Buf.SetCapacity(length); + tag.Buf.Alloc(length); if (s.ReadBytes(tag.Buf, length) != length) return S_FALSE; if (callback && offset >= offsetPrev + (1 << 20)) @@ -626,7 +901,12 @@ HRESULT CHandler::OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *ca offsetPrev = offset; } } - _packSize = s.GetProcessedSize() + NSwfc::kHeaderSize; + _phySize = s.GetProcessedSize() + NSwfc::kHeaderBaseSize; + if (_phySize != uncompressedSize) + { + // do we need to support files extracted from SFW-LZMA with additional 8 bytes? + return S_FALSE; + } return S_OK; } @@ -645,6 +925,7 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) STDMETHODIMP CHandler::Close() { + _phySize = 0; return S_OK; } @@ -652,7 +933,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _tags.Size(); if (numItems == 0) @@ -660,7 +941,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt64 totalSize = 0; UInt32 i; for (i = 0; i < numItems; i++) - totalSize += _tags[allFilesMode ? i : indices[i]].Buf.GetCapacity(); + totalSize += _tags[allFilesMode ? i : indices[i]].Buf.Size(); extractCallback->SetTotal(totalSize); CLocalProgress *lps = new CLocalProgress; @@ -678,7 +959,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, NExtract::NAskMode::kExtract; UInt32 index = allFilesMode ? i : indices[i]; const CByteBuffer &buf = _tags[index].Buf; - totalSize += buf.GetCapacity(); + totalSize += buf.Size(); CMyComPtr<ISequentialOutStream> outStream; RINOK(extractCallback->GetStream(index, &outStream, askMode)); @@ -687,7 +968,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->PrepareOperation(askMode)); if (outStream) - RINOK(WriteStream(outStream, buf, buf.GetCapacity())); + RINOK(WriteStream(outStream, buf, buf.Size())); outStream.Release(); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); } @@ -695,10 +976,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"SWF", L"swf", 0, 0xD7, { 'F', 'W', 'S' }, 3, true, CreateArc, 0 }; + { "SWF", "swf", 0, 0xD7, + 3, { 'F', 'W', 'S' }, + 0, + NArcInfoFlags::kKeepName, + CreateArc, NULL, NSwfc::IsArc_Swf }; REGISTER_ARC(Swf) diff --git a/CPP/7zip/Archive/Tar/StdAfx.h b/CPP/7zip/Archive/Tar/StdAfx.h index 2e4be10b..2854ff3e 100755..100644 --- a/CPP/7zip/Archive/Tar/StdAfx.h +++ b/CPP/7zip/Archive/Tar/StdAfx.h @@ -3,7 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" -#include "../../../Common/NewHandler.h" +#include "../../../Common/Common.h" #endif diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp index 251afdb7..fc7de5ae 100755..100644 --- a/CPP/7zip/Archive/Tar/TarHandler.cpp +++ b/CPP/7zip/Archive/Tar/TarHandler.cpp @@ -2,13 +2,15 @@ #include "StdAfx.h" -#include "Common/ComTry.h" -#include "Common/StringConvert.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../../Windows/TimeUtils.h" #include "../../Common/LimitedStreams.h" +#include "../../Common/MethodProps.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamObjects.h" #include "../../Common/StreamUtils.h" @@ -16,32 +18,34 @@ #include "../Common/ItemNameUtils.h" #include "TarHandler.h" -#include "TarIn.h" using namespace NWindows; namespace NArchive { namespace NTar { -static const char *kUnexpectedEnd = "Unexpected end of archive"; +static const UINT k_DefaultCodePage = CP_OEMCP; // it uses it if UTF8 check in names shows error -static const STATPROPSTG kProps[] = + +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidPosixAttrib, VT_UI4}, - { NULL, kpidUser, VT_BSTR}, - { NULL, kpidGroup, VT_BSTR}, - { NULL, kpidLink, VT_BSTR} + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidPosixAttrib, + kpidUser, + kpidGroup, + kpidSymLink, + kpidHardLink, + // kpidLinkType }; -static const STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidPhySize, VT_UI8}, - { NULL, kpidHeadersSize, VT_UI8} + kpidHeadersSize, + kpidCodePage }; IMP_IInArchive_Props @@ -50,11 +54,42 @@ IMP_IInArchive_ArcProps STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidPhySize: if (_phySizeDefined) prop = _phySize; break; case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break; - case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + case kpidErrorFlags: + { + UInt32 flags = 0; + if (!_isArc) + flags |= kpv_ErrorFlags_IsNotArc; + else switch (_error) + { + case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break; + case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break; + } + prop = flags; + break; + } + + case kpidCodePage: + { + const char *name = NULL; + switch (_openCodePage) + { + case CP_OEMCP: name = "OEM"; break; + case CP_UTF8: name = "UTF-8"; break; + } + if (name != NULL) + prop = name; + else + { + char sz[16]; + ConvertUInt32ToString(_openCodePage, sz); + prop = sz; + }; + break; + } } prop.Detach(value); return S_OK; @@ -63,9 +98,16 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item) { item.HeaderPos = _phySize; - RINOK(ReadItem(stream, filled, item, _errorMessage)); - if (filled && item.IsSparse()) - _isSparse = true; + RINOK(ReadItem(stream, filled, item, _error)); + if (filled) + { + /* + if (item.IsSparse()) + _isSparse = true; + */ + if (item.IsPaxExtendedHeader()) + _thereIsPaxExtendedHeader = true; + } _phySize += item.HeaderSize; _headersSize += item.HeaderSize; return S_OK; @@ -80,6 +122,14 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) } _phySizeDefined = true; + + bool utf8_OK = true; + if (!_forceCodePage) + { + if (!utf8_OK) + _curCodePage = k_DefaultCodePage; + } + for (;;) { CItemEx item; @@ -87,12 +137,22 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) RINOK(ReadItem2(stream, filled, item)); if (!filled) break; + + _isArc = true; _items.Add(item); + + if (!_forceCodePage) + { + if (utf8_OK) utf8_OK = CheckUTF8(item.Name); + if (utf8_OK) utf8_OK = CheckUTF8(item.User); + if (utf8_OK) utf8_OK = CheckUTF8(item.Group); + if (utf8_OK) utf8_OK = CheckUTF8(item.LinkName); + } RINOK(stream->Seek(item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize)); if (_phySize > endPos) { - _errorMessage = kUnexpectedEnd; + _error = k_ErrorType_UnexpectedEnd; break; } /* @@ -102,13 +162,13 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) break; } */ - if (callback != NULL) + if (callback) { if (_items.Size() == 1) { RINOK(callback->SetTotal(NULL, &endPos)); } - if (_items.Size() % 100 == 0) + if ((_items.Size() & 0x3FF) == 0) { UInt64 numFiles = _items.Size(); RINOK(callback->SetCompleted(&numFiles, &_phySize)); @@ -116,8 +176,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) } } + if (!_forceCodePage) + { + if (!utf8_OK) + _curCodePage = k_DefaultCodePage; + } + _openCodePage = _curCodePage; + if (_items.Size() == 0) { + if (_error != k_ErrorType_OK) + { + _isArc = false; + return S_FALSE; + } CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; if (!callback) return S_FALSE; @@ -129,11 +201,12 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) return S_FALSE; if (prop.vt != VT_BSTR) return S_FALSE; - UString baseName = prop.bstrVal; - baseName = baseName.Right(4); - if (baseName.CompareNoCase(L".tar") != 0) + unsigned len = MyStringLen(prop.bstrVal); + if (len < 4 || MyStringCompareNoCase(prop.bstrVal + len - 4, L".tar") != 0) return S_FALSE; } + + _isArc = true; return S_OK; } @@ -158,13 +231,16 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) STDMETHODIMP CHandler::Close() { - _errorMessage.Empty(); + _isArc = false; + _error = k_ErrorType_OK; + _phySizeDefined = false; _phySize = 0; _headersSize = 0; _curIndex = 0; _latestIsRead = false; - _isSparse = false; + // _isSparse = false; + _thereIsPaxExtendedHeader = false; _items.Clear(); _seqStream.Release(); _stream.Release(); @@ -181,6 +257,8 @@ CHandler::CHandler() { copyCoderSpec = new NCompress::CCopyCoder(); copyCoder = copyCoderSpec; + _openCodePage = CP_UTF8; + Init(); } HRESULT CHandler::SkipTo(UInt32 index) @@ -194,7 +272,7 @@ HRESULT CHandler::SkipTo(UInt32 index) _phySize += copyCoderSpec->TotalSize; if (copyCoderSpec->TotalSize != packSize) { - _errorMessage = kUnexpectedEnd; + _error = k_ErrorType_UnexpectedEnd; return S_FALSE; } _latestIsRead = false; @@ -215,15 +293,29 @@ HRESULT CHandler::SkipTo(UInt32 index) return S_OK; } -static UString TarStringToUnicode(const AString &s) +void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs) const { - return MultiByteToUnicodeString(s, CP_OEMCP); + UString dest; + if (_curCodePage == CP_UTF8) + { + if (!ConvertUTF8ToUnicode(s, dest)) + { + prop = "[ERROR-NAME]"; + return; + } + } + else + dest = MultiByteToUnicodeString(s, _curCodePage); + if (toOs) + prop = NItemName::GetOSName2(dest); + else + prop = dest; } STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; const CItemEx *item; if (_stream) @@ -239,9 +331,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } } - switch(propID) + switch (propID) { - case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break; + case kpidPath: TarStringToUnicode(item->Name, prop, true); break; case kpidIsDir: prop = item->IsDir(); break; case kpidSize: prop = item->GetUnpackSize(); break; case kpidPackSize: prop = item->GetPackSizeAligned(); break; @@ -254,9 +346,11 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val } break; case kpidPosixAttrib: prop = item->Mode; break; - case kpidUser: prop = TarStringToUnicode(item->User); break; - case kpidGroup: prop = TarStringToUnicode(item->Group); break; - case kpidLink: prop = TarStringToUnicode(item->LinkName); break; + case kpidUser: TarStringToUnicode(item->User, prop); break; + case kpidGroup: TarStringToUnicode(item->Group, prop); break; + case kpidSymLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kSymLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break; + case kpidHardLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kHardLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break; + // case kpidLinkType: prop = (int)item->LinkFlag; break; } prop.Detach(value); return S_OK; @@ -272,7 +366,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (!seqMode) stream = _stream; - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (_stream && numItems == 0) @@ -333,7 +427,18 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (!testMode && !realOutStream) { if (!seqMode) + { + /* + // probably we must show extracting info it callback handler instead + if (item->IsHardLink() || + item->IsSymLink()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + } + */ continue; + } skipMode = true; askMode = NExtract::NAskMode::kSkip; } @@ -344,13 +449,20 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, outStreamSpec->Init(skipMode ? 0 : unpackSize, true); Int32 opRes = NExtract::NOperationResult::kOK; - if (item->IsSparse()) - opRes = NExtract::NOperationResult::kUnSupportedMethod; + CMyComPtr<ISequentialInStream> inStream2; + if (!item->IsSparse()) + inStream2 = inStream; else { - if (item->IsLink()) + GetStream(index, &inStream2); + if (!inStream2) + return E_FAIL; + } + + { + if (item->IsSymLink()) { - RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length())); + RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len())); } else { @@ -359,7 +471,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL)); } streamSpec->Init(item->GetPackSizeAligned()); - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + RINOK(copyCoder->Code(inStream2, outStream, NULL, NULL, progress)); } if (outStreamSpec->GetRem() != 0) opRes = NExtract::NOperationResult::kDataError; @@ -376,22 +488,198 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } +class CSparseStream: + public IInStream, + public CMyUnknownImp +{ + UInt64 _phyPos; + UInt64 _virtPos; + bool _needStartSeek; + +public: + CHandler *Handler; + CMyComPtr<IUnknown> HandlerRef; + unsigned ItemIndex; + CRecordVector<UInt64> PhyOffsets; + + MY_UNKNOWN_IMP2(ISequentialInStream, IInStream) + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); + + void Init() + { + _virtPos = 0; + _phyPos = 0; + _needStartSeek = true; + } +}; + + +STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + const CItemEx &item = Handler->_items[ItemIndex]; + if (_virtPos >= item.Size) + return S_OK; + { + UInt64 rem = item.Size - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + + HRESULT res = S_OK; + + if (item.SparseBlocks.IsEmpty()) + memset(data, 0, size); + else + { + unsigned left = 0, right = item.SparseBlocks.Size(); + for (;;) + { + unsigned mid = (left + right) / 2; + if (mid == left) + break; + if (_virtPos < item.SparseBlocks[mid].Offset) + right = mid; + else + left = mid; + } + + const CSparseBlock &sb = item.SparseBlocks[left]; + UInt64 relat = _virtPos - sb.Offset; + + if (_virtPos >= sb.Offset && relat < sb.Size) + { + UInt64 rem = sb.Size - relat; + if (size > rem) + size = (UInt32)rem; + UInt64 phyPos = PhyOffsets[left] + relat; + if (_needStartSeek || _phyPos != phyPos) + { + RINOK(Handler->_stream->Seek(item.GetDataPosition() + phyPos, STREAM_SEEK_SET, NULL)); + _needStartSeek = false; + _phyPos = phyPos; + } + res = Handler->_stream->Read(data, size, &size); + _phyPos += size; + } + else + { + UInt64 next = item.Size; + if (_virtPos < sb.Offset) + next = sb.Offset; + else if (left + 1 < item.SparseBlocks.Size()) + next = item.SparseBlocks[left + 1].Offset; + UInt64 rem = next - _virtPos; + if (size > rem) + size = (UInt32)rem; + memset(data, 0, size); + } + } + + _virtPos += size; + if (processedSize) + *processedSize = size; + return res; +} + +STDMETHODIMP CSparseStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += Handler->_items[ItemIndex].Size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = offset; + if (newPosition) + *newPosition = _virtPos; + return S_OK; +} + STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) { COM_TRY_BEGIN + const CItemEx &item = _items[index]; + if (item.IsSparse()) - return E_NOTIMPL; - if (item.IsLink()) + { + CSparseStream *streamSpec = new CSparseStream; + CMyComPtr<IInStream> streamTemp = streamSpec; + streamSpec->Init(); + streamSpec->Handler = this; + streamSpec->HandlerRef = (IInArchive *)this; + streamSpec->ItemIndex = index; + streamSpec->PhyOffsets.Reserve(item.SparseBlocks.Size()); + UInt64 offs = 0; + FOR_VECTOR(i, item.SparseBlocks) + { + const CSparseBlock &sb = item.SparseBlocks[i]; + streamSpec->PhyOffsets.AddInReserved(offs); + offs += sb.Size; + } + *stream = streamTemp.Detach(); + return S_OK; + } + + if (item.IsSymLink()) { CBufInStream *streamSpec = new CBufInStream; CMyComPtr<IInStream> streamTemp = streamSpec; - streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Length(), (IInArchive *)this); + streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this); *stream = streamTemp.Detach(); return S_OK; } + return CreateLimitedInStream(_stream, item.GetDataPosition(), item.PackSize, stream); + COM_TRY_END } +void CHandler::Init() +{ + _forceCodePage = false; + // _codePage = CP_OEMCP; + _curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP; +} + +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +{ + Init(); + + for (UInt32 i = 0; i < numProps; i++) + { + UString name = names[i]; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + const PROPVARIANT &prop = values[i]; + + if (name[0] == L'x') + { + // some clients write 'x' property. So we support it + UInt32 level = 0; + RINOK(ParsePropToUInt32(name.Ptr(1), prop, level)); + } + else if (name.IsEqualTo("cp")) + { + UInt32 cp = CP_OEMCP; + RINOK(ParsePropToUInt32(L"", prop, cp)); + _forceCodePage = true; + _curCodePage = _specifiedCodePage = cp; + } + else + return E_INVALIDARG; + } + return S_OK; +} + }} diff --git a/CPP/7zip/Archive/Tar/TarHandler.h b/CPP/7zip/Archive/Tar/TarHandler.h index 9251edf6..23854767 100755..100644 --- a/CPP/7zip/Archive/Tar/TarHandler.h +++ b/CPP/7zip/Archive/Tar/TarHandler.h @@ -3,12 +3,15 @@ #ifndef __TAR_HANDLER_H #define __TAR_HANDLER_H -#include "Common/MyCom.h" -#include "../IArchive.h" +#include "../../../Common/MyCom.h" + +#include "../../../Windows/PropVariant.h" #include "../../Compress/CopyCoder.h" -#include "TarItem.h" +#include "../IArchive.h" + +#include "TarIn.h" namespace NArchive { namespace NTar { @@ -17,13 +20,15 @@ class CHandler: public IInArchive, public IArchiveOpenSeq, public IInArchiveGetStream, + public ISetProperties, public IOutArchive, public CMyUnknownImp { +public: CObjectVector<CItemEx> _items; CMyComPtr<IInStream> _stream; CMyComPtr<ISequentialInStream> _seqStream; - +private: UInt32 _curIndex; bool _latestIsRead; CItemEx _latestItem; @@ -31,8 +36,16 @@ class CHandler: UInt64 _phySize; UInt64 _headersSize; bool _phySizeDefined; - AString _errorMessage; - bool _isSparse; + EErrorType _error; + bool _isArc; + + // bool _isSparse; + bool _thereIsPaxExtendedHeader; + + bool _forceCodePage; + UInt32 _specifiedCodePage; + UInt32 _curCodePage; + UInt32 _openCodePage; NCompress::CCopyCoder *copyCoderSpec; CMyComPtr<ICompressCoder> copyCoder; @@ -40,12 +53,13 @@ class CHandler: HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo); HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); HRESULT SkipTo(UInt32 index); - + void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const; public: - MY_UNKNOWN_IMP4( + MY_UNKNOWN_IMP5( IInArchive, IArchiveOpenSeq, IInArchiveGetStream, + ISetProperties, IOutArchive ) @@ -53,7 +67,9 @@ public: INTERFACE_IOutArchive(;) STDMETHOD(OpenSeq)(ISequentialInStream *stream); STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); + void Init(); CHandler(); }; diff --git a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp index b0ec63d1..b909e96c 100755..100644 --- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp +++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp @@ -2,11 +2,13 @@ #include "StdAfx.h" -#include "Common/ComTry.h" -#include "Common/StringConvert.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/Defs.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" #include "TarHandler.h" #include "TarUpdate.h" @@ -22,24 +24,54 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) return S_OK; } -static HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res) +HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, + AString &res, UINT codePage, bool convertSlash = false) { NCOM::CPropVariant prop; RINOK(callback->GetProperty(index, propId, &prop)); if (prop.vt == VT_BSTR) - res = UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP); + { + UString s = prop.bstrVal; + if (convertSlash) + s = NItemName::MakeLegalName(s); + if (codePage == CP_UTF8) + { + if (!ConvertUnicodeToUTF8(s, res)) + return E_INVALIDARG; + } + else + UnicodeStringToMultiByte2(res, s, codePage); + } else if (prop.vt != VT_EMPTY) return E_INVALIDARG; return S_OK; } +// sort old files with original order. + +static int CompareUpdateItems(void *const *p1, void *const *p2, void *) +{ + const CUpdateItem &u1 = *(*((const CUpdateItem **)p1)); + const CUpdateItem &u2 = *(*((const CUpdateItem **)p2)); + if (!u1.NewProps) + { + if (u2.NewProps) + return -1; + return MyCompare(u1.IndexInArchive, u2.IndexInArchive); + } + if (!u2.NewProps) + return 1; + return MyCompare(u1.IndexInClient, u2.IndexInClient); +} + STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *callback) { COM_TRY_BEGIN - if ((_stream && (!_errorMessage.IsEmpty() || _isSparse)) || _seqStream) + if ((_stream && (_error != k_ErrorType_OK /* || _isSparse */)) || _seqStream) return E_NOTIMPL; CObjectVector<CUpdateItem> updateItems; + UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage); for (UInt32 i = 0; i < numItems; i++) { CUpdateItem ui; @@ -87,19 +119,13 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt else ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime); } - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidPath, &prop)); - if (prop.vt == VT_BSTR) - ui.Name = UnicodeStringToMultiByte(NItemName::MakeLegalName(prop.bstrVal), CP_OEMCP); - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - if (ui.IsDir) - ui.Name += '/'; - } - RINOK(GetPropString(callback, i, kpidUser, ui.User)); - RINOK(GetPropString(callback, i, kpidGroup, ui.Group)); + RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, true)); + if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/') + ui.Name += '/'; + RINOK(GetPropString(callback, i, kpidUser, ui.User, codePage)); + RINOK(GetPropString(callback, i, kpidGroup, ui.Group, codePage)); } + if (IntToBool(newData)) { NCOM::CPropVariant prop; @@ -115,7 +141,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt } updateItems.Add(ui); } - return UpdateArchive(_stream, outStream, _items, updateItems, callback); + if (_thereIsPaxExtendedHeader) + { + // we restore original order of files, if there is pax header block + updateItems.Sort(CompareUpdateItems, NULL); + } + return UpdateArchive(_stream, outStream, _items, updateItems, codePage, callback); COM_TRY_END } diff --git a/CPP/7zip/Archive/Tar/TarHeader.cpp b/CPP/7zip/Archive/Tar/TarHeader.cpp index 3275b284..70be09f3 100755..100644 --- a/CPP/7zip/Archive/Tar/TarHeader.cpp +++ b/CPP/7zip/Archive/Tar/TarHeader.cpp @@ -1,4 +1,4 @@ -// Archive/Tar/Header.h +// Archive/TarHeader.cpp #include "StdAfx.h" @@ -8,18 +8,16 @@ namespace NArchive { namespace NTar { namespace NFileHeader { - // The checksum field is filled with this while the checksum is computed. - const char *kCheckSumBlanks = " "; // 8 blanks, no null - const char *kLongLink = "././@LongLink"; const char *kLongLink2 = "@LongLink"; // The magic field is filled with this if uname and gname are valid. namespace NMagic { - const char *kUsTar = "ustar"; // 5 chars - const char *kGNUTar = "GNUtar "; // 7 chars and a null - const char *kEmpty = "\0\0\0\0\0\0\0\0"; // 7 chars and a null + // const char *kUsTar = "ustar"; // 5 chars + // const char *kGNUTar = "GNUtar "; // 7 chars and a null + // const char *kEmpty = "\0\0\0\0\0\0\0\0"; + const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ; } }}} diff --git a/CPP/7zip/Archive/Tar/TarHeader.h b/CPP/7zip/Archive/Tar/TarHeader.h index a212ae03..df594d81 100755..100644 --- a/CPP/7zip/Archive/Tar/TarHeader.h +++ b/CPP/7zip/Archive/Tar/TarHeader.h @@ -1,20 +1,22 @@ -// Archive/Tar/Header.h +// Archive/TarHeader.h #ifndef __ARCHIVE_TAR_HEADER_H #define __ARCHIVE_TAR_HEADER_H -#include "Common/Types.h" +#include "../../../Common/MyTypes.h" namespace NArchive { namespace NTar { namespace NFileHeader { - const int kRecordSize = 512; - const int kNameSize = 100; - const int kUserNameSize = 32; - const int kGroupNameSize = 32; - const int kPrefixSize = 155; + const unsigned kRecordSize = 512; + const unsigned kNameSize = 100; + const unsigned kUserNameSize = 32; + const unsigned kGroupNameSize = 32; + const unsigned kPrefixSize = 155; + + const unsigned kUstarMagic_Offset = 257; /* struct CHeader @@ -42,66 +44,39 @@ namespace NFileHeader }; */ - namespace NMode - { - const int kSetUID = 04000; // Set UID on execution - const int kSetGID = 02000; // Set GID on execution - const int kSaveText = 01000; // Save text (sticky bit) - } - - namespace NFilePermissions - { - const int kUserRead = 00400; // read by owner - const int kUserWrite = 00200; // write by owner - const int kUserExecute = 00100; // execute/search by owner - const int kGroupRead = 00040; // read by group - const int kGroupWrite = 00020; // write by group - const int kGroupExecute = 00010; // execute/search by group - const int kOtherRead = 00004; // read by other - const int kOtherWrite = 00002; // write by other - const int kOtherExecute = 00001; // execute/search by other - } - - - // The linkflag defines the type of file namespace NLinkFlag { - const char kOldNormal = '\0'; // Normal disk file, Unix compatible + const char kOldNormal = 0; // Normal disk file, Unix compatible const char kNormal = '0'; // Normal disk file - const char kLink = '1'; // Link to previously dumped file - const char kSymbolicLink = '2'; // Symbolic link + const char kHardLink = '1'; // Link to previously dumped file + const char kSymLink = '2'; // Symbolic link const char kCharacter = '3'; // Character special file const char kBlock = '4'; // Block special file const char kDirectory = '5'; // Directory const char kFIFO = '6'; // FIFO special file const char kContiguous = '7'; // Contiguous file - - const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR. + const char kGnu_LongLink = 'K'; + const char kGnu_LongName = 'L'; + const char kSparse = 'S'; + const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR. data: list of files created by the --incremental (-G) option Each file name is preceded by either - 'Y' (file should be in this archive) - 'N' (file is a directory, or is not stored in the archive.) Each file name is terminated by a null + an additional null after the last file name. */ - - const char kSparse = 'S'; } - // Further link types may be defined later. - - // The checksum field is filled with this while the checksum is computed. - extern const char *kCheckSumBlanks;// = " "; // 8 blanks, no null extern const char *kLongLink; // = "././@LongLink"; extern const char *kLongLink2; // = "@LongLink"; - // The magic field is filled with this if uname and gname are valid. namespace NMagic { - extern const char *kUsTar; // = "ustar"; // 5 chars - extern const char *kGNUTar; // = "GNUtar "; // 7 chars and a null - extern const char *kEmpty; // = "GNUtar "; // 7 chars and a null + // extern const char *kUsTar; // = "ustar"; // 5 chars + // extern const char *kGNUTar; // = "GNUtar "; // 7 chars and a null + // extern const char *kEmpty; // = "\0\0\0\0\0\0\0\0" + extern const char kUsTar_00[]; } - } }} diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp index b6e5e0f5..1584a520 100755..100644 --- a/CPP/7zip/Archive/Tar/TarIn.cpp +++ b/CPP/7zip/Archive/Tar/TarIn.cpp @@ -4,18 +4,20 @@ #include "../../../../C/CpuArch.h" -#include "Common/StringToInt.h" +#include "../../../Common/StringToInt.h" #include "../../Common/StreamUtils.h" +#include "../IArchive.h" + #include "TarIn.h" namespace NArchive { namespace NTar { -static void MyStrNCpy(char *dest, const char *src, int size) +static void MyStrNCpy(char *dest, const char *src, unsigned size) { - for (int i = 0; i < size; i++) + for (unsigned i = 0; i < size; i++) { char c = src[i]; dest[i] = c; @@ -24,19 +26,21 @@ static void MyStrNCpy(char *dest, const char *src, int size) } } -static bool OctalToNumber(const char *srcString, int size, UInt64 &res) +static bool OctalToNumber(const char *srcString, unsigned size, UInt64 &res) { char sz[32]; MyStrNCpy(sz, srcString, size); sz[size] = 0; const char *end; - int i; + unsigned i; for (i = 0; sz[i] == ' '; i++); res = ConvertOctStringToUInt64(sz + i, &end); + if (end == sz + i) + return false; return (*end == ' ' || *end == 0); } -static bool OctalToNumber32(const char *srcString, int size, UInt32 &res) +static bool OctalToNumber32(const char *srcString, unsigned size, UInt32 &res) { UInt64 res64; if (!OctalToNumber(srcString, size, res64)) @@ -45,17 +49,27 @@ static bool OctalToNumber32(const char *srcString, int size, UInt32 &res) return (res64 <= 0xFFFFFFFF); } -#define RIF(x) { if (!(x)) return S_FALSE; } +#define RIF(x) { if (!(x)) return S_OK; } + +/* +static bool IsEmptyData(const char *buf, size_t size) +{ + for (unsigned i = 0; i < size; i++) + if (buf[i] != 0) + return false; + return true; +} +*/ static bool IsRecordLast(const char *buf) { - for (int i = 0; i < NFileHeader::kRecordSize; i++) + for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) if (buf[i] != 0) return false; return true; } -static void ReadString(const char *s, int size, AString &result) +static void ReadString(const char *s, unsigned size, AString &result) { char temp[NFileHeader::kRecordSize + 1]; MyStrNCpy(temp, s, size); @@ -88,12 +102,39 @@ static bool ParseSize(const char *p, UInt64 &val) return OctalToNumber(p, 12, val); } -static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error) +#define CHECK(x) { if (!(x)) return k_IsArc_Res_NO; } + +API_FUNC_IsArc IsArc_Tar(const Byte *p2, size_t size) +{ + if (size < NFileHeader::kRecordSize) + return k_IsArc_Res_NEED_MORE; + + const char *p = (const char *)p2; + p += NFileHeader::kNameSize; + + UInt32 mode; + CHECK(OctalToNumber32(p, 8, mode)); p += 8; + + // if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; + p += 8; + // if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; + p += 8; + + UInt64 packSize; + Int64 time; + UInt32 checkSum; + CHECK(ParseSize(p, packSize)); p += 12; + CHECK(ParseInt64(p, time)); p += 12; + CHECK(OctalToNumber32(p, 8, checkSum)); + return k_IsArc_Res_YES; +} + +static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error) { char buf[NFileHeader::kRecordSize]; char *p = buf; - error.Empty(); + error = k_ErrorType_OK; filled = false; bool thereAreEmptyRecords = false; @@ -103,26 +144,41 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE RINOK(ReadStream(stream, buf, &processedSize)); if (processedSize == 0) { - if (!thereAreEmptyRecords ) - error = "There are no trailing zero-filled records"; + if (!thereAreEmptyRecords) + error = k_ErrorType_UnexpectedEnd; // "There are no trailing zero-filled records"; return S_OK; } if (processedSize != NFileHeader::kRecordSize) { - error = "There is no correct record at the end of archive"; + if (!thereAreEmptyRecords) + error = k_ErrorType_UnexpectedEnd; // error = "There is no correct record at the end of archive"; + else + { + /* + if (IsEmptyData(buf, processedSize)) + error = k_ErrorType_UnexpectedEnd; + else + { + // extraReadSize = processedSize; + // error = k_ErrorType_Corrupted; // some data after the end tail zeros + } + */ + } + return S_OK; } - item.HeaderSize += NFileHeader::kRecordSize; if (!IsRecordLast(buf)) break; + item.HeaderSize += NFileHeader::kRecordSize; thereAreEmptyRecords = true; } if (thereAreEmptyRecords) { - error = "There are data after end of archive"; + // error = "There are data after end of archive"; return S_OK; } + error = k_ErrorType_Corrupted; ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize; RIF(OctalToNumber32(p, 8, item.Mode)); p += 8; @@ -137,7 +193,7 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE UInt32 checkSum; RIF(OctalToNumber32(p, 8, checkSum)); - memcpy(p, NFileHeader::kCheckSumBlanks, 8); p += 8; + memset(p, ' ', 8); p += 8; item.LinkFlag = *p++; @@ -148,93 +204,170 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize; ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize; - item.DeviceMajorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMajor)); p += 8; - item.DeviceMinorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMinor)); p += 8; + item.DeviceMajorDefined = (p[0] != 0); if (item.DeviceMajorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMajor)); } p += 8; + item.DeviceMinorDefined = (p[0] != 0); if (item.DeviceMinorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMinor)); } p += 8; AString prefix; ReadString(p, NFileHeader::kPrefixSize, prefix); p += NFileHeader::kPrefixSize; - if (!prefix.IsEmpty() && item.IsMagic() && + if (!prefix.IsEmpty() && item.IsUstarMagic() && (item.LinkFlag != 'L' /* || prefix != "00000000000" */ )) item.Name = prefix + AString('/') + item.Name; - if (item.LinkFlag == NFileHeader::NLinkFlag::kLink) + if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink) { item.PackSize = 0; item.Size = 0; } - else if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse) + /* + TAR standard requires sum of unsigned byte values. + But some TAR programs use sum of signed byte values. + So we check both values. + */ + UInt32 checkSumReal = 0; + Int32 checkSumReal_Signed = 0; + for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) + { + char c = buf[i]; + checkSumReal_Signed += (signed char)c; + checkSumReal += (Byte)buf[i]; + } + + if (checkSumReal != checkSum) + { + if ((UInt32)checkSumReal_Signed != checkSum) + return S_OK; + } + + item.HeaderSize += NFileHeader::kRecordSize; + + if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse) { - if (buf[482] != 0) - return S_FALSE; + Byte isExtended = buf[482]; + if (isExtended != 0 && isExtended != 1) + return S_OK; RIF(ParseSize(buf + 483, item.Size)); - p = buf + 386; UInt64 min = 0; - for (int i = 0; i < 4; i++, p += 24) + for (unsigned i = 0; i < 4; i++) { + p = buf + 386 + 24 * i; if (GetBe32(p) == 0) + { + if (isExtended != 0) + return S_OK; break; + } CSparseBlock sb; RIF(ParseSize(p, sb.Offset)); RIF(ParseSize(p + 12, sb.Size)); item.SparseBlocks.Add(sb); if (sb.Offset < min || sb.Offset > item.Size) - return S_FALSE; + return S_OK; if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0) - return S_FALSE; + return S_OK; min = sb.Offset + sb.Size; if (min < sb.Offset) - return S_FALSE; + return S_OK; + } + if (min > item.Size) + return S_OK; + + while (isExtended != 0) + { + size_t processedSize = NFileHeader::kRecordSize; + RINOK(ReadStream(stream, buf, &processedSize)); + if (processedSize != NFileHeader::kRecordSize) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + + item.HeaderSize += NFileHeader::kRecordSize; + isExtended = buf[21 * 24]; + if (isExtended != 0 && isExtended != 1) + return S_OK; + for (unsigned i = 0; i < 21; i++) + { + p = buf + 24 * i; + if (GetBe32(p) == 0) + { + if (isExtended != 0) + return S_OK; + break; + } + CSparseBlock sb; + RIF(ParseSize(p, sb.Offset)); + RIF(ParseSize(p + 12, sb.Size)); + item.SparseBlocks.Add(sb); + if (sb.Offset < min || sb.Offset > item.Size) + return S_OK; + if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0) + return S_OK; + min = sb.Offset + sb.Size; + if (min < sb.Offset) + return S_OK; + } } if (min > item.Size) - return S_FALSE; + return S_OK; } - UInt32 checkSumReal = 0; - for (int i = 0; i < NFileHeader::kRecordSize; i++) - checkSumReal += (Byte)buf[i]; - - if (checkSumReal != checkSum) - return S_FALSE; - filled = true; + error = k_ErrorType_OK; return S_OK; } -HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error) +HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error) { item.HeaderSize = 0; bool flagL = false; bool flagK = false; AString nameL; AString nameK; + for (;;) { RINOK(GetNextItemReal(stream, filled, item, error)); if (!filled) + { + if (error == k_ErrorType_OK && (flagL || flagK)) + error = k_ErrorType_Corrupted; + return S_OK; + } + + if (error != k_ErrorType_OK) return S_OK; - if (item.LinkFlag == 'L' || // NEXT file has a long name - item.LinkFlag == 'K') // NEXT file has a long linkname + + if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName || // file contains a long name + item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongLink) // file contains a long linkname { AString *name; - if (item.LinkFlag == 'L') - { if (flagL) return S_FALSE; flagL = true; name = &nameL; } + if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName) + { if (flagL) return S_OK; flagL = true; name = &nameL; } else - { if (flagK) return S_FALSE; flagK = true; name = &nameK; } + { if (flagK) return S_OK; flagK = true; name = &nameK; } - if (item.Name.Compare(NFileHeader::kLongLink) != 0 && - item.Name.Compare(NFileHeader::kLongLink2) != 0) - return S_FALSE; + if (item.Name != NFileHeader::kLongLink && + item.Name != NFileHeader::kLongLink2) + return S_OK; if (item.PackSize > (1 << 14)) - return S_FALSE; - int packSize = (int)item.GetPackSizeAligned(); + return S_OK; + unsigned packSize = (unsigned)item.GetPackSizeAligned(); char *buf = name->GetBuffer(packSize); - RINOK(ReadStream_FALSE(stream, buf, packSize)); - item.HeaderSize += packSize; - buf[(size_t)item.PackSize] = '\0'; + size_t processedSize = packSize; + HRESULT res = ReadStream(stream, buf, &processedSize); + item.HeaderSize += (unsigned)processedSize; + buf[(size_t)item.PackSize] = 0; name->ReleaseBuffer(); + RINOK(res); + if (processedSize != packSize) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } continue; } + switch (item.LinkFlag) { case 'g': @@ -256,10 +389,12 @@ HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AStri } default: if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0)) - return S_FALSE; + return S_OK; } + if (flagL) item.Name = nameL; if (flagK) item.LinkName = nameK; + error = k_ErrorType_OK; return S_OK; } } diff --git a/CPP/7zip/Archive/Tar/TarIn.h b/CPP/7zip/Archive/Tar/TarIn.h index a5491ebe..a67b1dbd 100755..100644 --- a/CPP/7zip/Archive/Tar/TarIn.h +++ b/CPP/7zip/Archive/Tar/TarIn.h @@ -10,7 +10,16 @@ namespace NArchive { namespace NTar { -HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, AString &error); +enum EErrorType +{ + k_ErrorType_OK, + k_ErrorType_Corrupted, + k_ErrorType_UnexpectedEnd, +}; + +HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, EErrorType &error); + +API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size); }} diff --git a/CPP/7zip/Archive/Tar/TarItem.h b/CPP/7zip/Archive/Tar/TarItem.h index 3584a7ce..805a2e7c 100755..100644 --- a/CPP/7zip/Archive/Tar/TarItem.h +++ b/CPP/7zip/Archive/Tar/TarItem.h @@ -40,28 +40,41 @@ struct CItem CRecordVector<CSparseBlock> SparseBlocks; - bool IsLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymbolicLink && (Size == 0); } + bool IsSymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); } + bool IsHardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; } bool IsSparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; } - UInt64 GetUnpackSize() const { return IsLink() ? LinkName.Length() : Size; } + UInt64 GetUnpackSize() const { return IsSymLink() ? LinkName.Len() : Size; } + bool IsPaxExtendedHeader() const + { + switch (LinkFlag) + { + case 'g': + case 'x': + case 'X': // Check it + return true; + } + return false; + } bool IsDir() const { - switch(LinkFlag) + switch (LinkFlag) { case NFileHeader::NLinkFlag::kDirectory: case NFileHeader::NLinkFlag::kDumpDir: return true; case NFileHeader::NLinkFlag::kOldNormal: case NFileHeader::NLinkFlag::kNormal: + case NFileHeader::NLinkFlag::kSymLink: return NItemName::HasTailSlash(Name, CP_OEMCP); } return false; } - bool IsMagic() const + bool IsUstarMagic() const { for (int i = 0; i < 5; i++) - if (Magic[i] != NFileHeader::NMagic::kUsTar[i]) + if (Magic[i] != NFileHeader::NMagic::kUsTar_00[i]) return false; return true; } diff --git a/CPP/7zip/Archive/Tar/TarOut.cpp b/CPP/7zip/Archive/Tar/TarOut.cpp index 6e699e28..51081e8b 100755..100644 --- a/CPP/7zip/Archive/Tar/TarOut.cpp +++ b/CPP/7zip/Archive/Tar/TarOut.cpp @@ -2,8 +2,6 @@ #include "StdAfx.h" -#include "Common/IntToString.h" - #include "../../Common/StreamUtils.h" #include "TarOut.h" @@ -11,26 +9,15 @@ namespace NArchive { namespace NTar { -HRESULT COutArchive::WriteBytes(const void *buffer, UInt32 size) -{ - return WriteStream(m_Stream, buffer, size); -} - -void COutArchive::Create(ISequentialOutStream *outStream) -{ - m_Stream = outStream; -} - -static AString MakeOctalString(UInt64 value) +HRESULT COutArchive::WriteBytes(const void *data, unsigned size) { - char s[32]; - ConvertUInt64ToString(value, s, 8); - return AString(s) + ' '; + Pos += size; + return WriteStream(m_Stream, data, size); } -static void MyStrNCpy(char *dest, const char *src, int size) +static void MyStrNCpy(char *dest, const char *src, unsigned size) { - for (int i = 0; i < size; i++) + for (unsigned i = 0; i < size; i++) { char c = src[i]; dest[i] = c; @@ -39,54 +26,53 @@ static void MyStrNCpy(char *dest, const char *src, int size) } } -static bool MakeOctalString8(char *s, UInt32 value) +static bool WriteOctal_8(char *s, UInt32 val) { - AString tempString = MakeOctalString(value); - - const int kMaxSize = 8; - if (tempString.Length() >= kMaxSize) + const unsigned kNumDigits = 8 - 1; + if (val >= ((UInt32)1 << (kNumDigits * 3))) return false; - int numSpaces = kMaxSize - (tempString.Length() + 1); - for (int i = 0; i < numSpaces; i++) - s[i] = ' '; - MyStringCopy(s + numSpaces, (const char *)tempString); + for (unsigned i = 0; i < kNumDigits; i++) + { + s[kNumDigits - 1 - i] = (char)('0' + (val & 7)); + val >>= 3; + } return true; } -static void MakeOctalString12(char *s, UInt64 value) +static void WriteOctal_12(char *s, UInt64 val) { - AString tempString = MakeOctalString(value); - const int kMaxSize = 12; - if (tempString.Length() > kMaxSize) + const unsigned kNumDigits = 12 - 1; + if (val >= ((UInt64)1 << (kNumDigits * 3))) { // GNU extension; s[0] = (char)(Byte)0x80; s[1] = s[2] = s[3] = 0; - for (int i = 0; i < 8; i++, value <<= 8) - s[4 + i] = (char)(value >> 56); + for (unsigned i = 0; i < 8; i++, val <<= 8) + s[4 + i] = (char)(val >> 56); return; } - int numSpaces = kMaxSize - tempString.Length(); - for (int i = 0; i < numSpaces; i++) - s[i] = ' '; - memmove(s + numSpaces, (const char *)tempString, tempString.Length()); + for (unsigned i = 0; i < kNumDigits; i++) + { + s[kNumDigits - 1 - i] = (char)('0' + (val & 7)); + val >>= 3; + } } -static void MakeOctalString12_From_Int64(char *s, Int64 value) +static void WriteOctal_12_Signed(char *s, Int64 val) { - if (value >= 0) + if (val >= 0) { - MakeOctalString12(s, value); + WriteOctal_12(s, val); return; } s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF; - for (int i = 0; i < 8; i++, value <<= 8) - s[4 + i] = (char)(value >> 56); + for (unsigned i = 0; i < 8; i++, val <<= 8) + s[4 + i] = (char)(val >> 56); } -static bool CopyString(char *dest, const AString &src, int maxSize) +static bool CopyString(char *dest, const AString &src, unsigned maxSize) { - if (src.Length() >= maxSize) + if (src.Len() >= maxSize) return false; MyStringCopy(dest, (const char *)src); return true; @@ -97,25 +83,22 @@ static bool CopyString(char *dest, const AString &src, int maxSize) HRESULT COutArchive::WriteHeaderReal(const CItem &item) { char record[NFileHeader::kRecordSize]; + memset(record, 0, NFileHeader::kRecordSize); char *cur = record; - int i; - for (i = 0; i < NFileHeader::kRecordSize; i++) - record[i] = 0; - // RETURN_IF_NOT_TRUE(CopyString(header.Name, item.Name, NFileHeader::kNameSize)); - if (item.Name.Length() > NFileHeader::kNameSize) + if (item.Name.Len() > NFileHeader::kNameSize) return E_FAIL; MyStrNCpy(cur, item.Name, NFileHeader::kNameSize); cur += NFileHeader::kNameSize; - RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.Mode)); cur += 8; - RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID)); cur += 8; - RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID)); cur += 8; + RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.Mode)); cur += 8; + RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.UID)); cur += 8; + RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.GID)); cur += 8; - MakeOctalString12(cur, item.PackSize); cur += 12; - MakeOctalString12_From_Int64(cur, item.MTime); cur += 12; + WriteOctal_12(cur, item.PackSize); cur += 12; + WriteOctal_12_Signed(cur, item.MTime); cur += 12; - memmove(cur, NFileHeader::kCheckSumBlanks, 8); + memset(cur, ' ', 8); cur += 8; *cur++ = item.LinkFlag; @@ -123,7 +106,7 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item) RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize)); cur += NFileHeader::kNameSize; - memmove(cur, item.Magic, 8); + memcpy(cur, item.Magic, 8); cur += 8; RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize)); @@ -132,64 +115,127 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item) cur += NFileHeader::kGroupNameSize; - if (item.DeviceMajorDefined) - RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMajor)); - cur += 8; + if (item.DeviceMajorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMajor)); cur += 8; + if (item.DeviceMinorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMinor)); cur += 8; - if (item.DeviceMinorDefined) - RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMinor)); - cur += 8; + if (item.IsSparse()) + { + record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0); + WriteOctal_12(record + 483, item.Size); + for (unsigned i = 0; i < item.SparseBlocks.Size() && i < 4; i++) + { + const CSparseBlock &sb = item.SparseBlocks[i]; + char *p = record + 386 + 24 * i; + WriteOctal_12(p, sb.Offset); + WriteOctal_12(p + 12, sb.Size); + } + } + { + UInt32 checkSum = 0; + { + for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) + checkSum += (Byte)record[i]; + } + /* we use GNU TAR scheme: + checksum field is formatted differently from the + other fields: it has [6] digits, a null, then a space. */ + // RETURN_IF_NOT_TRUE(WriteOctal_8(record + 148, checkSum)); + const unsigned kNumDigits = 6; + for (unsigned i = 0; i < kNumDigits; i++) + { + record[148 + kNumDigits - 1 - i] = (char)('0' + (checkSum & 7)); + checkSum >>= 3; + } + record[148 + 6] = 0; + } - UInt32 checkSumReal = 0; - for (i = 0; i < NFileHeader::kRecordSize; i++) - checkSumReal += Byte(record[i]); + RINOK(WriteBytes(record, NFileHeader::kRecordSize)); - RETURN_IF_NOT_TRUE(MakeOctalString8(record + 148, checkSumReal)); + if (item.IsSparse()) + { + for (unsigned i = 4; i < item.SparseBlocks.Size();) + { + memset(record, 0, NFileHeader::kRecordSize); + for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++) + { + const CSparseBlock &sb = item.SparseBlocks[i]; + char *p = record + 24 * t; + WriteOctal_12(p, sb.Offset); + WriteOctal_12(p + 12, sb.Size); + } + record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0); + RINOK(WriteBytes(record, NFileHeader::kRecordSize)); + } + } - return WriteBytes(record, NFileHeader::kRecordSize); + return S_OK; } HRESULT COutArchive::WriteHeader(const CItem &item) { - int nameSize = item.Name.Length(); - if (nameSize < NFileHeader::kNameSize) + unsigned nameSize = item.Name.Len(); + unsigned linkSize = item.LinkName.Len(); + + /* There two versions of GNU tar: + OLDGNU_FORMAT: it writes short name and zero at the end + GNU_FORMAT: it writes only short name without zero at the end + we write it as OLDGNU_FORMAT with zero at the end */ + + if (nameSize < NFileHeader::kNameSize && + linkSize < NFileHeader::kNameSize) return WriteHeaderReal(item); - CItem modifiedItem = item; - int nameStreamSize = nameSize + 1; - modifiedItem.PackSize = nameStreamSize; - modifiedItem.LinkFlag = 'L'; - modifiedItem.Name = NFileHeader::kLongLink; - modifiedItem.LinkName.Empty(); - RINOK(WriteHeaderReal(modifiedItem)); - RINOK(WriteBytes(item.Name, nameStreamSize)); - RINOK(FillDataResidual(nameStreamSize)); - - modifiedItem = item; - modifiedItem.Name = item.Name.Left(NFileHeader::kNameSize - 1); - return WriteHeaderReal(modifiedItem); + CItem mi = item; + mi.Name = NFileHeader::kLongLink; + mi.LinkName.Empty(); + for (int i = 0; i < 2; i++) + { + const AString *name; + // We suppose that GNU tar also writes item for long link before item for LongName? + if (i == 0) + { + mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink; + name = &item.LinkName; + } + else + { + mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName; + name = &item.Name; + } + if (name->Len() < NFileHeader::kNameSize) + continue; + unsigned nameStreamSize = name->Len() + 1; + mi.PackSize = nameStreamSize; + RINOK(WriteHeaderReal(mi)); + RINOK(WriteBytes((const char *)*name, nameStreamSize)); + RINOK(FillDataResidual(nameStreamSize)); + } + + mi = item; + if (mi.Name.Len() >= NFileHeader::kNameSize) + mi.Name.SetFrom(item.Name, NFileHeader::kNameSize - 1); + if (mi.LinkName.Len() >= NFileHeader::kNameSize) + mi.LinkName.SetFrom(item.LinkName, NFileHeader::kNameSize - 1); + return WriteHeaderReal(mi); } HRESULT COutArchive::FillDataResidual(UInt64 dataSize) { - UInt32 lastRecordSize = UInt32(dataSize & (NFileHeader::kRecordSize - 1)); + unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1)); if (lastRecordSize == 0) return S_OK; - UInt32 residualSize = NFileHeader::kRecordSize - lastRecordSize; - Byte residualBytes[NFileHeader::kRecordSize]; - for (UInt32 i = 0; i < residualSize; i++) - residualBytes[i] = 0; - return WriteBytes(residualBytes, residualSize); + unsigned rem = NFileHeader::kRecordSize - lastRecordSize; + Byte buf[NFileHeader::kRecordSize]; + memset(buf, 0, rem); + return WriteBytes(buf, rem); } HRESULT COutArchive::WriteFinishHeader() { Byte record[NFileHeader::kRecordSize]; - int i; - for (i = 0; i < NFileHeader::kRecordSize; i++) - record[i] = 0; - for (i = 0; i < 2; i++) + memset(record, 0, NFileHeader::kRecordSize); + for (unsigned i = 0; i < 2; i++) { RINOK(WriteBytes(record, NFileHeader::kRecordSize)); } diff --git a/CPP/7zip/Archive/Tar/TarOut.h b/CPP/7zip/Archive/Tar/TarOut.h index ef837869..ee9b965e 100755..100644 --- a/CPP/7zip/Archive/Tar/TarOut.h +++ b/CPP/7zip/Archive/Tar/TarOut.h @@ -3,21 +3,29 @@ #ifndef __ARCHIVE_TAR_OUT_H #define __ARCHIVE_TAR_OUT_H -#include "TarItem.h" +#include "../../../Common/MyCom.h" -#include "Common/MyCom.h" #include "../../IStream.h" +#include "TarItem.h" + namespace NArchive { namespace NTar { class COutArchive { CMyComPtr<ISequentialOutStream> m_Stream; - HRESULT WriteBytes(const void *buffer, UInt32 size); -public: - void Create(ISequentialOutStream *outStream); + + HRESULT WriteBytes(const void *data, unsigned size); HRESULT WriteHeaderReal(const CItem &item); +public: + UInt64 Pos; + + void Create(ISequentialOutStream *outStream) + { + m_Stream = outStream; + } + HRESULT WriteHeader(const CItem &item); HRESULT FillDataResidual(UInt64 dataSize); HRESULT WriteFinishHeader(); diff --git a/CPP/7zip/Archive/Tar/TarRegister.cpp b/CPP/7zip/Archive/Tar/TarRegister.cpp index e21c0aac..9e0f6f21 100755..100644 --- a/CPP/7zip/Archive/Tar/TarRegister.cpp +++ b/CPP/7zip/Archive/Tar/TarRegister.cpp @@ -5,14 +5,22 @@ #include "../../Common/RegisterArc.h" #include "TarHandler.h" -static IInArchive *CreateArc() { return new NArchive::NTar::CHandler; } -#ifndef EXTRACT_ONLY -static IOutArchive *CreateArcOut() { return new NArchive::NTar::CHandler; } -#else -#define CreateArcOut 0 -#endif + +namespace NArchive { +namespace NTar { + +IMP_CreateArcIn +IMP_CreateArcOut static CArcInfo g_ArcInfo = -{ L"tar", L"tar", 0, 0xEE, { 'u', 's', 't', 'a', 'r' }, 5, false, CreateArc, CreateArcOut }; + { "tar", "tar", 0, 0xEE, + 5, { 'u', 's', 't', 'a', 'r' }, + NFileHeader::kUstarMagic_Offset, + NArcInfoFlags::kStartOpen | + NArcInfoFlags::kSymLinks | + NArcInfoFlags::kHardLinks, + REF_CreateArc_Pair, IsArc_Tar }; REGISTER_ARC(Tar) + +}} diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp index fb123169..fdbce395 100755..100644 --- a/CPP/7zip/Archive/Tar/TarUpdate.cpp +++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp @@ -2,6 +2,8 @@ #include "StdAfx.h" +#include "../../../Windows/TimeUtils.h" + #include "../../Common/LimitedStreams.h" #include "../../Common/ProgressUtils.h" @@ -13,18 +15,26 @@ namespace NArchive { namespace NTar { +HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, + AString &res, UINT codePage, bool convertSlash = false); + HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, const CObjectVector<NArchive::NTar::CItemEx> &inputItems, const CObjectVector<CUpdateItem> &updateItems, + UINT codePage, IArchiveUpdateCallback *updateCallback) { COutArchive outArchive; outArchive.Create(outStream); + outArchive.Pos = 0; + + CMyComPtr<IOutStream> outSeekStream; + outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream); UInt64 complexity = 0; - int i; - for(i = 0; i < updateItems.Size(); i++) + unsigned i; + for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; if (ui.NewData) @@ -76,37 +86,101 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, item.DeviceMinorDefined = false; item.UID = 0; item.GID = 0; - memmove(item.Magic, NFileHeader::NMagic::kEmpty, 8); + memcpy(item.Magic, NFileHeader::NMagic::kUsTar_00, 8); } else item = inputItems[ui.IndexInArchive]; + AString symLink; + if (ui.NewData || ui.NewProps) + { + RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink, codePage, true)); + if (!symLink.IsEmpty()) + { + item.LinkFlag = NFileHeader::NLinkFlag::kSymLink; + item.LinkName = symLink; + } + } + if (ui.NewData) { + item.SparseBlocks.Clear(); item.PackSize = ui.Size; + item.Size = ui.Size; if (ui.Size == (UInt64)(Int64)-1) return E_INVALIDARG; - } - else - item.PackSize = inputItems[ui.IndexInArchive].PackSize; - - if (ui.NewData) - { + CMyComPtr<ISequentialInStream> fileInStream; - HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); - if (res != S_FALSE) + + bool needWrite = true; + if (!symLink.IsEmpty()) { - RINOK(res); + item.PackSize = 0; + item.Size = 0; + } + else + { + HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); + if (res == S_FALSE) + needWrite = false; + else + { + RINOK(res); + + if (fileInStream) + { + CMyComPtr<IStreamGetProps> getProps; + fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); + if (getProps) + { + FILETIME mTime; + UInt64 size2; + if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK) + { + item.PackSize = size2; + item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);; + } + } + } + { + AString hardLink; + RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, codePage, true)); + if (!hardLink.IsEmpty()) + { + item.LinkFlag = NFileHeader::NLinkFlag::kHardLink; + item.LinkName = hardLink; + item.PackSize = 0; + item.Size = 0; + fileInStream.Release(); + } + } + } + } + + if (needWrite) + { + UInt64 fileHeaderStartPos = outArchive.Pos; RINOK(outArchive.WriteHeader(item)); - if (!ui.IsDir) + if (fileInStream) { RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress)); + outArchive.Pos += copyCoderSpec->TotalSize; if (copyCoderSpec->TotalSize != item.PackSize) - return E_FAIL; + { + if (!outSeekStream) + return E_FAIL; + UInt64 backOffset = outArchive.Pos - fileHeaderStartPos; + RINOK(outSeekStream->Seek(-(Int64)backOffset, STREAM_SEEK_CUR, NULL)); + outArchive.Pos = fileHeaderStartPos; + item.PackSize = copyCoderSpec->TotalSize; + RINOK(outArchive.WriteHeader(item)); + RINOK(outSeekStream->Seek(item.PackSize, STREAM_SEEK_CUR, NULL)); + outArchive.Pos += item.PackSize; + } RINOK(outArchive.FillDataResidual(item.PackSize)); } } - complexity += ui.Size; + complexity += item.PackSize; RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } else @@ -115,6 +189,30 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, UInt64 size; if (ui.NewProps) { + // memcpy(item.Magic, NFileHeader::NMagic::kEmpty, 8); + + if (!symLink.IsEmpty()) + { + item.PackSize = 0; + item.Size = 0; + } + else + { + if (ui.IsDir == existItem.IsDir()) + item.LinkFlag = existItem.LinkFlag; + + item.SparseBlocks = existItem.SparseBlocks; + item.Size = existItem.Size; + item.PackSize = existItem.PackSize; + } + + item.DeviceMajorDefined = existItem.DeviceMajorDefined; + item.DeviceMinorDefined = existItem.DeviceMinorDefined; + item.DeviceMajor = existItem.DeviceMajor; + item.DeviceMinor = existItem.DeviceMinor; + item.UID = existItem.UID; + item.GID = existItem.GID; + RINOK(outArchive.WriteHeader(item)); RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL)); size = existItem.PackSize; @@ -129,6 +227,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); if (copyCoderSpec->TotalSize != size) return E_FAIL; + outArchive.Pos += size; RINOK(outArchive.FillDataResidual(existItem.PackSize)); complexity += size; } diff --git a/CPP/7zip/Archive/Tar/TarUpdate.h b/CPP/7zip/Archive/Tar/TarUpdate.h index 3f889739..c2393416 100755..100644 --- a/CPP/7zip/Archive/Tar/TarUpdate.h +++ b/CPP/7zip/Archive/Tar/TarUpdate.h @@ -27,6 +27,7 @@ struct CUpdateItem HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, const CObjectVector<CItemEx> &inputItems, const CObjectVector<CUpdateItem> &updateItems, + UINT codePage, IArchiveUpdateCallback *updateCallback); }} diff --git a/CPP/7zip/Archive/Udf/StdAfx.h b/CPP/7zip/Archive/Udf/StdAfx.h index 2e4be10b..2854ff3e 100755..100644 --- a/CPP/7zip/Archive/Udf/StdAfx.h +++ b/CPP/7zip/Archive/Udf/StdAfx.h @@ -3,7 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" -#include "../../../Common/NewHandler.h" +#include "../../../Common/Common.h" #endif diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp index c7085272..6aa53ea9 100755..100644 --- a/CPP/7zip/Archive/Udf/UdfHandler.cpp +++ b/CPP/7zip/Archive/Udf/UdfHandler.cpp @@ -2,13 +2,14 @@ #include "StdAfx.h" -#include "Common/ComTry.h" +#include "../../../Common/ComTry.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" #include "../../Common/LimitedStreams.h" #include "../../Common/ProgressUtils.h" +#include "../../Common/RegisterArc.h" #include "../../Common/StreamObjects.h" #include "../../Compress/CopyCoder.h" @@ -18,7 +19,7 @@ namespace NArchive { namespace NUdf { -void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop) +static void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop) { UInt64 numSecs; const Byte *d = t.Data; @@ -33,21 +34,21 @@ void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop) prop = ft; } -static STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidATime, VT_FILETIME} + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidATime }; -static STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidComment, VT_BSTR}, - { NULL, kpidClusterSize, VT_UI4}, - { NULL, kpidCTime, VT_FILETIME} + kpidComment, + kpidClusterSize, + kpidCTime }; IMP_IInArchive_Props @@ -59,6 +60,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) NWindows::NCOM::CPropVariant prop; switch(propID) { + case kpidPhySize: prop = _archive.PhySize; break; + case kpidComment: { UString comment = _archive.GetComment(); @@ -71,7 +74,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) if (_archive.LogVols.Size() > 0) { UInt32 blockSize = _archive.LogVols[0].BlockSize; - int i; + unsigned i; for (i = 1; i < _archive.LogVols.Size(); i++) if (_archive.LogVols[i].BlockSize != blockSize) break; @@ -88,6 +91,16 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) UdfTimeToFileTime(vol.FileSets[0].RecodringTime, prop); } break; + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; + if (_archive.Unsupported) v |= kpv_ErrorFlags_UnsupportedFeature; + if (_archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + prop = v; + break; + } } prop.Detach(value); return S_OK; @@ -127,9 +140,7 @@ HRESULT CProgressImp::SetCompleted() return S_OK; } -STDMETHODIMP CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback *callback) +STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback) { COM_TRY_BEGIN { @@ -137,14 +148,14 @@ STDMETHODIMP CHandler::Open(IInStream *stream, CProgressImp progressImp(callback); RINOK(_archive.Open(stream, &progressImp)); bool showVolName = (_archive.LogVols.Size() > 1); - for (int volIndex = 0; volIndex < _archive.LogVols.Size(); volIndex++) + FOR_VECTOR (volIndex, _archive.LogVols) { const CLogVol &vol = _archive.LogVols[volIndex]; bool showFileSetName = (vol.FileSets.Size() > 1); - for (int fsIndex = 0; fsIndex < vol.FileSets.Size(); fsIndex++) + FOR_VECTOR (fsIndex, vol.FileSets) { const CFileSet &fs = vol.FileSets[fsIndex]; - for (int i = ((showVolName || showFileSetName) ? 0 : 1); i < fs.Refs.Size(); i++) + for (unsigned i = ((showVolName || showFileSetName) ? 0 : 1); i < fs.Refs.Size(); i++) { CRef2 ref2; ref2.Vol = volIndex; @@ -184,7 +195,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref]; const CFile &file = _archive.Files[ref.FileIndex]; const CItem &item = _archive.Items[file.ItemIndex]; - switch(propID) + switch (propID) { case kpidPath: prop = _archive.GetItemPath(ref2.Vol, ref2.Fs, ref2.Ref, _archive.LogVols.Size() > 1, vol.FileSets.Size() > 1); break; @@ -200,99 +211,6 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_END } -struct CSeekExtent -{ - UInt64 Phy; - UInt64 Virt; -}; - -class CExtentsStream: - public IInStream, - public CMyUnknownImp -{ - UInt64 _phyPos; - UInt64 _virtPos; - bool _needStartSeek; - - HRESULT SeekToPhys() { return Stream->Seek(_phyPos, STREAM_SEEK_SET, NULL); } - -public: - CMyComPtr<IInStream> Stream; - CRecordVector<CSeekExtent> Extents; - - MY_UNKNOWN_IMP1(IInStream) - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); - void ReleaseStream() { Stream.Release(); } - - void Init() - { - _virtPos = 0; - _phyPos = 0; - _needStartSeek = true; - } - -}; - - -STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize) -{ - if (processedSize) - *processedSize = 0; - if (size > 0) - { - UInt64 totalSize = Extents.Back().Virt; - if (_virtPos >= totalSize) - return (_virtPos == totalSize) ? S_OK : E_FAIL; - int left = 0, right = Extents.Size() - 1; - for (;;) - { - int mid = (left + right) / 2; - if (mid == left) - break; - if (_virtPos < Extents[mid].Virt) - right = mid; - else - left = mid; - } - - const CSeekExtent &extent = Extents[left]; - UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt); - if (_needStartSeek || _phyPos != phyPos) - { - _needStartSeek = false; - _phyPos = phyPos; - RINOK(SeekToPhys()); - } - - UInt64 rem = Extents[left + 1].Virt - _virtPos; - if (size > rem) - size = (UInt32)rem; - - HRESULT res = Stream->Read(data, size, &size); - _phyPos += size; - _virtPos += size; - if (processedSize) - *processedSize = size; - return res; - } - return S_OK; -} - -STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) -{ - switch(seekOrigin) - { - case STREAM_SEEK_SET: _virtPos = offset; break; - case STREAM_SEEK_CUR: _virtPos += offset; break; - case STREAM_SEEK_END: _virtPos = Extents.Back().Virt + offset; break; - default: return STG_E_INVALIDFUNCTION; - } - if (newPosition) - *newPosition = _virtPos; - return S_OK; -} - STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) { *stream = 0; @@ -325,7 +243,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) extentStreamSpec->Stream = _inStream; UInt64 virtOffset = 0; - for (int extentIndex = 0; extentIndex < item.Extents.Size(); extentIndex++) + FOR_VECTOR (extentIndex, item.Extents) { const CMyExtent &extent = item.Extents[extentIndex]; UInt32 len = extent.GetLen(); @@ -363,7 +281,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _refs2.Size(); if (numItems == 0) @@ -431,7 +349,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ISequentialInStream> udfInStream; HRESULT res = GetStream(index, &udfInStream); if (res == E_NOTIMPL) - opRes = NExtract::NOperationResult::kUnSupportedMethod; + opRes = NExtract::NOperationResult::kUnsupportedMethod; else if (res != S_OK) opRes = NExtract::NOperationResult::kDataError; else @@ -448,4 +366,18 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } +IMP_CreateArcIn + +static const UInt32 kIsoStartPos = 0x8000; + +static CArcInfo g_ArcInfo = + { "Udf", "udf iso img", 0, 0xE0, + // 5, { 0, 'N', 'S', 'R', '0' }, + 6, { 1, 'C', 'D', '0', '0', '1' }, + kIsoStartPos, + NArcInfoFlags::kStartOpen, + CreateArc, NULL, IsArc_Udf }; + +REGISTER_ARC(Udf) + }} diff --git a/CPP/7zip/Archive/Udf/UdfHandler.h b/CPP/7zip/Archive/Udf/UdfHandler.h index f513727d..da44b232 100755..100644 --- a/CPP/7zip/Archive/Udf/UdfHandler.h +++ b/CPP/7zip/Archive/Udf/UdfHandler.h @@ -1,9 +1,10 @@ -// Udf/Handler.h +// UdfHandler.h #ifndef __UDF_HANDLER_H #define __UDF_HANDLER_H -#include "Common/MyCom.h" +#include "../../../Common/MyCom.h" + #include "../IArchive.h" #include "UdfIn.h" @@ -13,9 +14,9 @@ namespace NUdf { struct CRef2 { - int Vol; - int Fs; - int Ref; + unsigned Vol; + unsigned Fs; + unsigned Ref; }; class CHandler: diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp index d2a2884f..3053a0c1 100755..100644 --- a/CPP/7zip/Archive/Udf/UdfIn.cpp +++ b/CPP/7zip/Archive/Udf/UdfIn.cpp @@ -2,12 +2,25 @@ #include "StdAfx.h" +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include <stdio.h> +#endif + #include "../../../../C/CpuArch.h" +#include "../../Common/RegisterArc.h" #include "../../Common/StreamUtils.h" #include "UdfIn.h" +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + #define Get16(p) GetUi16(p) #define Get32(p) GetUi32(p) #define Get64(p) GetUi64(p) @@ -15,24 +28,22 @@ namespace NArchive { namespace NUdf { -const int kNumPartitionsMax = 64; -const int kNumLogVolumesMax = 64; -const int kNumRecureseLevelsMax = 1 << 10; -const int kNumItemsMax = 1 << 27; -const int kNumFilesMax = 1 << 28; -const int kNumRefsMax = 1 << 28; -const UInt32 kNumExtentsMax = (UInt32)1 << 30; -const UInt64 kFileNameLengthTotalMax = (UInt64)1 << 33; -const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33; - -void MY_FAST_CALL Crc16GenerateTable(void); +static const unsigned kNumPartitionsMax = 64; +static const unsigned kNumLogVolumesMax = 64; +static const unsigned kNumRecursionLevelsMax = 1 << 10; +static const unsigned kNumItemsMax = 1 << 27; +static const unsigned kNumFilesMax = 1 << 28; +static const unsigned kNumRefsMax = 1 << 28; +static const UInt32 kNumExtentsMax = (UInt32)1 << 30; +static const UInt64 kFileNameLengthTotalMax = (UInt64)1 << 33; +static const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33; #define CRC16_INIT_VAL 0 #define CRC16_GET_DIGEST(crc) (crc) -#define CRC16_UPDATE_BYTE(crc, b) (g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8)) +#define CRC16_UPDATE_BYTE(crc, b) ((UInt16)(g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8))) #define kCrc16Poly 0x1021 -UInt16 g_Crc16Table[256]; +static UInt16 g_Crc16Table[256]; void MY_FAST_CALL Crc16GenerateTable(void) { @@ -61,15 +72,14 @@ UInt16 MY_FAST_CALL Crc16Calc(const void *data, size_t size) struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit; -void CDString128::Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } + void CDString::Parse(const Byte *p, unsigned size) { - Data.SetCapacity(size); - memcpy(Data, p, size); + Data.CopyFrom(p, size); } -static UString ParseDString(const Byte *data, int size) +static UString ParseDString(const Byte *data, unsigned size) { UString res; wchar_t *p; @@ -78,8 +88,8 @@ static UString ParseDString(const Byte *data, int size) Byte type = data[0]; if (type == 8) { - p = res.GetBuffer((int)size + 1); - for (int i = 1; i < size; i++) + p = res.GetBuffer(size); + for (unsigned i = 1; i < size; i++) { wchar_t c = data[i]; if (c == 0) @@ -89,10 +99,10 @@ static UString ParseDString(const Byte *data, int size) } else if (type == 16) { - p = res.GetBuffer((int)size / 2 + 1); - for (int i = 1; i + 2 <= size; i += 2) + p = res.GetBuffer(size / 2); + for (unsigned i = 1; i + 2 <= size; i += 2) { - wchar_t c = ((wchar_t)data[i] << 8) | data[i + 1]; + wchar_t c = GetBe16(data + i); if (c == 0) break; *p++ = c; @@ -106,13 +116,14 @@ static UString ParseDString(const Byte *data, int size) return res; } -UString CDString:: GetString() const { return ParseDString(Data, (int)Data.GetCapacity()); } UString CDString128::GetString() const { - int size = Data[sizeof(Data) - 1]; - return ParseDString(Data, MyMin(size, (int)(sizeof(Data) - 1))); + unsigned size = Data[sizeof(Data) - 1]; + return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1))); } +UString CDString::GetString() const { return ParseDString(Data, (unsigned)Data.Size()); } + void CTime::Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } /* @@ -161,8 +172,8 @@ HRESULT CTag::Parse(const Byte *buf, size_t size) return S_FALSE; Byte sum = 0; int i; - for (i = 0; i < 4; i++) sum = sum + buf[i]; - for (i = 5; i < 16; i++) sum = sum + buf[i]; + for (i = 0; i < 4; i++) sum = (Byte)(sum + buf[i]); + for (i = 5; i < 16; i++) sum = (Byte)(sum + buf[i]); if (sum != buf[4] || buf[5] != 0) return S_FALSE; Id = Get16(buf); @@ -182,27 +193,27 @@ HRESULT CTag::Parse(const Byte *buf, size_t size) enum EDescriptorType { - DESC_TYPE_SpoaringTable = 0, // UDF - DESC_TYPE_PrimVol = 1, - DESC_TYPE_AnchorVolPtr = 2, - DESC_TYPE_VolPtr = 3, - DESC_TYPE_ImplUseVol = 4, - DESC_TYPE_Partition = 5, - DESC_TYPE_LogicalVol = 6, - DESC_TYPE_UnallocSpace = 7, - DESC_TYPE_Terminating = 8, + DESC_TYPE_SpoaringTable = 0, // UDF + DESC_TYPE_PrimVol = 1, + DESC_TYPE_AnchorVolPtr = 2, + DESC_TYPE_VolPtr = 3, + DESC_TYPE_ImplUseVol = 4, + DESC_TYPE_Partition = 5, + DESC_TYPE_LogicalVol = 6, + DESC_TYPE_UnallocSpace = 7, + DESC_TYPE_Terminating = 8, DESC_TYPE_LogicalVolIntegrity = 9, - DESC_TYPE_FileSet = 256, - DESC_TYPE_FileId = 257, - DESC_TYPE_AllocationExtent = 258, - DESC_TYPE_Indirect = 259, - DESC_TYPE_Terminal = 260, - DESC_TYPE_File = 261, - DESC_TYPE_ExtendedAttrHeader = 262, - DESC_TYPE_UnallocatedSpace = 263, - DESC_TYPE_SpaceBitmap = 264, - DESC_TYPE_PartitionIntegrity = 265, - DESC_TYPE_ExtendedFile = 266 + DESC_TYPE_FileSet = 256, + DESC_TYPE_FileId = 257, + DESC_TYPE_AllocationExtent = 258, + DESC_TYPE_Indirect = 259, + DESC_TYPE_Terminal = 260, + DESC_TYPE_File = 261, + DESC_TYPE_ExtendedAttrHeader = 262, + DESC_TYPE_UnallocatedSpace = 263, + DESC_TYPE_SpaceBitmap = 264, + DESC_TYPE_PartitionIntegrity = 265, + DESC_TYPE_ExtendedFile = 266 }; @@ -237,6 +248,8 @@ void CLongAllocDesc::Parse(const Byte *buf) bool CInArchive::CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const { const CLogVol &vol = LogVols[volIndex]; + if (partitionRef >= (int)vol.PartitionMaps.Size()) + return false; const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; return (offset + len) <= (((UInt64)partition.Pos + partition.Len) << SecLogSize); @@ -244,7 +257,7 @@ bool CInArchive::CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UI bool CInArchive::CheckItemExtents(int volIndex, const CItem &item) const { - for (int i = 0; i < item.Extents.Size(); i++) + FOR_VECTOR (i, item.Extents) { const CMyExtent &e = item.Extents[i]; if (!CheckExtent(volIndex, e.PartitionRef, e.Pos, e.GetLen())) @@ -259,9 +272,14 @@ HRESULT CInArchive::Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 return S_FALSE; const CLogVol &vol = LogVols[volIndex]; const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; - RINOK(_stream->Seek(((UInt64)partition.Pos << SecLogSize) + - (UInt64)blockPos * vol.BlockSize, STREAM_SEEK_SET, NULL)); - return ReadStream_FALSE(_stream, buf, len); + UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; + RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); + HRESULT res = ReadStream_FALSE(_stream, buf, len); + if (res == S_FALSE && offset + len > FileSize) + UnexpectedEnd = true; + RINOK(res); + UpdatePhySize(offset + len); + return S_OK; } HRESULT CInArchive::Read(int volIndex, const CLongAllocDesc &lad, Byte *buf) @@ -278,9 +296,9 @@ HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &b buf = item.InlineData; return S_OK; } - buf.SetCapacity((size_t)item.Size); + buf.Alloc((size_t)item.Size); size_t pos = 0; - for (int i = 0; i < item.Extents.Size(); i++) + FOR_VECTOR (i, item.Extents) { const CMyExtent &e = item.Extents[i]; UInt32 len = e.GetLen(); @@ -407,9 +425,8 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la if (lad.GetLen() != vol.BlockSize) return S_FALSE; - CByteBuffer buf; size_t size = lad.GetLen(); - buf.SetCapacity(size); + CByteBuffer buf(size); RINOK(Read(volIndex, lad, buf)); CTag tag; @@ -456,8 +473,7 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la if (desctType == ICB_DESC_TYPE_INLINE) { item.IsInline = true; - item.InlineData.SetCapacity(allocDescriptorsLen); - memcpy(item.InlineData, p + pos, allocDescriptorsLen); + item.InlineData.CopyFrom(p + pos, allocDescriptorsLen); } else { @@ -504,7 +520,7 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la item.InlineData.Free(); const Byte *p = buf; - size = buf.GetCapacity(); + size = buf.Size(); size_t processedTotal = 0; for (; processedTotal < size;) { @@ -519,7 +535,7 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la // file.ImplUse = fileId.ImplUse; file.Id = fileId.Id; - _fileNameLengthTotal += file.Id.Data.GetCapacity(); + _fileNameLengthTotal += file.Id.Data.Size(); if (_fileNameLengthTotal > kFileNameLengthTotalMax) return S_FALSE; @@ -538,9 +554,9 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la return S_FALSE; _numExtents += item.Extents.Size(); - if (item.InlineData.GetCapacity() > kInlineExtentsSizeMax - _inlineExtentsSize) + if (item.InlineData.Size() > kInlineExtentsSizeMax - _inlineExtentsSize) return S_FALSE; - _inlineExtentsSize += item.InlineData.GetCapacity(); + _inlineExtentsSize += item.InlineData.Size(); } return S_OK; @@ -548,7 +564,7 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la HRESULT CInArchive::FillRefs(CFileSet &fs, int fileIndex, int parent, int numRecurseAllowed) { - if (_numRefs % 10000 == 0) + if ((_numRefs & 0xFFF) == 0) { RINOK(_progress->SetCompleted()); } @@ -563,23 +579,47 @@ HRESULT CInArchive::FillRefs(CFileSet &fs, int fileIndex, int parent, int numRec parent = fs.Refs.Size(); fs.Refs.Add(ref); const CItem &item = Items[Files[fileIndex].ItemIndex]; - for (int i = 0; i < item.SubFiles.Size(); i++) + FOR_VECTOR (i, item.SubFiles) { RINOK(FillRefs(fs, item.SubFiles[i], parent, numRecurseAllowed)); } return S_OK; } +API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size) +{ + UInt32 res = k_IsArc_Res_NO; + unsigned SecLogSize; + for (SecLogSize = 11;; SecLogSize -= 3) + { + if (SecLogSize < 8) + return res; + UInt32 offset = (UInt32)256 << SecLogSize; + size_t bufSize = 1 << SecLogSize; + if (offset + bufSize > size) + res = k_IsArc_Res_NEED_MORE; + else + { + CTag tag; + if (tag.Parse(p + offset, bufSize) == S_OK) + if (tag.Id == DESC_TYPE_AnchorVolPtr) + return k_IsArc_Res_YES; + } + } +} + HRESULT CInArchive::Open2() { Clear(); + UInt64 fileSize; + RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize)); + FileSize = fileSize; // Some UDFs contain additional pad zeros (2 KB). // Seek to STREAM_SEEK_END for direct DVD reading can return 8 KB more, so we check last 16 KB. // And when we read last block, result read size can be smaller than required size. - UInt64 fileSize; - RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize)); + /* const size_t kBufSize = 1 << 14; Byte buf[kBufSize]; size_t readSize = (fileSize < kBufSize) ? (size_t)fileSize : kBufSize; @@ -598,22 +638,69 @@ HRESULT CInArchive::Open2() if (tag.Id == DESC_TYPE_AnchorVolPtr) break; } - + PhySize = fileSize; CExtent extentVDS; extentVDS.Parse(buf + i + 16); + */ + const size_t kBufSize = 1 << 11; + Byte buf[kBufSize]; + for (SecLogSize = 11;; SecLogSize -= 3) + { + if (SecLogSize < 8) + return S_FALSE; + UInt32 offset = (UInt32)256 << SecLogSize; + if (offset >= fileSize) + continue; + RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); + size_t bufSize = 1 << SecLogSize; + size_t readSize = bufSize; + RINOK(ReadStream(_stream, buf, &readSize)); + if (readSize == bufSize) + { + CTag tag; + if (tag.Parse(buf, readSize) == S_OK) + if (tag.Id == DESC_TYPE_AnchorVolPtr) + break; + } + } + PhySize = (UInt32)(256 + 1) << SecLogSize; + IsArc = true; - for (UInt32 location = extentVDS.Pos; ; location++) + CExtent extentVDS; + extentVDS.Parse(buf + 16); + { + CExtent extentVDS2; + extentVDS2.Parse(buf + 24); + UpdatePhySize(((UInt64)extentVDS.Pos << SecLogSize) + extentVDS.Len); + UpdatePhySize(((UInt64)extentVDS2.Pos << SecLogSize) + extentVDS2.Len); + } + + for (UInt32 location = 0; ; location++) { size_t bufSize = 1 << SecLogSize; size_t pos = 0; - RINOK(_stream->Seek((UInt64)location << SecLogSize, STREAM_SEEK_SET, NULL)); - RINOK(ReadStream_FALSE(_stream, buf, bufSize)); + if (((UInt64)(location + 1) << SecLogSize) > extentVDS.Len) + return S_FALSE; + + UInt64 offs = (UInt64)(extentVDS.Pos + location) << SecLogSize; + RINOK(_stream->Seek(offs, STREAM_SEEK_SET, NULL)); + HRESULT res = ReadStream_FALSE(_stream, buf, bufSize); + if (res == S_FALSE && offs + bufSize > FileSize) + UnexpectedEnd = true; + RINOK(res); + + CTag tag; RINOK(tag.Parse(buf + pos, bufSize - pos)); if (tag.Id == DESC_TYPE_Terminating) break; + if (tag.Id == DESC_TYPE_Partition) { + // Partition Descriptor + // ECMA 167 3/10.5 + // UDF / 2.2.14 + if (Partitions.Size() >= kNumPartitionsMax) return S_FALSE; CPartition partition; @@ -631,10 +718,15 @@ HRESULT CInArchive::Open2() // partition.ImplId.Parse(buf + 196); // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse)); + PRF(printf("\nPartition number = %2d pos = %d len = %d", partition.Number, partition.Pos, partition.Len)); Partitions.Add(partition); } else if (tag.Id == DESC_TYPE_LogicalVol) { + /* Logical Volume Descriptor + ECMA 3/10.6 + UDF 2.60 2.2.4 */ + if (LogVols.Size() >= kNumLogVolumesMax) return S_FALSE; CLogVol vol; @@ -647,6 +739,8 @@ HRESULT CInArchive::Open2() // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse)); vol.FileSetLocation.Parse(buf + 248); + /* the extent in which the first File Set Descriptor Sequence + of the logical volume is recorded */ // UInt32 mapTableLength = Get32(buf + 264); UInt32 numPartitionMaps = Get32(buf + 268); @@ -654,6 +748,8 @@ HRESULT CInArchive::Open2() return S_FALSE; // vol.ImplId.Parse(buf + 272); // memcpy(vol.ImplUse, buf + 128, sizeof(vol.ImplUse)); + + PRF(printf("\nLogicalVol numPartitionMaps = %2d", numPartitionMaps)); size_t pos = 440; for (UInt32 i = 0; i < numPartitionMaps; i++) { @@ -670,10 +766,33 @@ HRESULT CInArchive::Open2() // memcpy(pm.Data, buf + pos + 2, pm.Length - 2); if (pm.Type == 1) { - if (pos + 6 > bufSize) + if (len != 6) // < 6 return S_FALSE; // pm.VolSeqNumber = Get16(buf + pos + 2); pm.PartitionNumber = Get16(buf + pos + 4); + PRF(printf("\nPartitionMap type 1 PartitionNumber = %2d", pm.PartitionNumber)); + } + else if (pm.Type == 2) + { + if (len != 64) + return S_FALSE; + /* ECMA 10.7.3 / Type 2 Partition Map + 62 bytes: Partition Identifier. */ + + /* UDF 2.6 + 2.2.8 Virtual Partition Map + This is an extension of ECMA 167 to expand its scope to include + sequentially written media (eg. CD-R). This extension is for a + Partition Map entry to describe a virtual space. */ + + // It's not implemented still. + if (Get16(buf + pos + 2) != 0) + return S_FALSE; + // pm.VolSeqNumber = Get16(buf + pos + 36); + pm.PartitionNumber = Get16(buf + pos + 38); + PRF(printf("\nPartitionMap type 2 PartitionNumber = %2d", pm.PartitionNumber)); + // Unsupported = true; + return S_FALSE; } else return S_FALSE; @@ -686,21 +805,26 @@ HRESULT CInArchive::Open2() UInt64 totalSize = 0; - int volIndex; + unsigned volIndex; for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) { CLogVol &vol = LogVols[volIndex]; - for (int pmIndex = 0; pmIndex < vol.PartitionMaps.Size(); pmIndex++) + FOR_VECTOR (pmIndex, vol.PartitionMaps) { CPartitionMap &pm = vol.PartitionMaps[pmIndex]; - int i; + unsigned i; for (i = 0; i < Partitions.Size(); i++) { CPartition &part = Partitions[i]; if (part.Number == pm.PartitionNumber) { if (part.VolIndex >= 0) - return S_FALSE; + { + // it's for 2.60. Fix it + if (part.VolIndex != (int)volIndex) + return S_FALSE; + // return S_FALSE; + } pm.PartitionIndex = i; part.VolIndex = volIndex; @@ -715,27 +839,39 @@ HRESULT CInArchive::Open2() RINOK(_progress->SetTotal(totalSize)); + PRF(printf("\n Read files")); + for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) { CLogVol &vol = LogVols[volIndex]; + PRF(printf("\nLogVol %2d", volIndex)); + CLongAllocDesc nextExtent = vol.FileSetLocation; // while (nextExtent.ExtentLen != 0) // for (int i = 0; i < 1; i++) { if (nextExtent.GetLen() < 512) return S_FALSE; - CByteBuffer buf; - buf.SetCapacity(nextExtent.GetLen()); + CByteBuffer buf(nextExtent.GetLen()); RINOK(Read(volIndex, nextExtent, buf)); const Byte *p = buf; size_t size = nextExtent.GetLen(); CTag tag; RINOK(tag.Parse(p, size)); + + if (tag.Id == DESC_TYPE_ExtendedFile) + { + // ECMA 4 / 14.17 + // 2.60 ?? + return S_FALSE; + } + if (tag.Id != DESC_TYPE_FileSet) return S_FALSE; + PRF(printf("\n FileSet", volIndex)); CFileSet fs; fs.RecodringTime.Parse(p + 16); // fs.InterchangeLevel = Get16(p + 18); @@ -757,16 +893,76 @@ HRESULT CInArchive::Open2() // nextExtent.Parse(p + 448); } - for (int fsIndex = 0; fsIndex < vol.FileSets.Size(); fsIndex++) + FOR_VECTOR (fsIndex, vol.FileSets) { CFileSet &fs = vol.FileSets[fsIndex]; - int fileIndex = Files.Size(); - Files.Add(CFile()); - RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, kNumRecureseLevelsMax)); - RINOK(FillRefs(fs, fileIndex, -1, kNumRecureseLevelsMax)); + unsigned fileIndex = Files.Size(); + Files.AddNew(); + RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, kNumRecursionLevelsMax)); + RINOK(FillRefs(fs, fileIndex, -1, kNumRecursionLevelsMax)); + } + } + + + for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) + { + const CLogVol &vol = LogVols[volIndex]; + // bool showFileSetName = (vol.FileSets.Size() > 1); + FOR_VECTOR (fsIndex, vol.FileSets) + { + const CFileSet &fs = vol.FileSets[fsIndex]; + for (unsigned i = + // ((showVolName || showFileSetName) ? 0 : 1) + 0; i < fs.Refs.Size(); i++) + { + const CRef &ref = vol.FileSets[fsIndex].Refs[i]; + const CFile &file = Files[ref.FileIndex]; + const CItem &item = Items[file.ItemIndex]; + UInt64 size = item.Size; + + if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || !CheckItemExtents(volIndex, item)) + continue; + + FOR_VECTOR (extentIndex, item.Extents) + { + const CMyExtent &extent = item.Extents[extentIndex]; + UInt32 len = extent.GetLen(); + if (len == 0) + continue; + if (size < len) + break; + + int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; + UInt32 logBlockNumber = extent.Pos; + const CPartition &partition = Partitions[partitionIndex]; + UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + + (UInt64)logBlockNumber * vol.BlockSize; + UpdatePhySize(offset + len); + } + } } } + { + UInt32 secMask = ((UInt32)1 << SecLogSize) - 1; + PhySize = (PhySize + secMask) & ~(UInt64)secMask; + } + if (PhySize < fileSize) + { + RINOK(_stream->Seek(PhySize, STREAM_SEEK_SET, NULL)); + size_t bufSize = 1 << SecLogSize; + size_t readSize = bufSize; + RINOK(ReadStream(_stream, buf, &readSize)); + if (readSize == bufSize) + { + CTag tag; + if (tag.Parse(buf, readSize) == S_OK) + if (tag.Id == DESC_TYPE_AnchorVolPtr) + { + PhySize += bufSize; + } + } + } return S_OK; } @@ -774,15 +970,38 @@ HRESULT CInArchive::Open(IInStream *inStream, CProgressVirt *progress) { _progress = progress; _stream = inStream; + HRESULT res = Open2(); + if (res == S_FALSE && IsArc && !UnexpectedEnd) + Unsupported = true; + return res; + + /* HRESULT res; - try { res = Open2(); } - catch(...) { Clear(); res = S_FALSE; } + try + { + res = Open2(); + } + catch(...) + { + // Clear(); + // res = S_FALSE; + _stream.Release(); + throw; + } _stream.Release(); return res; + */ } void CInArchive::Clear() { + IsArc = false; + Unsupported = false; + UnexpectedEnd = false; + + PhySize = 0; + FileSize = 0; + Partitions.Clear(); LogVols.Clear(); Items.Clear(); @@ -797,7 +1016,7 @@ void CInArchive::Clear() UString CInArchive::GetComment() const { UString res; - for (int i = 0; i < LogVols.Size(); i++) + FOR_VECTOR (i, LogVols) { if (i > 0) res += L" "; @@ -827,7 +1046,7 @@ static void UpdateWithName(UString &res, const UString &addString) if (res.IsEmpty()) res = addString; else - res = addString + WCHAR_PATH_SEPARATOR + res; + res.Insert(0, addString + WCHAR_PATH_SEPARATOR); } UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex, @@ -851,7 +1070,7 @@ UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex, if (showFsName) { wchar_t s[32]; - ConvertUInt64ToString(fsIndex, s); + ConvertUInt32ToString(fsIndex, s); UString newName = L"File Set "; newName += s; UpdateWithName(name, newName); @@ -860,7 +1079,7 @@ UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex, if (showVolName) { wchar_t s[32]; - ConvertUInt64ToString(volIndex, s); + ConvertUInt32ToString(volIndex, s); UString newName = s; UString newName2 = vol.GetName(); if (newName2.IsEmpty()) diff --git a/CPP/7zip/Archive/Udf/UdfIn.h b/CPP/7zip/Archive/Udf/UdfIn.h index 46b9a7e8..23693a71 100755..100644 --- a/CPP/7zip/Archive/Udf/UdfIn.h +++ b/CPP/7zip/Archive/Udf/UdfIn.h @@ -3,11 +3,11 @@ #ifndef __ARCHIVE_UDF_IN_H #define __ARCHIVE_UDF_IN_H -#include "Common/MyCom.h" -#include "Common/IntToString.h" -#include "Common/Buffer.h" -#include "Common/MyString.h" -#include "Common/MyMap.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyCom.h" +#include "../../../Common/MyMap.h" +#include "../../../Common/MyString.h" #include "../../IStream.h" @@ -22,6 +22,7 @@ namespace NUdf { struct CDString32 { Byte Data[32]; + void Parse(const Byte *buf); // UString GetString() const; }; @@ -30,13 +31,15 @@ struct CDString32 struct CDString128 { Byte Data[128]; - void Parse(const Byte *buf); + + void Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } UString GetString() const; }; struct CDString { CByteBuffer Data; + void Parse(const Byte *p, unsigned size); UString GetString() const; }; @@ -52,12 +55,12 @@ struct CTime bool IsLocal() const { return GetType() == 1; } int GetMinutesOffset() const { - int t = (Data[0] | ((UInt16)Data[1] << 8)) & 0xFFF; + int t = (Data[0] | ((unsigned)Data[1] << 8)) & 0xFFF; if ((t >> 11) != 0) t -= (1 << 12); return (t > (60 * 24) || t < -(60 * 24)) ? 0 : t; } - unsigned GetYear() const { return (Data[2] | ((UInt16)Data[3] << 8)); } + unsigned GetYear() const { return (Data[2] | ((unsigned)Data[3] << 8)); } void Parse(const Byte *buf); }; @@ -208,8 +211,9 @@ struct CFile // CByteBuffer ImplUse; CDString Id; - CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {} int ItemIndex; + + CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {} UString GetName() const { return Id.GetString(); } }; @@ -217,7 +221,7 @@ struct CMyExtent { UInt32 Pos; UInt32 Len; - int PartitionRef; + unsigned PartitionRef; UInt32 GetLen() const { return Len & 0x3FFFFFFF; } UInt32 GetType() const { return Len >> 30; } @@ -254,7 +258,7 @@ struct CItem bool IsRecAndAlloc() const { - for (int i = 0; i < Extents.Size(); i++) + FOR_VECTOR (i, Extents) if (!Extents[i].IsRecAndAlloc()) return false; return true; @@ -263,9 +267,9 @@ struct CItem UInt64 GetChunksSumSize() const { if (IsInline) - return InlineData.GetCapacity(); + return InlineData.Size(); UInt64 size = 0; - for (int i = 0; i < Extents.Size(); i++) + FOR_VECTOR (i, Extents) size += Extents[i].GetLen(); return size; } @@ -331,7 +335,7 @@ struct CProgressVirt class CInArchive { - CMyComPtr<IInStream> _stream; + IInStream *_stream; CProgressVirt *_progress; HRESULT Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf); @@ -351,17 +355,29 @@ class CInArchive UInt32 _numExtents; UInt64 _inlineExtentsSize; bool CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const; -public: - HRESULT Open(IInStream *inStream, CProgressVirt *progress); - void Clear(); +public: CObjectVector<CPartition> Partitions; CObjectVector<CLogVol> LogVols; CObjectVector<CItem> Items; CObjectVector<CFile> Files; - int SecLogSize; + unsigned SecLogSize; + UInt64 PhySize; + UInt64 FileSize; + + bool IsArc; + bool Unsupported; + bool UnexpectedEnd; + + void UpdatePhySize(UInt64 val) + { + if (PhySize < val) + PhySize = val; + } + HRESULT Open(IInStream *inStream, CProgressVirt *progress); + void Clear(); UString GetComment() const; UString GetItemPath(int volIndex, int fsIndex, int refIndex, @@ -370,6 +386,8 @@ public: bool CheckItemExtents(int volIndex, const CItem &item) const; }; +API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size); + }} #endif diff --git a/CPP/7zip/Archive/Udf/UdfRegister.cpp b/CPP/7zip/Archive/Udf/UdfRegister.cpp index 1b08d120..ed32f12e 100755..100644 --- a/CPP/7zip/Archive/Udf/UdfRegister.cpp +++ b/CPP/7zip/Archive/Udf/UdfRegister.cpp @@ -5,9 +5,3 @@ #include "../../Common/RegisterArc.h" #include "UdfHandler.h" -static IInArchive *CreateArc() { return new NArchive::NUdf::CHandler; } - -static CArcInfo g_ArcInfo = - { L"Udf", L"iso img", 0, 0xE0, { 0, 'N', 'S', 'R', '0' }, 5, false, CreateArc, 0 }; - -REGISTER_ARC(Udf) diff --git a/CPP/7zip/Archive/UefiHandler.cpp b/CPP/7zip/Archive/UefiHandler.cpp index 88739d8f..2aaf7d8f 100755..100644 --- a/CPP/7zip/Archive/UefiHandler.cpp +++ b/CPP/7zip/Archive/UefiHandler.cpp @@ -4,8 +4,6 @@ // #define SHOW_DEBUG_INFO -// #include <stdio.h> - #ifdef SHOW_DEBUG_INFO #include <stdio.h> #endif @@ -15,13 +13,12 @@ #include "../../../C/CpuArch.h" #include "../../../C/LzmaDec.h" -#include "Common/Buffer.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/StringConvert.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/StringConvert.h" -#include "Windows/PropVariant.h" -#include "Windows/PropVariantUtils.h" +#include "../../Windows/PropVariantUtils.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" @@ -30,8 +27,6 @@ #include "../Compress/CopyCoder.h" -#include "./Common/FindSignature.h" - #ifdef SHOW_DEBUG_INFO #define PRF(x) x #else @@ -43,8 +38,6 @@ #define Get64(p) GetUi64(p) #define Get24(p) (Get32(p) & 0xFFFFFF) -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) - namespace NArchive { namespace NUefi { @@ -71,7 +64,7 @@ static const Byte k_FFS_Guid[kGuidSize] = FFS_SIGNATURE; static const Byte k_MacFS_Guid[kGuidSize] = { 0xAD,0xEE,0xAD,0x04,0xFF,0x61,0x31,0x4D,0xB6,0xBA,0x64,0xF8,0xBF,0x90,0x1F,0x5A }; -static const UInt32 kFvSignature = 0x4856465F; +static const UInt32 kFvSignature = 0x4856465F; // "_FVH" static const Byte kGuids[][kGuidSize] = { @@ -93,19 +86,19 @@ static const Byte kGuids[][kGuidSize] = static const char *kGuidNames[] = { - "CRC", - "VolumeTopFile", - "ACPI", - "ACPI2", - "Main", - "Intel32", - "Intel64", - "Intel32c", - "Intel64c", - "MacVolume", - "MacUpdate.txt", - "MacName", - "Insyde" + "CRC" + , "VolumeTopFile" + , "ACPI" + , "ACPI2" + , "Main" + , "Intel32" + , "Intel64" + , "Intel32c" + , "Intel64c" + , "MacVolume" + , "MacUpdate.txt" + , "MacName" + , "Insyde" }; enum @@ -237,18 +230,18 @@ enum static const char *g_FileTypes[] = { - "ALL", - "RAW", - "FREEFORM", - "SECURITY_CORE", - "PEI_CORE", - "DXE_CORE", - "PEIM", - "DRIVER", - "COMBINED_PEIM_DRIVER", - "APPLICATION", - "0xA", - "VOLUME" + "ALL" + , "RAW" + , "FREEFORM" + , "SECURITY_CORE" + , "PEI_CORE" + , "DXE_CORE" + , "PEIM" + , "DRIVER" + , "COMBINED_PEIM_DRIVER" + , "APPLICATION" + , "0xA" + , "VOLUME" }; // typedef Byte FFS_FILE_ATTRIBUTES; @@ -334,9 +327,9 @@ static const CUInt32PCharPair g_SECTION_TYPE[] = static const char *g_Methods[] = { - "COPY", - "LZH", - "LZMA" + "COPY" + , "LZH" + , "LZMA" }; static AString UInt32ToString(UInt32 val) @@ -446,7 +439,7 @@ class CFfsFileHeader Byte Attrib; Byte State; - UInt16 GetTailReference() const { return CheckHeader | ((UInt16)CheckFile << 8); } + UInt16 GetTailReference() const { return (UInt16)(CheckHeader | ((UInt16)CheckFile << 8)); } UInt32 GetTailSize() const { return IsThereTail() ? 2 : 0; } bool IsThereFileChecksum() const { return (Attrib & FFS_ATTRIB_CHECKSUM) != 0; } bool IsThereTail() const { return (Attrib & FFS_ATTRIB_TAIL_PRESENT) != 0; } @@ -474,6 +467,7 @@ public: } UInt32 GetDataSize() const { return Size - kFileHeaderSize - GetTailSize(); } + UInt32 GetDataSize2(UInt32 rem) const { return rem - kFileHeaderSize - GetTailSize(); } bool Check(const Byte *p, UInt32 size) { @@ -544,8 +538,7 @@ public: } }; -#define GET_32(offs, dest) dest = Get32(p + (offs)); -#define GET_64(offs, dest) dest = Get64(p + (offs)); +#define G32(_offs_, dest) dest = Get32(p + (_offs_)); struct CCapsuleHeader { @@ -567,18 +560,18 @@ struct CCapsuleHeader void Parse(const Byte *p) { - GET_32(0x10, HeaderSize); - GET_32(0x14, Flags); - GET_32(0x18, CapsuleImageSize); - GET_32(0x1C, SequenceNumber); - GET_32(0x30, OffsetToSplitInformation); - GET_32(0x34, OffsetToCapsuleBody); - GET_32(0x38, OffsetToOemDefinedHeader); - GET_32(0x3C, OffsetToAuthorInformation); - GET_32(0x40, OffsetToRevisionInformation); - GET_32(0x44, OffsetToShortDescription); - GET_32(0x48, OffsetToLongDescription); - GET_32(0x4C, OffsetToApplicableDevices); + 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); } }; @@ -655,6 +648,7 @@ class CHandler: UInt32 _totalBufsSize; CCapsuleHeader _h; + UInt64 _phySize; void AddCommentString(const wchar_t *name, UInt32 pos); int AddItem(const CItem &item); @@ -663,7 +657,9 @@ class CHandler: int AddBuf(UInt32 size); HRESULT ParseSections(int bufIndex, UInt32 pos, UInt32 size, int parent, int method, int level); - HRESULT ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, int parent, int method, int level); + HRESULT 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,21 +670,20 @@ public: STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; -static const STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidCharacts, VT_BSTR} + kpidPath, + kpidIsDir, + kpidSize, + kpidMethod, + kpidCharacts }; -static const STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidComment, VT_BSTR}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidPhySize, VT_UI8}, - { NULL, kpidCharacts, VT_BSTR} + kpidComment, + kpidMethod, + kpidCharacts }; IMP_IInArchive_Props @@ -733,7 +728,7 @@ void CHandler::AddCommentString(const wchar_t *name, UInt32 pos) return; for (UInt32 i = pos;; i += 2) { - if (s.Length() > (1 << 16) || i >= _h.OffsetToCapsuleBody) + if (s.Len() > (1 << 16) || i >= _h.OffsetToCapsuleBody) return; wchar_t c = Get16(buf + i); if (c == 0) @@ -773,7 +768,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) break; } case kpidComment: if (!_comment.IsEmpty()) prop = _comment; break; - case kpidPhySize: prop = (UInt64)_h.CapsuleImageSize; break; + case kpidPhySize: prop = (UInt64)_phySize; break; } prop.Detach(value); return S_OK; @@ -1037,7 +1032,7 @@ static HRESULT LzhDecode(Byte *dest, UInt32 destSize, const Byte *src, UInt32 sr { UInt32 c = extraHuff.DecodeSymbol(&bitDec); if (c > 2) - lens[i++] = (Byte)c - 2; + lens[i++] = (Byte)(c - 2); else { UInt32 numZeros; @@ -1163,8 +1158,8 @@ int CHandler::AddBuf(UInt32 size) if (size > kBufTotalSizeMax - _totalBufsSize) throw 1; _totalBufsSize += size; - int index = _bufs.Add(CByteBuffer()); - _bufs[index].SetCapacity(size); + int index = _bufs.Size(); + _bufs.AddNew().Alloc(size); return index; } @@ -1272,7 +1267,9 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p 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) + 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)); } @@ -1323,7 +1320,10 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p { item.KeepName = false; int newParent = AddDirItem(item); - RINOK(ParseVolume(bufIndex, posBase + pos + 4, sectSize - 4, newParent, method, level)); + RINOK(ParseVolume(bufIndex, posBase + pos + 4, + sectSize - 4, + sectSize - 4, + newParent, method, level)); } else { @@ -1341,7 +1341,10 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p needAdd = false; item.Name = "vol"; int newParent = AddDirItem(item); - RINOK(ParseVolume(bufIndex, posBase + pos + 4 + kInsydeOffset, sectDataSize - kInsydeOffset, newParent, method, level)); + RINOK(ParseVolume(bufIndex, posBase + pos + 4 + kInsydeOffset, + sectDataSize - kInsydeOffset, + sectDataSize - kInsydeOffset, + newParent, method, level)); } if (needAdd) @@ -1359,19 +1362,20 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p AString s; if (ParseDepedencyExpression(p + 4, sectDataSize, s)) { - if (s.Length() < (1 << 9)) + if (s.Len() < (1 << 9)) { - s = '[' + s + ']'; + s.InsertAtFront('['); + s += ']'; AddSpaceAndString(_items[item.Parent].Characts, s); needAdd = false; } else { - item.BufIndex = AddBuf(s.Length()); + item.BufIndex = AddBuf(s.Len()); CByteBuffer &buf0 = _bufs[item.BufIndex]; - memcpy(buf0, s, s.Length()); + memcpy(buf0, s, s.Len()); item.Offset = 0; - item.Size = s.Length(); + item.Size = s.Len(); } } break; @@ -1383,7 +1387,11 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p AString s; if (ParseUtf16zString2(p + 6, sectDataSize - 2, s)) { - AddSpaceAndString(_items[item.Parent].Characts, (AString)"ver:" + UInt32ToString(Get16(p + 4)) + ' ' + s); + AString s2 = "ver:"; + s2 += UInt32ToString(Get16(p + 4)); + s2 += ' '; + s2 += s; + AddSpaceAndString(_items[item.Parent].Characts, s2); needAdd = false; } } @@ -1430,13 +1438,39 @@ static bool Is_FF_Stream(const Byte *p, UInt32 size) return (Count_FF_Bytes(p, size) == size); } -HRESULT CHandler::ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, int parent, int method, int level) +struct CVolFfsHeader +{ + UInt32 HeaderLen; + UInt64 VolSize; + + bool Parse(const Byte *p); +}; + +bool CVolFfsHeader::Parse(const Byte *p) +{ + if (Get32(p + 0x28) != kFvSignature) + return false; + + UInt32 attribs = Get32(p + 0x2C); + if ((attribs & FVB_ERASE_POLARITY) == 0) + return false; + VolSize = Get64(p + 0x20); + HeaderLen = Get16(p + 0x30); + if (HeaderLen < kFvHeaderSize || (HeaderLen & 0x7) != 0 || VolSize < HeaderLen) + return false; + return true; +}; + +HRESULT CHandler::ParseVolume( + int bufIndex, UInt32 posBase, + UInt32 exactSize, UInt32 limitSize, + int parent, int method, int level) { if (level > kLevelMax) return S_FALSE; MyPrint(posBase, size, level, "Volume"); level++; - if (size < kFvHeaderSize) + if (exactSize < kFvHeaderSize) return S_FALSE; const Byte *p = _bufs[bufIndex] + posBase; // first 16 bytes must be zeros, but they are not zeros sometimes. @@ -1448,28 +1482,27 @@ HRESULT CHandler::ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, int par item.BufIndex = bufIndex; item.Parent = parent; item.Offset = posBase; - item.Size = size; + item.Size = exactSize; item.SetGuid(p + kFfsGuidOffset); item.Name += " [VOLUME]"; AddItem(item); return S_OK; } - if (Get32(p + 0x28) != kFvSignature) - return S_FALSE; - UInt32 attribs = Get32(p + 0x2C); - if ((attribs & FVB_ERASE_POLARITY) == 0) + CVolFfsHeader ffsHeader; + if (!ffsHeader.Parse(p)) return S_FALSE; // if (parent >= 0) AddSpaceAndString(_items[parent].Characts, FLAGS_TO_STRING(g_FV_Attribs, attribs)); - UInt64 fvLen = Get64(p + 0x20); - UInt32 headerLen = Get16(p + 0x30); - if (headerLen > size || headerLen < kFvHeaderSize || (headerLen & 0x7) != 0 || - fvLen > size || fvLen < headerLen) + + // VolSize > exactSize (fh.Size) for some UEFI archives (is it correct UEFI?) + // so we check VolSize for limitSize instead. + + if (ffsHeader.HeaderLen > limitSize || ffsHeader.VolSize > limitSize) return S_FALSE; { UInt32 checkCalc = 0; - for (UInt32 i = 0; i < headerLen; i += 2) + for (UInt32 i = 0; i < ffsHeader.HeaderLen; i += 2) checkCalc += Get16(p + i); if ((checkCalc & 0xFFFF) != 0) return S_FALSE; @@ -1482,7 +1515,7 @@ HRESULT CHandler::ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, int par UInt32 pos = kFvHeaderSize; for (;;) { - if (pos >= headerLen) + if (pos >= ffsHeader.HeaderLen) return S_FALSE; UInt32 numBlocks = Get32(p + pos); UInt32 length = Get32(p + pos + 4); @@ -1490,18 +1523,18 @@ HRESULT CHandler::ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, int par if (numBlocks == 0 && length == 0) break; } - if (pos != headerLen) + if (pos != ffsHeader.HeaderLen) return S_FALSE; CRecordVector<UInt32> guidsVector; for (;;) { - UInt32 rem = (UInt32)fvLen - pos; + UInt32 rem = (UInt32)ffsHeader.VolSize - pos; if (rem < kFileHeaderSize) break; pos = (pos + 7) & ~7; - rem = (UInt32)fvLen - pos; + rem = (UInt32)ffsHeader.VolSize - pos; if (rem < kFileHeaderSize) break; @@ -1565,7 +1598,10 @@ HRESULT CHandler::ParseVolume(int bufIndex, UInt32 posBase, UInt32 size, int par if (isVolume) { int newParent = AddDirItem(item); - RINOK(ParseVolume(bufIndex, offset, sectSize, newParent, method, level)); + UInt32 limSize = fh.GetDataSize2(rem); + // volume.VolSize > fh.Size for some UEFI archives (is it correct UEFI?) + // so we will check VolSize for limitSize instead. + RINOK(ParseVolume(bufIndex, offset, sectSize, limSize, newParent, method, level)); } else AddItem(item); @@ -1590,6 +1626,7 @@ HRESULT CHandler::OpenCapsule(IInStream *stream) _h.OffsetToCapsuleBody < kHeaderSize || _h.OffsetToCapsuleBody > _h.CapsuleImageSize) return S_FALSE; + _phySize = _h.CapsuleImageSize; if (_h.SequenceNumber != 0 || _h.OffsetToSplitInformation != 0 ) @@ -1605,112 +1642,29 @@ HRESULT CHandler::OpenCapsule(IInStream *stream) AddCommentString(L"Short Description", _h.OffsetToShortDescription); AddCommentString(L"Long Description", _h.OffsetToLongDescription); - return ParseVolume(bufIndex, _h.OffsetToCapsuleBody, _h.CapsuleImageSize - _h.OffsetToCapsuleBody, -1, -1, 0); + return ParseVolume(bufIndex, _h.OffsetToCapsuleBody, + _h.CapsuleImageSize - _h.OffsetToCapsuleBody, + _h.CapsuleImageSize - _h.OffsetToCapsuleBody, + -1, -1, 0); } -HRESULT CHandler::OpenFv(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) +HRESULT CHandler::OpenFv(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback * /* callback */) { - UInt64 fileSize; - RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); - if (fileSize > (1 << 27)) + Byte buf[kFvHeaderSize]; + RINOK(ReadStream_FALSE(stream, buf, kFvHeaderSize)); + if (!IsFfs(buf)) return S_FALSE; - - UInt32 volIndex = 0; - UInt32 pos = 0, prevEnd = 0; - if (callback) - { - RINOK(callback->SetTotal(NULL, &fileSize)); - } - - for (;;) - { - UInt64 limit = 0; - UInt64 *limitPtr = NULL; - if (maxCheckStartPosition) - { - UInt32 directSize = pos - prevEnd; - if (directSize >= *maxCheckStartPosition) - break; - limit = *maxCheckStartPosition - directSize; - limitPtr = &limit; - } - - UInt64 resPos; - RINOK(stream->Seek(pos + kFfsGuidOffset, STREAM_SEEK_SET, NULL)); - if (FindSignatureInStream(stream, k_FFS_Guid, kGuidSize, limitPtr, resPos) == S_FALSE) - break; - - pos += (UInt32)resPos; - UInt64 fvSize; - { - UInt32 rem = (UInt32)fileSize - pos; - if (rem < kFvHeaderSize) - break; - RINOK(stream->Seek(pos, STREAM_SEEK_SET, NULL)); - Byte buf[kFvHeaderSize]; - RINOK(ReadStream_FALSE(stream, buf, kFvHeaderSize)); - fvSize = Get64(buf + 0x20); - if (!IsFfs(buf) || fvSize > rem) - { - pos++; - continue; - } - } - - RINOK(stream->Seek(prevEnd, STREAM_SEEK_SET, NULL)); - - if (pos != prevEnd) - { - CItem item; - item.Offset = 0; - item.Size = pos - prevEnd; - item.BufIndex = AddBuf(item.Size); - CByteBuffer &buf0 = _bufs[item.BufIndex]; - RINOK(ReadStream_FALSE(stream, buf0, item.Size)); - item.Name = UInt32ToString(volIndex++); - AddItem(item); - } - - prevEnd = pos; - RINOK(stream->Seek(pos, STREAM_SEEK_SET, NULL)); - UInt32 fvSize32 = (UInt32)fvSize; - CItem item; - item.BufIndex = AddBuf(fvSize32); - CByteBuffer &buf0 = _bufs[item.BufIndex]; - item.Name = UInt32ToString(volIndex++); - int parent = AddDirItem(item); - ReadStream_FALSE(stream, buf0, fvSize32); - RINOK(ParseVolume(item.BufIndex, 0, fvSize32, parent, -1, 0)); - pos += fvSize32; - prevEnd = pos; - - if (callback) - { - UInt64 pos64 = pos; - RINOK(callback->SetCompleted(NULL, &pos64)); - } - } - if (_items.Size() == 0) + CVolFfsHeader ffsHeader; + if (!ffsHeader.Parse(buf)) return S_FALSE; - - if (pos <= fileSize) - { - pos = (UInt32)fileSize; - if (prevEnd < pos) - { - CItem item; - item.Offset = 0; - item.Size = pos - prevEnd; - item.BufIndex = AddBuf(item.Size); - CByteBuffer &buf0 = _bufs[item.BufIndex]; - RINOK(stream->Seek(prevEnd, STREAM_SEEK_SET, NULL)); - RINOK(ReadStream_FALSE(stream, buf0, item.Size)); - item.Name = UInt32ToString(volIndex++); - AddItem(item); - } - } - _h.CapsuleImageSize = pos; - return S_OK; + if (ffsHeader.VolSize > ((UInt32)1 << 30)) + return S_FALSE; + _phySize = ffsHeader.VolSize; + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + UInt32 fvSize32 = (UInt32)ffsHeader.VolSize; + int bufIndex = AddBuf(fvSize32); + RINOK(ReadStream_FALSE(stream, _bufs[bufIndex], fvSize32)); + return ParseVolume(bufIndex, 0, fvSize32, fvSize32, -1, -1, 0); } HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) @@ -1724,20 +1678,21 @@ HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, RINOK(OpenFv(stream, maxCheckStartPosition, callback)); } - CIntVector numChilds; - numChilds.Reserve(_items.Size()); - int i; - for (i = 0; i < _items.Size(); i++) + unsigned num = _items.Size(); + CIntArr numChilds(num); + unsigned i; + for (i = 0; i < num; i++) + numChilds[i] = 0; + for (i = 0; i < num; i++) { - numChilds.Add(0); int parent = _items[i].Parent; if (parent >= 0) numChilds[parent]++; } - for (i = 0; i < _items.Size(); i++) + for (i = 0; i < num; i++) { - CItem &item = _items[i]; + const CItem &item = _items[i]; int parent = item.Parent; if (parent >= 0) { @@ -1748,7 +1703,7 @@ HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, } } - CIntVector mainToReduced; + CUIntVector mainToReduced; for (i = 0; i < _items.Size(); i++) { mainToReduced.Add(_items2.Size()); @@ -1807,18 +1762,18 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, { COM_TRY_BEGIN Close(); - try { - if (Open2(inStream, maxCheckStartPosition, callback) != S_OK) - return S_FALSE; + HRESULT res = Open2(inStream, maxCheckStartPosition, callback); + if (res == E_NOTIMPL) + res = S_FALSE; + return res; } - catch(...) { return S_FALSE; } - return S_OK; COM_TRY_END } STDMETHODIMP CHandler::Close() { + _phySize = 0; _totalBufsSize = 0; _methodsMask = 0; _items.Clear(); @@ -1839,7 +1794,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items2.Size(); if (numItems == 0) @@ -1916,20 +1871,32 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) } -namespace UEFIc -{ - static IInArchive *CreateArc() { return new CHandler(true); } - static CArcInfo g_ArcInfo = - { L"UEFIc", L"scap", 0, 0xD0, CAPSULE_SIGNATURE, kCapsuleSigSize, false, CreateArc, 0 }; - REGISTER_ARC(UEFIc) +namespace UEFIc { + +IMP_CreateArcIn_2(CHandler(true)) + +static CArcInfo g_ArcInfo = + { "UEFIc", "scap", 0, 0xD0, + kCapsuleSigSize, CAPSULE_SIGNATURE, + 0, + NArcInfoFlags::kFindSignature, + CreateArc }; + +REGISTER_ARC(UEFIc) } -namespace UEFIs -{ - static IInArchive *CreateArc() { return new CHandler(false); } - static CArcInfo g_ArcInfo = - { L"UEFIs", L"", 0, 0xD1, FFS_SIGNATURE, kGuidSize, false, CreateArc, 0 }; - REGISTER_ARC(UEFIs) +namespace UEFIf { + +IMP_CreateArcIn_2(CHandler(false)) + +static CArcInfo g_ArcInfo = + { "UEFIf", "uefif", 0, 0xD1, + kGuidSize, FFS_SIGNATURE, + kFfsGuidOffset, + NArcInfoFlags::kFindSignature, + CreateArc }; + +REGISTER_ARC(UEFIf) } }} diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp index 9d1c928e..5268bd0b 100755..100644 --- a/CPP/7zip/Archive/VhdHandler.cpp +++ b/CPP/7zip/Archive/VhdHandler.cpp @@ -4,12 +4,12 @@ #include "../../../C/CpuArch.h" -#include "Common/Buffer.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/MyString.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/MyString.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -22,14 +22,19 @@ #define Get32(p) GetBe32(p) #define Get64(p) GetBe64(p) -#define G32(p, dest) dest = Get32(p); -#define G64(p, dest) dest = Get64(p); +#define G32(_offs_, dest) dest = Get32(p + (_offs_)); +#define G64(_offs_, dest) dest = Get64(p + (_offs_)); using namespace NWindows; namespace NArchive { namespace NVhd { +#define SIGNATURE { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x', 0, 0 } + +static const unsigned kSignatureSize = 10; +static const Byte kSignature[kSignatureSize] = SIGNATURE; + static const UInt32 kUnusedBlock = 0xFFFFFFFF; static const UInt32 kDiskType_Fixed = 2; @@ -38,11 +43,11 @@ static const UInt32 kDiskType_Diff = 4; static const char *kDiskTypes[] = { - "0", - "1", - "Fixed", - "Dynamic", - "Differencing" + "0" + , "1" + , "Fixed" + , "Dynamic" + , "Differencing" }; struct CFooter @@ -73,7 +78,7 @@ struct CFooter AString CFooter::GetTypeString() const { - if (Type < sizeof(kDiskTypes) / sizeof(kDiskTypes[0])) + if (Type < ARRAY_SIZE(kDiskTypes)) return kDiskTypes[Type]; char s[16]; ConvertUInt32ToString(Type, s); @@ -96,27 +101,35 @@ static bool CheckBlock(const Byte *p, unsigned size, unsigned checkSumOffset, un return true; } +static const unsigned kSectorSize_Log = 9; +static const unsigned kSectorSize = 1 << kSectorSize_Log; +static const unsigned kHeaderSize = 512; + bool CFooter::Parse(const Byte *p) { - if (memcmp(p, "conectix", 8) != 0) + if (memcmp(p, kSignature, kSignatureSize) != 0) + return false; + // G32(0x08, Features); + // G32(0x0C, FormatVersion); + G64(0x10, DataOffset); + G32(0x18, CTime); + G32(0x1C, CreatorApp); + G32(0x20, CreatorVersion); + G32(0x24, CreatorHostOS); + // G64(0x28, OriginalSize); + G64(0x30, CurrentSize); + G32(0x38, DiskGeometry); + G32(0x3C, Type); + if (Type < kDiskType_Fixed || + Type > kDiskType_Diff) return false; - // G32(p + 0x08, Features); - // G32(p + 0x0C, FormatVersion); - G64(p + 0x10, DataOffset); - G32(p + 0x18, CTime); - G32(p + 0x1C, CreatorApp); - G32(p + 0x20, CreatorVersion); - G32(p + 0x24, CreatorHostOS); - // G64(p + 0x28, OriginalSize); - G64(p + 0x30, CurrentSize); - G32(p + 0x38, DiskGeometry); - G32(p + 0x3C, Type); memcpy(Id, p + 0x44, 16); SavedState = p[0x54]; - return CheckBlock(p, 512, 0x40, 0x55); + // if (DataOffset > ((UInt64)1 << 62)) return false; + // if (CurrentSize > ((UInt64)1 << 62)) return false; + return CheckBlock(p, kHeaderSize, 0x40, 0x55); } -/* struct CParentLocatorEntry { UInt32 Code; @@ -124,17 +137,15 @@ struct CParentLocatorEntry UInt32 DataLen; UInt64 DataOffset; - bool Parse(const Byte *p); + bool Parse(const Byte *p) + { + G32(0x00, Code); + G32(0x04, DataSpace); + G32(0x08, DataLen); + G64(0x10, DataOffset); + return Get32(p + 0x0C) == 0; // Reserved + } }; -bool CParentLocatorEntry::Parse(const Byte *p) -{ - G32(p + 0x00, Code); - G32(p + 0x04, DataSpace); - G32(p + 0x08, DataLen); - G32(p + 0x10, DataOffset); - return (Get32(p + 0x0C) == 0); // Resrved -} -*/ struct CDynHeader { @@ -142,56 +153,63 @@ struct CDynHeader UInt64 TableOffset; // UInt32 HeaderVersion; UInt32 NumBlocks; - int BlockSizeLog; + unsigned BlockSizeLog; UInt32 ParentTime; Byte ParentId[16]; + bool RelativeNameWasUsed; UString ParentName; - // CParentLocatorEntry ParentLocators[8]; + UString RelativeParentNameFromLocator; + CParentLocatorEntry ParentLocators[8]; bool Parse(const Byte *p); UInt32 NumBitMapSectors() const { - UInt32 numSectorsInBlock = (1 << (BlockSizeLog - 9)); - return (numSectorsInBlock + 512 * 8 - 1) / (512 * 8); + UInt32 numSectorsInBlock = (1 << (BlockSizeLog - kSectorSize_Log)); + return (numSectorsInBlock + kSectorSize * 8 - 1) / (kSectorSize * 8); + } + void Clear() + { + RelativeNameWasUsed = false; + ParentName.Empty(); + RelativeParentNameFromLocator.Empty(); } }; -static int GetLog(UInt32 num) -{ - for (int i = 0; i < 31; i++) - if (((UInt32)1 << i) == num) - return i; - return -1; -} - bool CDynHeader::Parse(const Byte *p) { if (memcmp(p, "cxsparse", 8) != 0) return false; - // G64(p + 0x08, DataOffset); - G64(p + 0x10, TableOffset); - // G32(p + 0x18, HeaderVersion); - G32(p + 0x1C, NumBlocks); - BlockSizeLog = GetLog(Get32(p + 0x20)); - if (BlockSizeLog < 9 || BlockSizeLog > 30) - return false; - G32(p + 0x38, ParentTime); + // G64(0x08, DataOffset); + G64(0x10, TableOffset); + // G32(0x18, HeaderVersion); + G32(0x1C, NumBlocks); + { + UInt32 blockSize = Get32(p + 0x20); + unsigned i; + for (i = kSectorSize_Log;; i++) + { + if (i > 31) + return false; + if (((UInt32)1 << i) == blockSize) + break; + } + BlockSizeLog = i; + } + G32(0x38, ParentTime); if (Get32(p + 0x3C) != 0) // reserved return false; memcpy(ParentId, p + 0x28, 16); { - const int kNameLength = 256; - wchar_t *s = ParentName.GetBuffer(kNameLength); - for (unsigned i = 0; i < kNameLength; i++) + const unsigned kNameLen = 256; + wchar_t *s = ParentName.GetBuffer(kNameLen); + for (unsigned i = 0; i < kNameLen; i++) s[i] = Get16(p + 0x40 + i * 2); - s[kNameLength] = 0; + s[kNameLen] = 0; ParentName.ReleaseBuffer(); } - /* - for (int i = 0; i < 8; i++) + for (unsigned i = 0; i < 8; i++) if (!ParentLocators[i].Parse(p + 0x240 + i * 24)) return false; - */ return CheckBlock(p, 1024, 0x24, 0x240 + 8 * 24); } @@ -202,8 +220,10 @@ class CHandler: public CMyUnknownImp { UInt64 _virtPos; - UInt64 _phyPos; - UInt64 _phyLimit; + UInt64 _posInArc; + UInt64 _posInArcLimit; + UInt64 _startOffset; + UInt64 _phySize; CFooter Footer; CDynHeader Dyn; @@ -214,7 +234,22 @@ class CHandler: CMyComPtr<IInStream> Stream; CMyComPtr<IInStream> ParentStream; CHandler *Parent; + UString _errorMessage; + // bool _unexpectedEnd; + void AddErrorMessage(const wchar_t *s) + { + if (!_errorMessage.IsEmpty()) + _errorMessage += L'\n'; + _errorMessage += s; + } + void UpdatePhySize(UInt64 value) + { + if (_phySize < value) + _phySize = value; + } + + void Reset_PosInArc() { _posInArc = (UInt64)0 - 1; } HRESULT Seek(UInt64 offset); HRESULT InitAndSeek(); HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size); @@ -223,7 +258,7 @@ class CHandler: UInt64 GetPackSize() const { return Footer.ThereIsDynamic() ? ((UInt64)NumUsedBlocks << Dyn.BlockSizeLog) : Footer.CurrentSize; } - UString GetParentName() const + UString GetParentSequence() const { const CHandler *p = this; UString res; @@ -231,26 +266,45 @@ class CHandler: { if (!res.IsEmpty()) res += L" -> "; - res += p->Dyn.ParentName; + UString mainName; + UString anotherName; + if (Dyn.RelativeNameWasUsed) + { + mainName = p->Dyn.RelativeParentNameFromLocator; + anotherName = p->Dyn.ParentName; + } + else + { + mainName = p->Dyn.ParentName; + anotherName = p->Dyn.RelativeParentNameFromLocator; + } + res += mainName; + if (mainName != anotherName && !anotherName.IsEmpty()) + { + res += L' '; + res += L'('; + res += anotherName; + res += L')'; + } p = p->Parent; } return res; } - bool IsOK() const + bool AreParentsOK() const { const CHandler *p = this; while (p->NeedParent()) { p = p->Parent; - if (p == 0) + if (!p) return false; } return true; } HRESULT Open3(); - HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, int level); + HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level); public: MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream) @@ -261,7 +315,7 @@ public: STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; -HRESULT CHandler::Seek(UInt64 offset) { return Stream->Seek(offset, STREAM_SEEK_SET, NULL); } +HRESULT CHandler::Seek(UInt64 offset) { return Stream->Seek(_startOffset + offset, STREAM_SEEK_SET, NULL); } HRESULT CHandler::InitAndSeek() { @@ -269,50 +323,122 @@ HRESULT CHandler::InitAndSeek() { RINOK(Parent->InitAndSeek()); } - _virtPos = _phyPos = 0; + _virtPos = _posInArc = 0; BitMapTag = kUnusedBlock; - BitMap.SetCapacity(Dyn.NumBitMapSectors() << 9); + BitMap.Alloc(Dyn.NumBitMapSectors() << kSectorSize_Log); return Seek(0); } HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size) { - if (offset + size > _phyLimit) + if (offset + size > _posInArcLimit) return S_FALSE; - if (offset != _phyPos) + if (offset != _posInArc) { - _phyPos = offset; + _posInArc = offset; RINOK(Seek(offset)); } HRESULT res = ReadStream_FALSE(Stream, data, size); - _phyPos += size; + if (res == S_OK) + _posInArc += size; + else + Reset_PosInArc(); return res; } HRESULT CHandler::Open3() { - RINOK(Stream->Seek(0, STREAM_SEEK_END, &_phyPos)); - if (_phyPos < 512) + // Fixed archive uses only footer + + UInt64 startPos; + RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &startPos)); + _startOffset = startPos; + Byte header[kHeaderSize]; + RINOK(ReadStream_FALSE(Stream, header, kHeaderSize)); + bool headerIsOK = Footer.Parse(header); + + if (headerIsOK && !Footer.ThereIsDynamic()) + { + // fixed archive + if (startPos < Footer.CurrentSize) + return S_FALSE; + _posInArcLimit = Footer.CurrentSize; + _phySize = Footer.CurrentSize + kHeaderSize; + _startOffset = startPos - Footer.CurrentSize; + _posInArc = _phySize; + return S_OK; + } + + UInt64 fileSize; + RINOK(Stream->Seek(0, STREAM_SEEK_END, &fileSize)); + if (fileSize < kHeaderSize) return S_FALSE; + const UInt32 kDynSize = 1024; Byte buf[kDynSize]; - _phyLimit = _phyPos; - RINOK(ReadPhy(_phyLimit - 512, buf, 512)); - if (!Footer.Parse(buf)) - return S_FALSE; - _phyLimit -= 512; + RINOK(Stream->Seek(fileSize - kHeaderSize, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(Stream, buf, kHeaderSize)); - if (!Footer.ThereIsDynamic()) + if (!headerIsOK) + { + if (!Footer.Parse(buf)) + return S_FALSE; + if (Footer.ThereIsDynamic()) + return S_FALSE; // we can't open Dynamic Archive backward. + _posInArcLimit = Footer.CurrentSize; + _phySize = Footer.CurrentSize + kHeaderSize; + _startOffset = fileSize - kHeaderSize - Footer.CurrentSize; + _posInArc = _phySize; return S_OK; + } - RINOK(ReadPhy(0, buf + 512, 512)); - if (memcmp(buf, buf + 512, 512) != 0) - return S_FALSE; + _phySize = kHeaderSize; + _posInArc = fileSize - startPos; + _posInArcLimit = _posInArc - kHeaderSize; + + bool headerAndFooterAreEqual = false; + if (memcmp(header, buf, kHeaderSize) == 0) + { + headerAndFooterAreEqual = true; + _phySize = fileSize - _startOffset; + } RINOK(ReadPhy(Footer.DataOffset, buf, kDynSize)); if (!Dyn.Parse(buf)) return S_FALSE; + + UpdatePhySize(Footer.DataOffset + kDynSize); + + for (int i = 0; i < 8; i++) + { + const CParentLocatorEntry &locator = Dyn.ParentLocators[i]; + const UInt32 kNameBufSizeMax = 1024; + if (locator.DataLen < kNameBufSizeMax && + locator.DataOffset < _posInArcLimit && + locator.DataOffset + locator.DataLen <= _posInArcLimit) + { + if (locator.Code == 0x57327275 && (locator.DataLen & 1) == 0) + { + // "W2ru" locator + // Path is encoded as little-endian UTF-16 + Byte nameBuf[kNameBufSizeMax]; + UString tempString; + unsigned len = (locator.DataLen >> 1); + wchar_t *s = tempString.GetBuffer(len); + RINOK(ReadPhy(locator.DataOffset, nameBuf, locator.DataLen)); + for (unsigned j = 0; j < len; j++) + s[j] = GetUi16(nameBuf + j * 2); + s[len] = 0; + tempString.ReleaseBuffer(); + if (tempString[0] == L'.' && tempString[1] == L'\\') + tempString.DeleteFrontal(2); + Dyn.RelativeParentNameFromLocator = tempString; + } + } + if (locator.DataLen != 0) + UpdatePhySize(locator.DataOffset + locator.DataLen); + } if (Dyn.NumBlocks >= (UInt32)1 << 31) return S_FALSE; @@ -324,20 +450,69 @@ HRESULT CHandler::Open3() else if (((Footer.CurrentSize - 1) >> Dyn.BlockSizeLog) + 1 != Dyn.NumBlocks) return S_FALSE; - Bat.Reserve(Dyn.NumBlocks); + Bat.ClearAndReserve(Dyn.NumBlocks); + + UInt32 bitmapSize = Dyn.NumBitMapSectors() << kSectorSize_Log; + while ((UInt32)Bat.Size() < Dyn.NumBlocks) { - RINOK(ReadPhy(Dyn.TableOffset + (UInt64)Bat.Size() * 4, buf, 512)); - for (UInt32 j = 0; j < 512; j += 4) + RINOK(ReadPhy(Dyn.TableOffset + (UInt64)Bat.Size() * 4, buf, kSectorSize)); + UpdatePhySize(Dyn.TableOffset + kSectorSize); + for (UInt32 j = 0; j < kSectorSize; j += 4) { UInt32 v = Get32(buf + j); if (v != kUnusedBlock) + { + UInt32 blockSize = (UInt32)1 << Dyn.BlockSizeLog; + UpdatePhySize(((UInt64)v << kSectorSize_Log) + bitmapSize + blockSize); NumUsedBlocks++; - Bat.Add(v); + } + Bat.AddInReserved(v); if ((UInt32)Bat.Size() >= Dyn.NumBlocks) break; } } + + if (headerAndFooterAreEqual) + return S_OK; + + if (_startOffset + _phySize + kHeaderSize > fileSize) + { + // _unexpectedEnd = true; + _posInArcLimit = _phySize; + _phySize += kHeaderSize; + return S_OK; + } + + RINOK(ReadPhy(_phySize, buf, kHeaderSize)); + if (memcmp(header, buf, kHeaderSize) == 0) + { + _posInArcLimit = _phySize; + _phySize += kHeaderSize; + return S_OK; + } + + if (_phySize == 0x800) + { + /* WHY does empty archive contain additional empty sector? + We skip that sector and check footer again. */ + unsigned i; + for (i = 0; i < kSectorSize && buf[i] == 0; i++); + if (i == kSectorSize) + { + RINOK(ReadPhy(_phySize + kSectorSize, buf, kHeaderSize)); + if (memcmp(header, buf, kHeaderSize) == 0) + { + _phySize += kSectorSize; + _posInArcLimit = _phySize; + _phySize += kHeaderSize; + return S_OK; + } + } + } + _posInArcLimit = _phySize; + _phySize += kHeaderSize; + AddErrorMessage(L"Can't find footer"); return S_OK; } @@ -371,17 +546,17 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize) } else { - UInt64 newPos = (UInt64)blockSectIndex << 9; + UInt64 newPos = (UInt64)blockSectIndex << kSectorSize_Log; if (BitMapTag != blockIndex) { - RINOK(ReadPhy(newPos, BitMap, (UInt32)BitMap.GetCapacity())); + RINOK(ReadPhy(newPos, BitMap, (UInt32)BitMap.Size())); BitMapTag = blockIndex; } - RINOK(ReadPhy(newPos + BitMap.GetCapacity() + offsetInBlock, data, size)); + RINOK(ReadPhy(newPos + BitMap.Size() + offsetInBlock, data, size)); for (UInt32 cur = 0; cur < size;) { UInt32 rem = MyMin(0x200 - (offsetInBlock & 0x1FF), size - cur); - UInt32 bmi = offsetInBlock >> 9; + UInt32 bmi = offsetInBlock >> kSectorSize_Log; if (((BitMap[bmi >> 3] >> (7 - (bmi & 7))) & 1) == 0) { if (ParentStream) @@ -409,15 +584,18 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize) STDMETHODIMP CHandler::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { - switch(seekOrigin) + switch (seekOrigin) { - case STREAM_SEEK_SET: _virtPos = offset; break; - case STREAM_SEEK_CUR: _virtPos += offset; break; - case STREAM_SEEK_END: _virtPos = Footer.CurrentSize + offset; break; + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += Footer.CurrentSize; break; default: return STG_E_INVALIDFUNCTION; } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = offset; if (newPosition) - *newPosition = _virtPos; + *newPosition = offset; return S_OK; } @@ -427,9 +605,10 @@ enum kpidSavedState }; -STATPROPSTG kArcProps[] = +static const STATPROPSTG kArcProps[] = { { NULL, kpidSize, VT_UI8}, + { NULL, kpidOffset, VT_UI8}, { NULL, kpidCTime, VT_FILETIME}, { NULL, kpidClusterSize, VT_UI8}, { NULL, kpidMethod, VT_BSTR}, @@ -440,16 +619,16 @@ STATPROPSTG kArcProps[] = { NULL, kpidId, VT_BSTR} }; -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidCTime, VT_FILETIME} + kpidSize, + kpidPackSize, + kpidCTime /* - { NULL, kpidNumCyls, VT_UI4}, - { NULL, kpidNumHeads, VT_UI4}, - { NULL, kpidSectorsPerTrack, VT_UI4} + { kpidNumCyls, VT_UI4}, + { kpidNumHeads, VT_UI4}, + { kpidSectorsPerTrack, VT_UI4} */ }; @@ -470,11 +649,11 @@ static void VhdTimeToFileTime(UInt32 vhdTime, NCOM::CPropVariant &prop) prop = utc; } -static void StringToAString(char *dest, UInt32 s) +static void StringToAString(char *dest, UInt32 val) { for (int i = 24; i >= 0; i -= 8) { - Byte b = (Byte)((s >> i) & 0xFF); + Byte b = (Byte)((val >> i) & 0xFF); if (b < 0x20 || b > 0x7F) break; *dest++ = b; @@ -496,11 +675,12 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidMainSubfile: prop = (UInt32)0; break; case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break; case kpidClusterSize: if (Footer.ThereIsDynamic()) prop = (UInt32)1 << Dyn.BlockSizeLog; break; + case kpidShortComment: case kpidMethod: { AString s = Footer.GetTypeString(); @@ -535,7 +715,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } case kpidHostOS: { - if (Footer.CreatorHostOS == 0x5769326b) + if (Footer.CreatorHostOS == 0x5769326B) prop = "Windows"; else { @@ -555,18 +735,32 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) break; } case kpidSavedState: prop = Footer.SavedState ? true : false; break; - case kpidParent: if (NeedParent()) prop = GetParentName(); break; + case kpidParent: if (NeedParent()) prop = GetParentSequence(); break; + case kpidOffset: prop = _startOffset; break; + case kpidPhySize: prop = _phySize; break; + /* + case kpidErrorFlags: + { + UInt32 flags = 0; + if (_unexpectedEnd) + flags |= kpv_ErrorFlags_UnexpectedEndOfArc; + if (flags != 0) + prop = flags; + break; + } + */ + case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; } prop.Detach(value); return S_OK; COM_TRY_END } -HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, int level) +HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level) { Close(); Stream = stream; - if (level > 32) + if (level > (1 << 12)) // Maybe we need to increase that limit return S_FALSE; RINOK(Open3()); if (child && memcmp(child->Dyn.ParentId, Footer.Id, 16) != 0) @@ -575,16 +769,65 @@ HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback return S_OK; CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; if (openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback) != S_OK) - return S_FALSE; + { + // return S_FALSE; + } CMyComPtr<IInStream> nextStream; - HRESULT res = openVolumeCallback->GetStream(Dyn.ParentName, &nextStream); - if (res == S_FALSE) - return S_OK; - RINOK(res); - Parent = new CHandler; - ParentStream = Parent; - return Parent->Open2(nextStream, this, openArchiveCallback, level + 1); + bool useRelative; + UString name; + if (!Dyn.RelativeParentNameFromLocator.IsEmpty()) + { + useRelative = true; + name = Dyn.RelativeParentNameFromLocator; + } + else + { + useRelative = false; + name = Dyn.ParentName; + } + Dyn.RelativeNameWasUsed = useRelative; + + if (openVolumeCallback) + { + HRESULT res = openVolumeCallback->GetStream(name, &nextStream); + if (res == S_FALSE) + { + if (useRelative && Dyn.ParentName != Dyn.RelativeParentNameFromLocator) + { + res = openVolumeCallback->GetStream(Dyn.ParentName, &nextStream); + if (res == S_OK) + Dyn.RelativeNameWasUsed = false; + } + if (res == S_FALSE) + return S_OK; + } + RINOK(res); + + Parent = new CHandler; + ParentStream = Parent; + + res = Parent->Open2(nextStream, this, openArchiveCallback, level + 1); + if (res == S_FALSE) + { + Parent = NULL; + ParentStream.Release(); + } + } + { + const CHandler *p = this; + while (p->NeedParent()) + { + p = p->Parent; + if (p == 0) + { + AddErrorMessage(L"Can't open parent VHD file:"); + AddErrorMessage(Dyn.ParentName); + break; + } + } + } + return S_OK; } STDMETHODIMP CHandler::Open(IInStream *stream, @@ -613,11 +856,15 @@ STDMETHODIMP CHandler::Open(IInStream *stream, STDMETHODIMP CHandler::Close() { + _phySize = 0; Bat.Clear(); NumUsedBlocks = 0; Parent = 0; Stream.Release(); ParentStream.Release(); + Dyn.Clear(); + _errorMessage.Empty(); + // _unexpectedEnd = false; return S_OK; } @@ -629,8 +876,8 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + // COM_TRY_BEGIN + NCOM::CPropVariant prop; switch(propID) { @@ -645,7 +892,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN } prop.Detach(value); return S_OK; - COM_TRY_END + // COM_TRY_END } STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, @@ -654,7 +901,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_BEGIN if (numItems == 0) return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; RINOK(extractCallback->SetTotal(Footer.CurrentSize)); @@ -678,7 +925,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ISequentialInStream> inStream; HRESULT hres = GetStream(0, &inStream); if (hres == S_FALSE) - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; else { RINOK(hres); @@ -715,7 +962,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea *stream = streamTemp.Detach(); return S_OK; } - if (!Footer.ThereIsDynamic() || !IsOK()) + if (!Footer.ThereIsDynamic() || !AreParentsOK()) return S_FALSE; CMyComPtr<ISequentialInStream> streamTemp = this; RINOK(InitAndSeek()); @@ -724,10 +971,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"VHD", L"vhd", L".mbr", 0xDC, { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x', 0, 0 }, 10, false, CreateArc, 0 }; + { "VHD", "vhd", ".mbr", 0xDC, + kSignatureSize, SIGNATURE, + 0, + NArcInfoFlags::kUseGlobalOffset, + CreateArc }; REGISTER_ARC(Vhd) diff --git a/CPP/7zip/Archive/Wim/StdAfx.h b/CPP/7zip/Archive/Wim/StdAfx.h index e7fb6986..2854ff3e 100755..100644 --- a/CPP/7zip/Archive/Wim/StdAfx.h +++ b/CPP/7zip/Archive/Wim/StdAfx.h @@ -3,6 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" +#include "../../../Common/Common.h" #endif diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp index eaad1e7c..6f0b10e2 100755..100644 --- a/CPP/7zip/Archive/Wim/WimHandler.cpp +++ b/CPP/7zip/Archive/Wim/WimHandler.cpp @@ -4,13 +4,10 @@ #include "../../../../C/CpuArch.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/StringToInt.h" -#include "Common/UTFConvert.h" - -#include "Windows/PropVariant.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../Common/MethodProps.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamUtils.h" @@ -25,29 +22,36 @@ using namespace NWindows; namespace NArchive { namespace NWim { -#define WIM_DETAILS +// #define WIM_DETAILS -static STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidATime, VT_FILETIME}, - { NULL, kpidAttrib, VT_UI4}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidShortName, VT_BSTR} + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidAttrib, + kpidMethod, + kpidShortName, + kpidINode, + kpidLinks #ifdef WIM_DETAILS - , { NULL, kpidVolume, VT_UI4} - , { NULL, kpidOffset, VT_UI8} - , { NULL, kpidLinks, VT_UI4} + , kpidVolume + , kpidOffset #endif }; -static STATPROPSTG kArcProps[] = +enum +{ + kpidNumImages = kpidUserDefined, + kpidBootImage +}; + +static const STATPROPSTG kArcProps[] = { { NULL, kpidSize, VT_UI8}, { NULL, kpidPackSize, VT_UI8}, @@ -58,133 +62,60 @@ static STATPROPSTG kArcProps[] = { NULL, kpidUnpackVer, VT_BSTR}, { NULL, kpidIsVolume, VT_BOOL}, { NULL, kpidVolume, VT_UI4}, - { NULL, kpidNumVolumes, VT_UI4} + { NULL, kpidNumVolumes, VT_UI4}, + { L"Images", kpidNumImages, VT_UI4}, + { L"Boot Image", kpidBootImage, VT_UI4} }; -static bool ParseNumber64(const AString &s, UInt64 &res) -{ - const char *end; - if (s.Left(2) == "0x") - { - if (s.Length() == 2) - return false; - res = ConvertHexStringToUInt64((const char *)s + 2, &end); - } - else - { - if (s.IsEmpty()) - return false; - res = ConvertStringToUInt64(s, &end); - } - return *end == 0; -} - -static bool ParseNumber32(const AString &s, UInt32 &res) -{ - UInt64 res64; - if (!ParseNumber64(s, res64) || res64 >= ((UInt64)1 << 32)) - return false; - res = (UInt32)res64; - return true; -} - -bool ParseTime(const CXmlItem &item, FILETIME &ft, const char *tag) -{ - int index = item.FindSubTag(tag); - if (index >= 0) - { - const CXmlItem &timeItem = item.SubItems[index]; - UInt32 low = 0, high = 0; - if (ParseNumber32(timeItem.GetSubStringForTag("LOWPART"), low) && - ParseNumber32(timeItem.GetSubStringForTag("HIGHPART"), high)) - { - ft.dwLowDateTime = low; - ft.dwHighDateTime = high; - return true; - } - } - return false; -} +static const char *kMethodLZX = "LZX"; +static const char *kMethodXpress = "XPress"; +static const char *kMethodCopy = "Copy"; -void CImageInfo::Parse(const CXmlItem &item) -{ - CTimeDefined = ParseTime(item, CTime, "CREATIONTIME"); - MTimeDefined = ParseTime(item, MTime, "LASTMODIFICATIONTIME"); - NameDefined = ConvertUTF8ToUnicode(item.GetSubStringForTag("NAME"), Name); - // IndexDefined = ParseNumber32(item.GetPropertyValue("INDEX"), Index); -} +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_WITH_NAME -void CXml::ToUnicode(UString &s) +static void AddErrorMessage(AString &s, const char *message) { - size_t size = Data.GetCapacity(); - if (size < 2 || (size & 1) != 0 || size > (1 << 24)) - return; - const Byte *p = Data; - if (Get16(p) != 0xFEFF) - return; - wchar_t *chars = s.GetBuffer((int)size / 2); - for (size_t i = 2; i < size; i += 2) - *chars++ = (wchar_t)Get16(p + i); - *chars = 0; - s.ReleaseBuffer(); + if (!s.IsEmpty()) + s += ". "; + s += message; } -void CXml::Parse() +static void ConvertByteToHex(unsigned value, char *s) { - UString s; - ToUnicode(s); - AString utf; - if (!ConvertUnicodeToUTF8(s, utf)) - return; - ::CXml xml; - if (!xml.Parse(utf)) - return; - if (xml.Root.Name != "WIM") - return; - - for (int i = 0; i < xml.Root.SubItems.Size(); i++) + for (int i = 0; i < 2; i++) { - const CXmlItem &item = xml.Root.SubItems[i]; - if (item.IsTagged("IMAGE")) - { - CImageInfo imageInfo; - imageInfo.Parse(item); - Images.Add(imageInfo); - } + unsigned t = value & 0xF; + value >>= 4; + s[1 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); } } -static const char *kMethodLZX = "LZX"; -static const char *kMethodXpress = "XPress"; -static const char *kMethodCopy = "Copy"; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; const CImageInfo *image = NULL; if (_xmls.Size() == 1) { - const CXml &xml = _xmls[0]; + const CWimXml &xml = _xmls[0]; if (xml.Images.Size() == 1) image = &xml.Images[0]; } - switch(propID) + switch (propID) { + case kpidPhySize: prop = _phySize; break; case kpidSize: prop = _db.GetUnpackSize(); break; case kpidPackSize: prop = _db.GetPackSize(); break; case kpidCTime: if (_xmls.Size() == 1) { - const CXml &xml = _xmls[0]; + const CWimXml &xml = _xmls[0]; int index = -1; - for (int i = 0; i < xml.Images.Size(); i++) + FOR_VECTOR (i, xml.Images) { const CImageInfo &image = xml.Images[i]; if (image.CTimeDefined) @@ -199,9 +130,9 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidMTime: if (_xmls.Size() == 1) { - const CXml &xml = _xmls[0]; + const CWimXml &xml = _xmls[0]; int index = -1; - for (int i = 0; i < xml.Images.Size(); i++) + FOR_VECTOR (i, xml.Images) { const CImageInfo &image = xml.Images[i]; if (image.MTimeDefined) @@ -266,10 +197,63 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } break; case kpidNumVolumes: if (_volumes.Size() > 0) prop = (UInt32)(_volumes.Size() - 1); break; + + case kpidName: + if (_firstVolumeIndex >= 0) + { + const CHeader &h = _volumes[_firstVolumeIndex].Header; + if (GetUi32(h.Guid) != 0) + { + char temp[16 * 2 + 4]; + int i; + for (i = 0; i < 4; i++) + ConvertByteToHex(h.Guid[i], temp + i * 2); + temp[i * 2] = 0; + AString s = temp; + const char *ext = ".wim"; + if (h.NumParts != 1) + { + s += '_'; + if (h.PartNumber != 1) + { + char sz[16]; + ConvertUInt32ToString(h.PartNumber, sz); + s += sz; + } + ext = ".swm"; + } + s += ext; + prop = s; + } + } + break; + + case kpidExtension: + if (_firstVolumeIndex >= 0) + { + const CHeader &h = _volumes[_firstVolumeIndex].Header; + if (h.NumParts > 1) + { + AString s; + if (h.PartNumber != 1) + { + char sz[16]; + ConvertUInt32ToString(h.PartNumber, sz); + s = sz; + s += '.'; + } + s += "swm"; + prop = s; + } + } + break; + + case kpidNumImages: prop = (UInt32)_db.Images.Size(); break; + case kpidBootImage: if (_bootIndex != 0) prop = (UInt32)_bootIndex; break; case kpidMethod: { bool lzx = false, xpress = false, copy = false; - for (int i = 0; i < _xmls.Size(); i++) + FOR_VECTOR (i, _xmls) { const CHeader &header = _volumes[_xmls[i].VolIndex].Header; if (header.IsCompressed()) @@ -296,6 +280,34 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) res += kMethodCopy; } prop = res; + break; + } + case kpidIsTree: prop = true; break; + case kpidIsAltStream: prop = _db.ThereAreAltStreams; break; + case kpidIsAux: prop = true; break; + // WIM uses special prefix to represent deleted items + // case kpidIsDeleted: prop = _db.ThereAreDeletedStreams; break; + case kpidINode: prop = true; break; + + case kpidErrorFlags: + { + UInt32 flags = 0; + if (!_isArc) flags |= kpv_ErrorFlags_IsNotArc; + // if (HeadersError) flags |= kpv_ErrorFlags_HeadersError; + // if (UnexpectedEnd) flags |= kpv_ErrorFlags_UnexpectedEndOfArc; + prop = flags; + break; + } + + case kpidWarning: + { + AString s; + if (_xmlError) + AddErrorMessage(s, "XML error"); + if (_db.RefCountError) + AddErrorMessage(s, "Some files have incorrect reference count"); + if (!s.IsEmpty()) + prop = s; } } prop.Detach(value); @@ -303,104 +315,404 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) COM_TRY_END } +void GetFileTime(const Byte *p, NCOM::CPropVariant &prop) +{ + prop.vt = VT_FILETIME; + prop.filetime.dwLowDateTime = Get32(p); + prop.filetime.dwHighDateTime = Get32(p + 4); +} + +#define FILES_DIR_NAME "[Files]" + STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - if (index < (UInt32)_db.SortedItems.Size()) + NCOM::CPropVariant prop; + + if (index < _db.SortedItems.Size()) { - int realIndex = _db.SortedItems[index]; + unsigned realIndex = _db.SortedItems[index]; const CItem &item = _db.Items[realIndex]; const CStreamInfo *si = NULL; const CVolume *vol = NULL; if (item.StreamIndex >= 0) { - si = &_db.Streams[item.StreamIndex]; + si = &_db.DataStreams[item.StreamIndex]; vol = &_volumes[si->PartNumber]; } - switch(propID) + const CItem *mainItem = &item; + if (item.IsAltStream) + mainItem = &_db.Items[item.Parent]; + const Byte *metadata = NULL; + if (mainItem->ImageIndex >= 0) + metadata = _db.Images[mainItem->ImageIndex].Meta + mainItem->Offset; + + switch (propID) { case kpidPath: - if (item.HasMetadata) - prop = _db.GetItemPath(realIndex); + if (item.ImageIndex >= 0) + _db.GetItemPath(realIndex, _showImageNumber, prop); else { char sz[16]; ConvertUInt32ToString(item.StreamIndex, sz); AString s = sz; - while (s.Length() < _nameLenForStreams) + /* + while (s.Len() < _nameLenForStreams) s = '0' + s; + */ /* if (si->Resource.IsFree()) - prefix = "[Free]"; + s = (AString)("[Free]" STRING_PATH_SEPARATOR) + sz; + else */ - s = "[Files]" STRING_PATH_SEPARATOR + s; + s = (AString)(FILES_DIR_NAME STRING_PATH_SEPARATOR) + sz; prop = s; } break; - case kpidShortName: if (item.HasMetadata) prop = item.ShortName; break; - - case kpidIsDir: prop = item.IsDir(); break; - case kpidAttrib: if (item.HasMetadata) prop = item.Attrib; break; - case kpidCTime: if (item.HasMetadata) prop = item.CTime; break; - case kpidATime: if (item.HasMetadata) prop = item.ATime; break; - case kpidMTime: if (item.HasMetadata) prop = item.MTime; break; - case kpidPackSize: prop = si ? si->Resource.PackSize : (UInt64)0; break; - case kpidSize: prop = si ? si->Resource.UnpackSize : (UInt64)0; break; + + case kpidName: + if (item.ImageIndex >= 0) + _db.GetItemName(realIndex, prop); + else + { + char sz[16]; + ConvertUInt32ToString(item.StreamIndex, sz); + /* + AString s = sz; + while (s.Len() < _nameLenForStreams) + s = '0' + s; + */ + prop = sz; + } + break; + + case kpidShortName: + if (item.ImageIndex >= 0 && !item.IsAltStream) + _db.GetShortName(realIndex, prop); + break; + + case kpidPackSize: prop = (UInt64)(si ? si->Resource.PackSize : 0); break; + case kpidSize: prop = (UInt64)(si ? si->Resource.UnpackSize : 0); break; + case kpidIsDir: prop = item.IsDir; break; + case kpidIsAltStream: prop = item.IsAltStream; break; + case kpidAttrib: + if (!item.IsAltStream && mainItem->ImageIndex >= 0) + { + /* + if (fileNameLen == 0 && isDir && !item.HasStream()) + item.Attrib = 0x10; // some swm archives have system/hidden attributes for root + */ + prop = (UInt32)Get32(metadata + 8); + } + break; + case kpidCTime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x18: 0x28), prop); break; + case kpidATime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x20: 0x30), prop); break; + case kpidMTime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x28: 0x38), prop); break; + + case kpidINode: + if (mainItem->HasMetadata() && !_isOldVersion) + { + UInt32 attrib = (UInt32)Get32(metadata + 8); + if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0) + { + // we don't know about that field in OLD WIM format + unsigned offset = 0x58; // (_db.IsOldVersion ? 0x30: 0x58); + UInt64 val = Get64(metadata + offset); + if (val != 0) + prop = val; + } + } + break; + + case kpidStreamId: + if (item.StreamIndex >= 0) + prop = (UInt32)item.StreamIndex; + break; + case kpidMethod: if (si) prop = si->Resource.IsCompressed() ? (vol->Header.IsLzxMode() ? kMethodLZX : kMethodXpress) : kMethodCopy; break; + case kpidLinks: if (si) prop = (UInt32)si->RefCount; break; #ifdef WIM_DETAILS case kpidVolume: if (si) prop = (UInt32)si->PartNumber; break; case kpidOffset: if (si) prop = (UInt64)si->Resource.Offset; break; - case kpidLinks: prop = si ? (UInt32)si->RefCount : (UInt32)0; break; #endif } } else { index -= _db.SortedItems.Size(); + if (index < _numXmlItems) { - switch(propID) + switch (propID) { case kpidPath: - { - char sz[16]; - ConvertUInt32ToString(_xmls[index].VolIndex, sz); - prop = (AString)"[" + (AString)sz + "].xml"; - break; - } + case kpidName: prop = _xmls[index].FileName; break; case kpidIsDir: prop = false; break; case kpidPackSize: - case kpidSize: prop = (UInt64)_xmls[index].Data.GetCapacity(); break; + case kpidSize: prop = (UInt64)_xmls[index].Data.Size(); break; case kpidMethod: prop = kMethodCopy; break; } } + else + { + index -= _numXmlItems; + switch (propID) + { + case kpidPath: + case kpidName: + if (index < (UInt32)_db.VirtualRoots.Size()) + prop = _db.Images[_db.VirtualRoots[index]].RootName; + else + prop = FILES_DIR_NAME; + break; + case kpidIsDir: prop = true; break; + case kpidIsAux: prop = true; break; + } + } } prop.Detach(value); return S_OK; COM_TRY_END } +STDMETHODIMP CHandler::GetRootProp(PROPID propID, PROPVARIANT *value) +{ + // COM_TRY_BEGIN + NCOM::CPropVariant prop; + if (_db.Images.Size() != 0 && _db.NumExludededItems != 0) + { + const CImage &image = _db.Images[_db.IndexOfUserImage]; + const CItem &item = _db.Items[image.StartItem]; + if (!item.IsDir || item.ImageIndex != _db.IndexOfUserImage) + return E_FAIL; + const Byte *metadata = image.Meta + item.Offset; + + switch (propID) + { + case kpidIsDir: prop = true; break; + case kpidAttrib: prop = (UInt32)Get32(metadata + 8); break; + case kpidCTime: GetFileTime(metadata + (_db.IsOldVersion ? 0x18: 0x28), prop); break; + case kpidATime: GetFileTime(metadata + (_db.IsOldVersion ? 0x20: 0x30), prop); break; + case kpidMTime: GetFileTime(metadata + (_db.IsOldVersion ? 0x28: 0x38), prop); break; + } + } + prop.Detach(value); + return S_OK; + // COM_TRY_END +} + +HRESULT CHandler::GetSecurity(UInt32 realIndex, const void **data, UInt32 *dataSize, UInt32 *propType) +{ + const CItem &item = _db.Items[realIndex]; + if (item.IsAltStream || item.ImageIndex < 0) + return S_OK; + const CImage &image = _db.Images[item.ImageIndex]; + const Byte *metadata = image.Meta + item.Offset; + UInt32 securityId = Get32(metadata + 0xC); + if (securityId == (UInt32)(Int32)-1) + return S_OK; + if (securityId >= (UInt32)image.SecurOffsets.Size()) + return E_FAIL; + UInt32 offs = image.SecurOffsets[securityId]; + UInt32 len = image.SecurOffsets[securityId + 1] - offs; + const CByteBuffer &buf = image.Meta; + if (offs <= buf.Size() && buf.Size() - offs >= len) + { + *data = buf + offs; + *dataSize = len; + *propType = NPropDataType::kRaw; + } + return S_OK; +} + +STDMETHODIMP CHandler::GetRootRawProp(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) +{ + *data = 0; + *dataSize = 0; + *propType = 0; + if (propID == kpidNtSecure && _db.Images.Size() != 0 && _db.NumExludededItems != 0) + { + const CImage &image = _db.Images[_db.IndexOfUserImage]; + const CItem &item = _db.Items[image.StartItem]; + if (!item.IsDir || item.ImageIndex != _db.IndexOfUserImage) + return E_FAIL; + return GetSecurity(image.StartItem, data, dataSize, propType); + } + return S_OK; +} + +static const Byte kRawProps[] = +{ + kpidSha1, + kpidNtReparse, + kpidNtSecure +}; + + +STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) +{ + *numProps = ARRAY_SIZE(kRawProps); + return S_OK; +} + +STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) +{ + *propID = kRawProps[index]; + *name = 0; + return S_OK; +} + +STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType) +{ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; + if (index >= _db.SortedItems.Size()) + return S_OK; + + const CItem &item = _db.Items[_db.SortedItems[index]]; + + if (item.ImageIndex >= 0) + { + *parentType = item.IsAltStream ? NParentType::kAltStream : NParentType::kDir; + if (item.Parent >= 0) + { + if (_db.ExludedItem != item.Parent) + *parent = _db.Items[item.Parent].IndexInSorted; + } + else + { + CImage &image = _db.Images[item.ImageIndex]; + if (image.VirtualRootIndex >= 0) + *parent = _db.SortedItems.Size() + _numXmlItems + image.VirtualRootIndex; + } + } + else + *parent = _db.SortedItems.Size() + _numXmlItems + _db.VirtualRoots.Size(); + return S_OK; +} + +static bool IsEmptySha(const Byte *data) +{ + for (int i = 0; i < kHashSize; i++) + if (data[i] != 0) + return false; + return true; +} + +STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + + if (propID == kpidName) + { + if (index < _db.SortedItems.Size()) + { + const CItem &item = _db.Items[_db.SortedItems[index]]; + if (item.ImageIndex < 0) + return S_OK; + const CImage &image = _db.Images[item.ImageIndex]; + *propType = NPropDataType::kUtf16z; + if (image.NumEmptyRootItems != 0 && item.Parent < 0) + { + const CByteBuffer &buf = _db.Images[item.ImageIndex].RootNameBuf; + *data = (void *)(const Byte *)buf; + *dataSize = (UInt32)buf.Size(); + return S_OK; + } + const Byte *meta = image.Meta + item.Offset + + (item.IsAltStream ? + (_isOldVersion ? 0x10 : 0x24) : + (_isOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2)); + *data = (const void *)(meta + 2); + *dataSize = (UInt32)Get16(meta) + 2; + return S_OK; + } + { + index -= _db.SortedItems.Size(); + if (index < _numXmlItems) + return S_OK; + index -= _numXmlItems; + if (index >= (UInt32)_db.VirtualRoots.Size()) + return S_OK; + const CByteBuffer &buf = _db.Images[_db.VirtualRoots[index]].RootNameBuf; + *data = (void *)(const Byte *)buf; + *dataSize = (UInt32)buf.Size(); + *propType = NPropDataType::kUtf16z; + return S_OK; + } + } + + if (index >= _db.SortedItems.Size()) + return S_OK; + + unsigned index2 = _db.SortedItems[index]; + + if (propID == kpidNtSecure) + { + return GetSecurity(index2, data, dataSize, propType); + } + + const CItem &item = _db.Items[index2]; + if (propID == kpidSha1) + { + if (item.StreamIndex >= 0) + *data = _db.DataStreams[item.StreamIndex].Hash; + else + { + if (_isOldVersion) + return S_OK; + const Byte *sha1 = _db.Images[item.ImageIndex].Meta + item.Offset + (item.IsAltStream ? 0x10 : 0x40); + if (IsEmptySha(sha1)) + return S_OK; + *data = sha1; + } + *dataSize = kHashSize; + *propType = NPropDataType::kRaw; + return S_OK; + } + + if (propID == kpidNtReparse && !_isOldVersion) + { + // we don't know about Reparse field in OLD WIM format + + if (item.StreamIndex < 0) + return S_OK; + if (index2 >= _db.ItemToReparse.Size()) + return S_OK; + int reparseIndex = _db.ItemToReparse[index2]; + if (reparseIndex < 0) + return S_OK; + const CByteBuffer &buf = _db.ReparseItems[reparseIndex]; + if (buf.Size() == 0) + return S_OK; + *data = buf; + *dataSize = (UInt32)buf.Size(); + *propType = NPropDataType::kRaw; + return S_OK; + } + + return S_OK; +} + class CVolumeName { - // UInt32 _volIndex; UString _before; UString _after; public: - CVolumeName() {}; - void InitName(const UString &name) { - // _volIndex = 1; int dotPos = name.ReverseFind('.'); if (dotPos < 0) - dotPos = name.Length(); + dotPos = name.Len(); _before = name.Left(dotPos); - _after = name.Mid(dotPos); + _after = name.Ptr(dotPos); } - UString GetNextName(UInt32 index) + UString GetNextName(UInt32 index) const { wchar_t s[16]; ConvertUInt32ToString(index, s); @@ -408,25 +720,26 @@ public: } }; -STDMETHODIMP CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback *openArchiveCallback) +STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback) { COM_TRY_BEGIN + Close(); { CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; CVolumeName seqName; - if (openArchiveCallback != NULL) - openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + if (callback) + callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); UInt32 numVolumes = 1; - int firstVolumeIndex = -1; + for (UInt32 i = 1; i <= numVolumes; i++) { CMyComPtr<IInStream> curStream; - if (i != 1) + if (i == 1) + curStream = inStream; + else { UString fullName = seqName.GetNextName(i); HRESULT result = openVolumeCallback->GetStream(fullName, &curStream); @@ -437,52 +750,59 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, if (!curStream) break; } - else - curStream = inStream; CHeader header; - HRESULT res = NWim::ReadHeader(curStream, header); + HRESULT res = NWim::ReadHeader(curStream, header, _phySize); if (res != S_OK) { - if (i == 1) - return res; - if (res == S_FALSE) + if (i != 1 && res == S_FALSE) continue; return res; } + _isArc = true; + _bootIndex = header.BootIndex; _version = header.Version; _isOldVersion = header.IsOldVersion(); - if (firstVolumeIndex >= 0) - if (!header.AreFromOnArchive(_volumes[firstVolumeIndex].Header)) + if (_firstVolumeIndex >= 0) + if (!header.AreFromOnArchive(_volumes[_firstVolumeIndex].Header)) break; if (_volumes.Size() > header.PartNumber && _volumes[header.PartNumber].Stream) break; - CXml xml; + CWimXml xml; xml.VolIndex = header.PartNumber; - res = _db.Open(curStream, header, xml.Data, openArchiveCallback); + res = _db.OpenXml(curStream, header, xml.Data); + if (res == S_OK) + { + if (!xml.Parse()) + _xmlError = true; + + UInt64 totalFiles = xml.GetTotalFilesAndDirs() + xml.Images.Size(); + totalFiles += 16 + xml.Images.Size() * 4; // we reserve some additional items + if (totalFiles >= ((UInt32)1 << 30)) + totalFiles = 0; + res = _db.Open(curStream, header, (unsigned)totalFiles, callback); + } if (res != S_OK) { - if (i == 1) - return res; - if (res == S_FALSE) + if (i != 1 && res == S_FALSE) continue; return res; } while (_volumes.Size() <= header.PartNumber) - _volumes.Add(CVolume()); + _volumes.AddNew(); CVolume &volume = _volumes[header.PartNumber]; volume.Header = header; volume.Stream = curStream; - firstVolumeIndex = header.PartNumber; + _firstVolumeIndex = header.PartNumber; - bool needAddXml = true; - if (_xmls.Size() != 0) - if (xml.Data == _xmls[0].Data) - needAddXml = false; - if (needAddXml) + if (_xmls.IsEmpty() || xml.Data != _xmls[0].Data) { - xml.Parse(); + wchar_t sz[16]; + ConvertUInt32ToString(xml.VolIndex, sz); + xml.FileName = L'['; + xml.FileName += sz; + xml.FileName += L"].xml"; _xmls.Add(xml); } @@ -503,14 +823,30 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, } } - _db.DetectPathMode(); - RINOK(_db.Sort(_db.SkipRoot)); + RINOK(_db.FillAndCheck()); + int defaultImageIndex = (int)_defaultImageNumber - 1; + + bool showImageNumber = (_db.Images.Size() != 1 && defaultImageIndex < 0); + if (!showImageNumber && _set_use_ShowImageNumber) + showImageNumber = _set_showImageNumber; + if (!showImageNumber && _keepMode_ShowImageNumber) + showImageNumber = true; + + _showImageNumber = showImageNumber; + + RINOK(_db.GenerateSortedItems(defaultImageIndex, showImageNumber)); + RINOK(_db.ExtractReparseStreams(_volumes, callback)); + + /* wchar_t sz[16]; - ConvertUInt32ToString(_db.Streams.Size(), sz); + ConvertUInt32ToString(_db.DataStreams.Size(), sz); _nameLenForStreams = MyStringLen(sz); + */ - _xmlInComments = (_xmls.Size() == 1 && !_db.ShowImageNumber); + _xmlInComments = !_showImageNumber; + _numXmlItems = (_xmlInComments ? 0 : _xmls.Size()); + _numIgnoreItems = _db.ThereAreDeletedStreams ? 1 : 0; } return S_OK; COM_TRY_END @@ -518,10 +854,17 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, STDMETHODIMP CHandler::Close() { + _firstVolumeIndex = -1; + _phySize = 0; _db.Clear(); _volumes.Clear(); _xmls.Clear(); - _nameLenForStreams = 0; + // _nameLenForStreams = 0; + _xmlInComments = false; + _numXmlItems = 0; + _numIgnoreItems = 0; + _xmlError = false; + _isArc = false; return S_OK; } @@ -529,10 +872,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) - numItems = _db.SortedItems.Size() + _xmls.Size(); + numItems = _db.SortedItems.Size() + _numXmlItems + _db.VirtualRoots.Size() + _numIgnoreItems; if (numItems == 0) return S_OK; @@ -541,17 +884,21 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, for (i = 0; i < numItems; i++) { UInt32 index = allFilesMode ? i : indices[i]; - if (index < (UInt32)_db.SortedItems.Size()) + if (index < _db.SortedItems.Size()) { int streamIndex = _db.Items[_db.SortedItems[index]].StreamIndex; if (streamIndex >= 0) { - const CStreamInfo &si = _db.Streams[streamIndex]; + const CStreamInfo &si = _db.DataStreams[streamIndex]; totalSize += si.Resource.UnpackSize; } } else - totalSize += _xmls[index - (UInt32)_db.SortedItems.Size()].Data.GetCapacity(); + { + index -= _db.SortedItems.Size(); + if (index < (UInt32)_numXmlItems) + totalSize += _xmls[index].Data.Size(); + } } RINOK(extractCallback->SetTotal(totalSize)); @@ -586,17 +933,21 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ISequentialOutStream> realOutStream; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - if (index >= (UInt32)_db.SortedItems.Size()) + if (index >= _db.SortedItems.Size()) { if (!testMode && !realOutStream) continue; RINOK(extractCallback->PrepareOperation(askMode)); - const CByteBuffer &data = _xmls[index - (UInt32)_db.SortedItems.Size()].Data; - currentItemUnPacked = data.GetCapacity(); - if (realOutStream) + index -= _db.SortedItems.Size(); + if (index < (UInt32)_numXmlItems) { - RINOK(WriteStream(realOutStream, (const Byte *)data, data.GetCapacity())); - realOutStream.Release(); + const CByteBuffer &data = _xmls[index].Data; + currentItemUnPacked = data.Size(); + if (realOutStream) + { + RINOK(WriteStream(realOutStream, (const Byte *)data, data.Size())); + realOutStream.Release(); + } } RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); continue; @@ -610,13 +961,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; RINOK(extractCallback->PrepareOperation(askMode)); realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(item.HasStream() ? - NExtract::NOperationResult::kDataError : - NExtract::NOperationResult::kOK)); + RINOK(extractCallback->SetOperationResult(_db.ItemHasStream(item) ? + NExtract::NOperationResult::kDataError : + NExtract::NOperationResult::kOK)); continue; } - const CStreamInfo &si = _db.Streams[streamIndex]; + const CStreamInfo &si = _db.DataStreams[streamIndex]; currentItemUnPacked = si.Resource.UnpackSize; currentItemPacked = si.Resource.PackSize; @@ -626,7 +977,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 opRes = NExtract::NOperationResult::kOK; if (streamIndex != prevSuccessStreamIndex || realOutStream) { - Byte digest[20]; + Byte digest[kHashSize]; const CVolume &vol = _volumes[si.PartNumber]; HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header.IsLzxMode(), realOutStream, progress, digest); @@ -651,9 +1002,59 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { - *numItems = _db.SortedItems.Size(); - if (!_xmlInComments) - *numItems += _xmls.Size(); + *numItems = _db.SortedItems.Size() + + _numXmlItems + + _db.VirtualRoots.Size() + + _numIgnoreItems; + return S_OK; +} + +CHandler::CHandler() +{ + _keepMode_ShowImageNumber = false; + InitDefaults(); + _xmlError = false; +} + +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +{ + InitDefaults(); + + for (UInt32 i = 0; i < numProps; i++) + { + UString name = names[i]; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + const PROPVARIANT &prop = values[i]; + + if (name[0] == L'x') + { + // some clients write 'x' property. So we support it + UInt32 level = 0; + RINOK(ParsePropToUInt32(name.Ptr(1), prop, level)); + } + else if (name.IsEqualTo("is")) + { + RINOK(PROPVARIANT_to_bool(prop, _set_showImageNumber)); + _set_use_ShowImageNumber = true; + } + else if (name.IsEqualTo("im")) + { + UInt32 image = 9; + RINOK(ParsePropToUInt32(L"", prop, image)); + _defaultImageNumber = image; + } + else + return E_INVALIDARG; + } + return S_OK; +} + +STDMETHODIMP CHandler::KeepModeForNextOpen() +{ + _keepMode_ShowImageNumber = _showImageNumber; return S_OK; } diff --git a/CPP/7zip/Archive/Wim/WimHandler.h b/CPP/7zip/Archive/Wim/WimHandler.h index aa92069a..416e11ca 100755..100644 --- a/CPP/7zip/Archive/Wim/WimHandler.h +++ b/CPP/7zip/Archive/Wim/WimHandler.h @@ -3,72 +3,75 @@ #ifndef __ARCHIVE_WIM_HANDLER_H #define __ARCHIVE_WIM_HANDLER_H -#include "Common/MyCom.h" -#include "Common/MyXml.h" +#include "../../../Common/MyCom.h" #include "WimIn.h" namespace NArchive { namespace NWim { -struct CVolume -{ - CHeader Header; - CMyComPtr<IInStream> Stream; -}; - -struct CImageInfo -{ - bool CTimeDefined; - bool MTimeDefined; - bool NameDefined; - // bool IndexDefined; - - FILETIME CTime; - FILETIME MTime; - UString Name; - // UInt32 Index; - - CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false) - // , IndexDefined(false) - {} - void Parse(const CXmlItem &item); -}; - -struct CXml -{ - CByteBuffer Data; - UInt16 VolIndex; - CObjectVector<CImageInfo> Images; - - void ToUnicode(UString &s); - void Parse(); -}; - - class CHandler: public IInArchive, + public IArchiveGetRawProps, + public IArchiveGetRootProps, + public IArchiveKeepModeForNextOpen, + public ISetProperties, + public IOutArchive, public CMyUnknownImp { CDatabase _db; UInt32 _version; bool _isOldVersion; + UInt32 _bootIndex; + CObjectVector<CVolume> _volumes; - CObjectVector<CXml> _xmls; - int _nameLenForStreams; + CObjectVector<CWimXml> _xmls; + // unsigned _nameLenForStreams; bool _xmlInComments; + + unsigned _numXmlItems; + unsigned _numIgnoreItems; -public: - MY_UNKNOWN_IMP1(IInArchive) - INTERFACE_IInArchive(;) -}; + bool _xmlError; + bool _isArc; -class COutHandler: - public IOutArchive, - public CMyUnknownImp -{ + bool _set_use_ShowImageNumber; + bool _set_showImageNumber; + int _defaultImageNumber; + + bool _showImageNumber; + + bool _keepMode_ShowImageNumber; + + UInt64 _phySize; + int _firstVolumeIndex; + + void InitDefaults() + { + _set_use_ShowImageNumber = false; + _set_showImageNumber = false; + _defaultImageNumber = -1; + } + + bool ThereIsError() const { return _xmlError || _db.ThereIsError(); } + HRESULT GetSecurity(UInt32 realIndex, const void **data, UInt32 *dataSize, UInt32 *propType); + + HRESULT GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value); + HRESULT GetTime(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, FILETIME &ft); public: - MY_UNKNOWN_IMP1(IOutArchive) + CHandler(); + MY_UNKNOWN_IMP6( + IInArchive, + IArchiveGetRawProps, + IArchiveGetRootProps, + IArchiveKeepModeForNextOpen, + ISetProperties, + IOutArchive) + INTERFACE_IInArchive(;) + INTERFACE_IArchiveGetRawProps(;) + INTERFACE_IArchiveGetRootProps(;) + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); + STDMETHOD(KeepModeForNextOpen)(); INTERFACE_IOutArchive(;) }; diff --git a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp index 85f0771c..149989d1 100755..100644 --- a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp +++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp @@ -2,17 +2,23 @@ #include "StdAfx.h" +// #include <stdio.h> + #include "../../../../C/CpuArch.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringToInt.h" +#include "../../../Common/UTFConvert.h" +#include "../../../Common/Wildcard.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" #include "../../Common/LimitedStreams.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamUtils.h" +#include "../../Common/UniqBlocks.h" #include "../../Crypto/RandGen.h" #include "../../Crypto/Sha1.h" @@ -24,125 +30,218 @@ using namespace NWindows; namespace NArchive { namespace NWim { +static const Int32 kNumImagesMax = (1 << 10); + struct CSha1Hash { Byte Hash[kHashSize]; }; -struct CHashList +class CHashList { + CUIntVector Sorted; +public: CRecordVector<CSha1Hash> Digests; - CIntVector Sorted; - int AddUnique(const CSha1Hash &h); + int AddUniq(const Byte *h); }; -int CHashList::AddUnique(const CSha1Hash &h) +// returns -1 : if it's new HASH + +int CHashList::AddUniq(const Byte *h) { - int left = 0, right = Sorted.Size(); + unsigned left = 0, right = Sorted.Size(); while (left != right) { - int mid = (left + right) / 2; - int index = Sorted[mid]; - UInt32 i; + unsigned mid = (left + right) / 2; + unsigned index = Sorted[mid]; const Byte *hash2 = Digests[index].Hash; + unsigned i; for (i = 0; i < kHashSize; i++) - if (h.Hash[i] != hash2[i]) + if (h[i] != hash2[i]) break; if (i == kHashSize) return index; - if (h.Hash[i] < hash2[i]) + if (h[i] < hash2[i]) right = mid; else left = mid + 1; } - Sorted.Insert(left, Digests.Add(h)); + CSha1Hash h2; + memcpy(h2.Hash, h, kHashSize); + Sorted.Insert(left, Digests.Add(h2)); return -1; } -struct CUpdateItem +struct CAltStream { + int UpdateIndex; + int HashIndex; + UInt64 Size; UString Name; + bool Skip; + + CAltStream(): UpdateIndex(-1), HashIndex(-1), Skip(false) {} +}; + +struct CMetaItem +{ + int UpdateIndex; + int HashIndex; + UInt64 Size; FILETIME CTime; FILETIME ATime; FILETIME MTime; UInt32 Attrib; + UInt64 FileID; + UInt64 VolID; + + UString Name; + UString ShortName; + + int SecurityId; // -1: means no secutity ID bool IsDir; - int HashIndex; + bool Skip; + unsigned NumSkipAltStreams; + CObjectVector<CAltStream> AltStreams; + + CByteBuffer Reparse; - CUpdateItem(): HashIndex(-1) {} + unsigned GetNumAltStreams() const { return AltStreams.Size() - NumSkipAltStreams; } + CMetaItem(): UpdateIndex(-1), HashIndex(-1), SecurityId(-1), + FileID(0), VolID(0), + Skip(false), NumSkipAltStreams(0) {} +}; + +static int Compare_HardLink_MetaItems(const CMetaItem &a1, const CMetaItem &a2) +{ + if (a1.VolID < a2.VolID) return -1; + if (a1.VolID > a2.VolID) return 1; + if (a1.FileID < a2.FileID) return -1; + if (a1.FileID > a2.FileID) return 1; + if (a1.Size < a2.Size) return -1; + if (a1.Size > a2.Size) return 1; + return ::CompareFileTime(&a1.MTime, &a2.MTime); +} + +static int AddToHardLinkList(const CObjectVector<CMetaItem> &metaItems, unsigned indexOfItem, CUIntVector &indexes) +{ + const CMetaItem &mi = metaItems[indexOfItem]; + unsigned left = 0, right = indexes.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + unsigned index = indexes[mid]; + int comp = Compare_HardLink_MetaItems(mi, metaItems[index]); + if (comp == 0) + return index; + if (comp < 0) + right = mid; + else + left = mid + 1; + } + indexes.Insert(left, indexOfItem); + return -1; +} + +struct CUpdateItem +{ + unsigned CallbackIndex; // index in callback + + int MetaIndex; // index in in MetaItems[] + + int AltStreamIndex; // index in CMetaItem::AltStreams vector + // -1: if not alt stream? + + int InArcIndex; // >= 0, if we use OLD Data + // -1, if we use NEW Data + + CUpdateItem(): MetaIndex(-1), AltStreamIndex(-1), InArcIndex(-1) {} }; struct CDir { - int Index; - UString Name; + int MetaIndex; CObjectVector<CDir> Dirs; - CIntVector Files; - - CDir(): Index(-1) {} - bool IsLeaf() const { return Index >= 0; } - UInt64 GetNumDirs() const; - UInt64 GetNumFiles() const; - CDir* AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index); + CUIntVector Files; // indexes in MetaItems[] + + CDir(): MetaIndex(-1) {} + unsigned GetNumDirs() const; + unsigned GetNumFiles() const; + UInt64 GetTotalSize(const CObjectVector<CMetaItem> &metaItems) const; + bool FindDir(const CObjectVector<CMetaItem> &items, const UString &name, unsigned &index); }; -UInt64 CDir::GetNumDirs() const +/* imagex counts Junctions as files (not as dirs). + We suppose that it's not correct */ + +unsigned CDir::GetNumDirs() const { - UInt64 num = Dirs.Size(); - for (int i = 0; i < Dirs.Size(); i++) + unsigned num = Dirs.Size(); + FOR_VECTOR (i, Dirs) num += Dirs[i].GetNumDirs(); return num; } -UInt64 CDir::GetNumFiles() const +unsigned CDir::GetNumFiles() const { - UInt64 num = Files.Size(); - for (int i = 0; i < Dirs.Size(); i++) + unsigned num = Files.Size(); + FOR_VECTOR (i, Dirs) num += Dirs[i].GetNumFiles(); return num; } -CDir* CDir::AddDir(CObjectVector<CUpdateItem> &items, const UString &name, int index) +UInt64 CDir::GetTotalSize(const CObjectVector<CMetaItem> &metaItems) const { - int left = 0, right = Dirs.Size(); + UInt64 sum = 0; + unsigned i; + for (i = 0; i < Files.Size(); i++) + sum += metaItems[Files[i]].Size; + for (i = 0; i < Dirs.Size(); i++) + sum += Dirs[i].GetTotalSize(metaItems); + return sum; +} + +bool CDir::FindDir(const CObjectVector<CMetaItem> &items, const UString &name, unsigned &index) +{ + unsigned left = 0, right = Dirs.Size(); while (left != right) { - int mid = (left + right) / 2; - CDir &d = Dirs[mid]; - int compare = name.CompareNoCase(d.IsLeaf() ? items[Dirs[mid].Index].Name : d.Name); - if (compare == 0) + unsigned mid = (left + right) / 2; + int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name); + if (comp == 0) { - if (index >= 0) - d.Index = index; - return &d; + index = mid; + return true; } - if (compare < 0) + if (comp < 0) right = mid; else left = mid + 1; } - Dirs.Insert(left, CDir()); - CDir &d = Dirs[left]; - d.Index = index; - if (index < 0) - d.Name = name; - return &d; + index = left; + return false; } - -STDMETHODIMP COutHandler::GetFileTimeType(UInt32 *type) +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) { *type = NFileTimeType::kWindows; return S_OK; } -static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propID, FILETIME &ft) +HRESULT CHandler::GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value) +{ + if (arcIndex >= 0) + return GetProperty(arcIndex, propID, value); + return callback->GetProperty(callbackIndex, propID, value); +} + +HRESULT CHandler::GetTime(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, FILETIME &ft) { ft.dwLowDateTime = ft.dwHighDateTime = 0; NCOM::CPropVariant prop; - RINOK(callback->GetProperty(index, propID, &prop)); + RINOK(GetOutProperty(callback, callbackIndex, arcIndex, propID, &prop)); if (prop.vt == VT_FILETIME) ft = prop.filetime; else if (prop.vt != VT_EMPTY) @@ -150,6 +249,37 @@ static HRESULT GetTime(IArchiveUpdateCallback *callback, int index, PROPID propI return S_OK; } +static HRESULT GetRootTime( + IArchiveGetRootProps *callback, + IArchiveGetRootProps *arcRoot, + PROPID propID, FILETIME &ft) +{ + NCOM::CPropVariant prop; + if (callback) + { + RINOK(callback->GetRootProp(propID, &prop)); + if (prop.vt == VT_FILETIME) + { + ft = prop.filetime; + return S_OK; + } + if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + if (arcRoot) + { + RINOK(arcRoot->GetRootProp(propID, &prop)); + if (prop.vt == VT_FILETIME) + { + ft = prop.filetime; + return S_OK; + } + if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + return S_OK; +} + #define Set16(p, d) SetUi16(p, d) #define Set32(p, d) SetUi32(p, d) #define Set64(p, d) SetUi64(p, d) @@ -217,7 +347,7 @@ STDMETHODIMP CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedS HRESULT result = _stream->Read(data, size, &realProcessedSize); _size += realProcessedSize; _sha.Update((const Byte *)data, realProcessedSize); - if (processedSize != NULL) + if (processedSize) *processedSize = realProcessedSize; return result; } @@ -228,116 +358,301 @@ static void SetFileTimeToMem(Byte *p, const FILETIME &ft) Set32(p + 4, ft.dwHighDateTime); } -static size_t WriteItem(const CUpdateItem &item, Byte *p, const Byte *hash) +static size_t WriteItem_Dummy(const CMetaItem &item) { - int fileNameLen = item.Name.Length() * 2; - int fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); + if (item.Skip) + return 0; + unsigned fileNameLen = item.Name.Len() * 2; + // we write fileNameLen + 2 + 2 to be same as original WIM. + unsigned fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2); + + unsigned shortNameLen = item.ShortName.Len() * 2; + unsigned shortNameLen2 = (shortNameLen == 0 ? 2 : shortNameLen + 4); - size_t totalLen = ((kDirRecordSize + fileNameLen2 + 6) & ~7); - if (p) + size_t totalLen = ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7); + if (item.GetNumAltStreams() != 0) { - memset(p, 0, totalLen); - Set64(p, totalLen); - Set64(p + 8, item.Attrib); - Set32(p + 0xC, (UInt32)(Int32)-1); // item.SecurityId - // Set64(p + 0x10, 0); // subdirOffset - SetFileTimeToMem(p + 0x28, item.CTime); - SetFileTimeToMem(p + 0x30, item.ATime); - SetFileTimeToMem(p + 0x38, item.MTime); - if (hash) - memcpy(p + 0x40, hash, kHashSize); - /* - else - memset(p + 0x40, 0, kHashSize); - */ - // Set16(p + 98, 0); // shortNameLen - Set16(p + 100, (UInt16)fileNameLen); - for (int i = 0; i * 2 < fileNameLen; i++) - Set16(p + kDirRecordSize + i * 2, item.Name[i]); + if (!item.IsDir) + { + UInt32 curLen = (((0x26 + 0) + 6) & ~7); + totalLen += curLen; + } + FOR_VECTOR (i, item.AltStreams) + { + const CAltStream &ss = item.AltStreams[i]; + if (ss.Skip) + continue; + fileNameLen = ss.Name.Len() * 2; + fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2 + 2); + UInt32 curLen = (((0x26 + fileNameLen2) + 6) & ~7); + totalLen += curLen; + } } return totalLen; } -static void WriteTree(const CDir &tree, CRecordVector<CSha1Hash> &digests, - CUpdateItem &defaultDirItem, - CObjectVector<CUpdateItem> &updateItems, Byte *dest, size_t &pos) +static size_t WriteItem(const CRecordVector<CSha1Hash> &digests, const CMetaItem &item, Byte *p) { - int i; - for (i = 0; i < tree.Files.Size(); i++) + if (item.Skip) + return 0; + unsigned fileNameLen = item.Name.Len() * 2; + unsigned fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2); + unsigned shortNameLen = item.ShortName.Len() * 2; + unsigned shortNameLen2 = (shortNameLen == 0 ? 2 : shortNameLen + 4); + + size_t totalLen = ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7); + + memset(p, 0, totalLen); + Set64(p, totalLen); + Set64(p + 8, item.Attrib); + Set32(p + 0xC, (Int32)item.SecurityId); + SetFileTimeToMem(p + 0x28, item.CTime); + SetFileTimeToMem(p + 0x30, item.ATime); + SetFileTimeToMem(p + 0x38, item.MTime); + + /* WIM format probably doesn't support hard links to symbolic links. + In these cases it just stores symbolic links (REPARSE TAGS). + Check it in new versions of WIM software form MS !!! + We also follow that scheme */ + + if (item.Reparse.Size() != 0) + { + UInt32 tag = GetUi32(item.Reparse); + Set32(p + 0x58, tag); + // Set32(p + 0x5C, 0); // probably it's always ZERO + } + else if (item.FileID != 0) { - const CUpdateItem &ui = updateItems[tree.Files[i]]; - pos += WriteItem(ui, dest ? dest + pos : NULL, - ui.HashIndex >= 0 ? digests[ui.HashIndex].Hash : NULL); + Set64(p + 0x58, item.FileID); + } + + Set16(p + 0x62, (UInt16)shortNameLen); + Set16(p + 0x64, (UInt16)fileNameLen); + unsigned i; + for (i = 0; i * 2 < fileNameLen; i++) + Set16(p + kDirRecordSize + i * 2, item.Name[i]); + for (i = 0; i * 2 < shortNameLen; i++) + Set16(p + kDirRecordSize + fileNameLen2 + i * 2, item.ShortName[i]); + + if (item.GetNumAltStreams() == 0) + { + if (item.HashIndex >= 0) + memcpy(p + 0x40, digests[item.HashIndex].Hash, kHashSize); + } + else + { + Set16(p + 0x60, (UInt16)(item.GetNumAltStreams() + (item.IsDir ? 0 : 1))); + p += totalLen; + + if (!item.IsDir) + { + UInt32 curLen = (((0x26 + 0) + 6) & ~7); + memset(p, 0, curLen); + Set64(p, curLen); + if (item.HashIndex >= 0) + memcpy(p + 0x10, digests[item.HashIndex].Hash, kHashSize); + totalLen += curLen; + p += curLen; + } + + FOR_VECTOR (si, item.AltStreams) + { + const CAltStream &ss = item.AltStreams[si]; + if (ss.Skip) + continue; + + fileNameLen = ss.Name.Len() * 2; + fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2 + 2); + UInt32 curLen = (((0x26 + fileNameLen2) + 6) & ~7); + memset(p, 0, curLen); + + Set64(p, curLen); + if (ss.HashIndex >= 0) + memcpy(p + 0x10, digests[ss.HashIndex].Hash, kHashSize); + Set16(p + 0x24, (UInt16)fileNameLen); + for (i = 0; i * 2 < fileNameLen; i++) + Set16(p + 0x26 + i * 2, ss.Name[i]); + totalLen += curLen; + p += curLen; + } } + + return totalLen; +} - size_t posStart = pos; +struct CDb +{ + CMetaItem DefaultDirItem; + const CRecordVector<CSha1Hash> *Hashes; + CObjectVector<CMetaItem> MetaItems; + CRecordVector<CUpdateItem> UpdateItems; + CUIntVector UpdateIndexes; /* indexes in UpdateItems in order of writing data streams + to disk (the order of tree items). */ + + size_t WriteTree_Dummy(const CDir &tree) const; + void WriteTree(const CDir &tree, Byte *dest, size_t &pos) const; + void WriteOrderList(const CDir &tree); +}; + +size_t CDb::WriteTree_Dummy(const CDir &tree) const +{ + unsigned i; + size_t pos = 0; + for (i = 0; i < tree.Files.Size(); i++) + pos += WriteItem_Dummy(MetaItems[tree.Files[i]]); for (i = 0; i < tree.Dirs.Size(); i++) { - const CDir &subfolder = tree.Dirs[i]; - CUpdateItem *item = &defaultDirItem; - if (subfolder.IsLeaf()) - item = &updateItems[subfolder.Index]; - else - defaultDirItem.Name = subfolder.Name; - pos += WriteItem(*item, NULL, NULL); + const CDir &subDir = tree.Dirs[i]; + pos += WriteItem_Dummy(MetaItems[subDir.MetaIndex]); + pos += WriteTree_Dummy(subDir); } + return pos + 8; +} + +void CDb::WriteTree(const CDir &tree, Byte *dest, size_t &pos) const +{ + unsigned i; + for (i = 0; i < tree.Files.Size(); i++) + pos += WriteItem(*Hashes, MetaItems[tree.Files[i]], dest + pos); - if (dest) - Set64(dest + pos, 0); + size_t posStart = pos; + for (i = 0; i < tree.Dirs.Size(); i++) + pos += WriteItem_Dummy(MetaItems[tree.Dirs[i].MetaIndex]); + + Set64(dest + pos, 0); pos += 8; for (i = 0; i < tree.Dirs.Size(); i++) { - const CDir &subfolder = tree.Dirs[i]; - if (dest) + const CDir &subDir = tree.Dirs[i]; + const CMetaItem &metaItem = MetaItems[subDir.MetaIndex]; + bool needCreateTree = (metaItem.Reparse.Size() == 0) + || !subDir.Files.IsEmpty() + || !subDir.Dirs.IsEmpty(); + size_t len = WriteItem(*Hashes, metaItem, dest + posStart); + posStart += len; + if (needCreateTree) { - CUpdateItem *item = &defaultDirItem; - if (subfolder.IsLeaf()) - item = &updateItems[subfolder.Index]; - else - defaultDirItem.Name = subfolder.Name; - size_t len = WriteItem(*item, dest + posStart, NULL); - Set64(dest + posStart + 0x10, pos); - posStart += len; + Set64(dest + posStart - len + 0x10, pos); // subdirOffset + WriteTree(subDir, dest, pos); } - WriteTree(subfolder, digests, defaultDirItem, updateItems, dest, pos); } } -static void AddTag(AString &s, const char *name, const AString &value) +void CDb::WriteOrderList(const CDir &tree) { - s += "<"; + if (tree.MetaIndex >= 0) + { + const CMetaItem &mi = MetaItems[tree.MetaIndex]; + if (mi.UpdateIndex >= 0) + UpdateIndexes.Add(mi.UpdateIndex); + FOR_VECTOR (si, mi.AltStreams) + UpdateIndexes.Add(mi.AltStreams[si].UpdateIndex); + } + + unsigned i; + for (i = 0; i < tree.Files.Size(); i++) + { + const CMetaItem &mi = MetaItems[tree.Files[i]]; + UpdateIndexes.Add(mi.UpdateIndex); + FOR_VECTOR (si, mi.AltStreams) + UpdateIndexes.Add(mi.AltStreams[si].UpdateIndex); + } + + for (i = 0; i < tree.Dirs.Size(); i++) + WriteOrderList(tree.Dirs[i]); +} + +static void AddTag_ToString(AString &s, const char *name, const char *value) +{ + s += '<'; s += name; - s += ">"; + s += '>'; s += value; - s += "</"; + s += '<'; + s += '/'; s += name; - s += ">"; + s += '>'; +} + +static void AddTagUInt64_ToString(AString &s, const char *name, UInt64 value) +{ + char temp[32]; + ConvertUInt64ToString(value, temp); + AddTag_ToString(s, name, temp); } -static void AddTagUInt64(AString &s, const char *name, UInt64 value) +static CXmlItem &AddUniqueTag(CXmlItem &parentItem, const char *name) { + int index = parentItem.FindSubTag(name); + if (index < 0) + { + CXmlItem &subItem = parentItem.SubItems.AddNew(); + subItem.IsTag = true; + subItem.Name = name; + return subItem; + } + CXmlItem &subItem = parentItem.SubItems[index]; + subItem.SubItems.Clear(); + return subItem; +} + +static void AddTag_UInt64_2(CXmlItem &item, UInt64 value) +{ + CXmlItem &subItem = item.SubItems.AddNew(); + subItem.IsTag = false; char temp[32]; ConvertUInt64ToString(value, temp); - AddTag(s, name, temp); + subItem.Name = temp; +} + +static void AddTag_UInt64(CXmlItem &parentItem, const char *name, UInt64 value) +{ + AddTag_UInt64_2(AddUniqueTag(parentItem, name), value); +} + +static void AddTag_Hex(CXmlItem &item, const char *name, UInt32 value) +{ + item.IsTag = true; + item.Name = name; + char temp[16]; + temp[0] = '0'; + temp[1] = 'x'; + ConvertUInt32ToHex8Digits(value, temp + 2); + CXmlItem &subItem = item.SubItems.AddNew(); + subItem.IsTag = false; + subItem.Name = temp; +} + +static void AddTag_Time_2(CXmlItem &item, const FILETIME &ft) +{ + AddTag_Hex(item.SubItems.AddNew(), "HIGHPART", ft.dwHighDateTime); + AddTag_Hex(item.SubItems.AddNew(), "LOWPART", ft.dwLowDateTime); +} + +static void AddTag_Time(CXmlItem &parentItem, const char *name, const FILETIME &ft) +{ + AddTag_Time_2(AddUniqueTag(parentItem, name), ft); } -static AString TimeToXml(FILETIME &ft) +static void AddTag_String_IfEmpty(CXmlItem &parentItem, const char *name, const char *value) { - AString res; - char temp[16] = { '0', 'x' }; - ConvertUInt32ToHexWithZeros(ft.dwHighDateTime, temp + 2); - AddTag(res, "HIGHPART", temp); - ConvertUInt32ToHexWithZeros(ft.dwLowDateTime, temp + 2); - AddTag(res, "LOWPART", temp); - return res; + int index = parentItem.FindSubTag(name); + if (index >= 0) + return; + CXmlItem &tag = parentItem.SubItems.AddNew(); + tag.IsTag = true; + tag.Name = name; + CXmlItem &subItem = tag.SubItems.AddNew(); + subItem.IsTag = false; + subItem.Name = value; } void CHeader::SetDefaultFields(bool useLZX) { Version = kWimVersion; - Flags = NHeaderFlags::kRpFix; + Flags = NHeaderFlags::kReparsePointFixup; ChunkSize = 0; if (useLZX) { @@ -355,24 +670,607 @@ void CHeader::SetDefaultFields(bool useLZX) IntegrityResource.Clear(); } -static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream, - CDir &rootFolder, - CObjectVector<CUpdateItem> &updateItems, - IArchiveUpdateCallback *callback) +static void AddTrees(CObjectVector<CDir> &trees, CObjectVector<CMetaItem> &metaItems, const CMetaItem &ri, int curTreeIndex) { + while (curTreeIndex >= (int)trees.Size()) + trees.AddNew().Dirs.AddNew().MetaIndex = metaItems.Add(ri); +} + +STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 numItems, IArchiveUpdateCallback *callback) +{ + COM_TRY_BEGIN + + if (ThereIsError()) + return E_NOTIMPL; + + bool isUpdate = (_volumes.Size() != 0); + int defaultImageIndex = _defaultImageNumber - 1; + bool showImageNumber; + + if (isUpdate) + { + showImageNumber = _showImageNumber; + if (_version != kWimVersion) + return E_NOTIMPL; + if (_volumes.Size() != 2 || _volumes[0].Stream) + return E_NOTIMPL; + if (!showImageNumber) + defaultImageIndex = _db.IndexOfUserImage; + if (_db.Images.Size() > kNumImagesMax) + return E_NOTIMPL; + } + else + { + showImageNumber = (_set_use_ShowImageNumber && _set_showImageNumber); + if (!showImageNumber) + defaultImageIndex = 0; + } + + if (defaultImageIndex >= kNumImagesMax) + return E_NOTIMPL; + CMyComPtr<IOutStream> outStream; - RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream)); + RINOK(outSeqStream->QueryInterface(IID_IOutStream, (void **)&outStream)); if (!outStream) return E_NOTIMPL; + if (!callback) + return E_FAIL; + + CDb db; + CObjectVector<CDir> trees; + + CMetaItem ri; // default DIR item + FILETIME ftCur; + NTime::GetCurUtcFileTime(ftCur); + ri.MTime = ri.ATime = ri.CTime = ftCur; + ri.Attrib = FILE_ATTRIBUTE_DIRECTORY; + ri.IsDir = true; + + + // ---------- Detect changed images ---------- + + unsigned i; + CBoolVector isChangedImage; + { + CUIntVector numUnchangedItemsInImage; + for (i = 0; i < _db.Images.Size(); i++) + { + numUnchangedItemsInImage.Add(0); + isChangedImage.Add(false); + } + + for (i = 0; i < numItems; i++) + { + UInt32 indexInArchive; + Int32 newData, newProps; + RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); + if (newProps == 0) + { + if (indexInArchive >= _db.SortedItems.Size()) + continue; + const CItem &item = _db.Items[_db.SortedItems[indexInArchive]]; + if (newData == 0) + { + if (item.ImageIndex >= 0) + numUnchangedItemsInImage[item.ImageIndex]++; + } + else + { + // oldProps & newData. Current version of 7-Zip doesn't use it + if (item.ImageIndex >= 0) + isChangedImage[item.ImageIndex] = true; + } + } + else if (!showImageNumber) + { + if (defaultImageIndex >= 0 && defaultImageIndex < (int)isChangedImage.Size()) + isChangedImage[defaultImageIndex] = true; + } + else + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidPath, &prop)); + + if (prop.vt != VT_BSTR) + return E_INVALIDARG; + const wchar_t *path = prop.bstrVal; + if (!path) + return E_INVALIDARG; + + const wchar_t *end; + UInt64 val = ConvertStringToUInt64(path, &end); + if (end == path) + return E_INVALIDARG; + if (val == 0 || val > kNumImagesMax) + return E_INVALIDARG; + wchar_t c = *end; + if (c != 0 && c != ':' && c != L'/' && c != WCHAR_PATH_SEPARATOR) + return E_INVALIDARG; + unsigned imageIndex = (unsigned)val - 1; + if (imageIndex < _db.Images.Size()) + isChangedImage[imageIndex] = true; + if (_defaultImageNumber > 0 && val != _defaultImageNumber) + return E_INVALIDARG; + } + } + + for (i = 0; i < _db.Images.Size(); i++) + if (!isChangedImage[i]) + isChangedImage[i] = _db.GetNumUserItemsInImage(i) != numUnchangedItemsInImage[i]; + } + + if (defaultImageIndex >= 0) + { + for (i = 0; i < _db.Images.Size(); i++) + if ((int)i != defaultImageIndex) + isChangedImage[i] = false; + } + + CMyComPtr<IArchiveGetRawProps> getRawProps; + callback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps); + + CMyComPtr<IArchiveGetRootProps> getRootProps; + callback->QueryInterface(IID_IArchiveGetRootProps, (void **)&getRootProps); + + CObjectVector<CUniqBlocks> secureBlocks; + + if (!showImageNumber && (getRootProps || isUpdate) && + ( + defaultImageIndex >= (int)isChangedImage.Size() + || defaultImageIndex < 0 // test it + || isChangedImage[defaultImageIndex] + )) + { + // Fill Root Item: Metadata and security + CMetaItem rootItem = ri; + { + const void *data = NULL; + UInt32 dataSize = 0; + UInt32 propType = 0; + if (getRootProps) + { + RINOK(getRootProps->GetRootRawProp(kpidNtSecure, &data, &dataSize, &propType)); + } + if (dataSize == 0 && isUpdate) + { + RINOK(GetRootRawProp(kpidNtSecure, &data, &dataSize, &propType)); + } + if (dataSize != 0) + { + if (propType != NPropDataType::kRaw) + return E_FAIL; + while (defaultImageIndex >= (int)secureBlocks.Size()) + secureBlocks.AddNew(); + CUniqBlocks &secUniqBlocks = secureBlocks[defaultImageIndex]; + rootItem.SecurityId = secUniqBlocks.AddUniq((const Byte *)data, dataSize); + } + } + + IArchiveGetRootProps *thisGetRoot = isUpdate ? this : NULL; + + RINOK(GetRootTime(getRootProps, thisGetRoot, kpidCTime, rootItem.CTime)); + RINOK(GetRootTime(getRootProps, thisGetRoot, kpidATime, rootItem.ATime)); + RINOK(GetRootTime(getRootProps, thisGetRoot, kpidMTime, rootItem.MTime)); + + { + NCOM::CPropVariant prop; + if (getRootProps) + { + RINOK(getRootProps->GetRootProp(kpidAttrib, &prop)); + if (prop.vt == VT_UI4) + rootItem.Attrib = prop.ulVal; + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + if (prop.vt == VT_EMPTY && thisGetRoot) + { + RINOK(GetRootProp(kpidAttrib, &prop)); + if (prop.vt == VT_UI4) + rootItem.Attrib = prop.ulVal; + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + rootItem.Attrib |= FILE_ATTRIBUTE_DIRECTORY; + } + + AddTrees(trees, db.MetaItems, ri, defaultImageIndex); + db.MetaItems[trees[defaultImageIndex].Dirs[0].MetaIndex] = rootItem; + } + + // ---------- Request Metadata for changed items ---------- + + UString fileName; + + for (i = 0; i < numItems; i++) + { + CUpdateItem ui; + UInt32 indexInArchive; + Int32 newData, newProps; + RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); + if (newData == 0 || newProps == 0) + { + if (indexInArchive >= _db.SortedItems.Size()) + continue; + + const CItem &item = _db.Items[_db.SortedItems[indexInArchive]]; + + if (item.ImageIndex >= 0) + { + if (!isChangedImage[item.ImageIndex]) + { + if (newData == 0 && newProps == 0) + continue; + return E_FAIL; + } + } + else + { + // if deleted item was not renamed, we just skip it + if (newProps == 0) + continue; + } + if (newData == 0) + ui.InArcIndex = indexInArchive; + } + + // we set arcIndex only if we must use old props + Int32 arcIndex = (newProps ? -1 : indexInArchive); + + bool isDir = false; + { + NCOM::CPropVariant prop; + RINOK(GetOutProperty(callback, i, arcIndex, kpidIsDir, &prop)); + if (prop.vt == VT_BOOL) + isDir = (prop.boolVal != VARIANT_FALSE); + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + + bool isAltStream = false; + { + NCOM::CPropVariant prop; + RINOK(GetOutProperty(callback, i, arcIndex, kpidIsAltStream, &prop)); + if (prop.vt == VT_BOOL) + isAltStream = (prop.boolVal != VARIANT_FALSE); + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + + if (isDir && isAltStream) + return E_INVALIDARG; + + UInt64 size = 0; + UInt64 iNode = 0; + + if (!isDir) + { + if (!newData) + { + NCOM::CPropVariant prop; + GetProperty(indexInArchive, kpidINode, &prop); + if (prop.vt == VT_UI8) + iNode = prop.uhVal.QuadPart; + } + + NCOM::CPropVariant prop; + if (newData) + { + RINOK(callback->GetProperty(i, kpidSize, &prop)); + } + else + { + RINOK(GetProperty(indexInArchive, kpidSize, &prop)); + } + if (prop.vt == VT_UI8) + size = prop.uhVal.QuadPart; + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + + { + NCOM::CPropVariant propPath; + const wchar_t *path = NULL; + RINOK(GetOutProperty(callback, i, arcIndex, kpidPath, &propPath)); + if (propPath.vt == VT_BSTR) + path = propPath.bstrVal; + else if (propPath.vt != VT_EMPTY) + return E_INVALIDARG; + + if (!path) + return E_INVALIDARG; + + CDir *curItem = NULL; + bool isRootImageDir = false; + fileName.Empty(); + + int imageIndex; + + if (!showImageNumber) + { + imageIndex = defaultImageIndex; + AddTrees(trees, db.MetaItems, ri, imageIndex); + curItem = &trees[imageIndex].Dirs[0]; + } + else + { + const wchar_t *end; + UInt64 val = ConvertStringToUInt64(path, &end); + if (end == path) + return E_INVALIDARG; + if (val == 0 || val > kNumImagesMax) + return E_INVALIDARG; + + imageIndex = (int)val - 1; + if (imageIndex < (int)isChangedImage.Size()) + if (!isChangedImage[imageIndex]) + return E_FAIL; + + AddTrees(trees, db.MetaItems, ri, imageIndex); + curItem = &trees[imageIndex].Dirs[0]; + wchar_t c = *end; + + if (c == 0) + { + if (!isDir || isAltStream) + return E_INVALIDARG; + ui.MetaIndex = curItem->MetaIndex; + isRootImageDir = true; + } + else if (c == ':') + { + if (isDir || !isAltStream) + return E_INVALIDARG; + ui.MetaIndex = curItem->MetaIndex; + CAltStream ss; + ss.Size = size; + ss.Name = end + 1; + ss.UpdateIndex = db.UpdateItems.Size(); + ui.AltStreamIndex = db.MetaItems[ui.MetaIndex].AltStreams.Add(ss); + } + else if (c == WCHAR_PATH_SEPARATOR || c == L'/') + { + path = end + 1; + if (*path == 0) + return E_INVALIDARG; + } + else + return E_INVALIDARG; + } + + if (ui.MetaIndex < 0) + { + for (;;) + { + wchar_t c = *path++; + if (c == 0) + break; + if (c == WCHAR_PATH_SEPARATOR || c == L'/') + { + unsigned indexOfDir; + if (!curItem->FindDir(db.MetaItems, fileName, indexOfDir)) + { + CDir &dir = curItem->Dirs.InsertNew(indexOfDir); + dir.MetaIndex = db.MetaItems.Add(ri); + db.MetaItems.Back().Name = fileName; + } + curItem = &curItem->Dirs[indexOfDir]; + fileName.Empty(); + } + else + fileName += c; + } + + if (isAltStream) + { + int colonPos = fileName.Find(L':'); + if (colonPos < 0) + return E_INVALIDARG; + const UString mainName = fileName.Left(colonPos); + unsigned indexOfDir; + if (curItem->FindDir(db.MetaItems, mainName, indexOfDir)) + ui.MetaIndex = curItem->Dirs[indexOfDir].MetaIndex; + else + { + for (int j = (int)curItem->Files.Size() - 1; j >= 0; j--) + { + int metaIndex = curItem->Files[j]; + const CMetaItem &mi = db.MetaItems[metaIndex]; + if (CompareFileNames(mainName, mi.Name) == 0) + { + ui.MetaIndex = metaIndex; + break; + } + } + } + if (ui.MetaIndex >= 0) + { + CAltStream ss; + ss.Size = size; + ss.Name = fileName.Ptr(colonPos + 1); + ss.UpdateIndex = db.UpdateItems.Size(); + ui.AltStreamIndex = db.MetaItems[ui.MetaIndex].AltStreams.Add(ss); + } + } + } + + + if (ui.MetaIndex < 0 || isRootImageDir) + { + if (!isRootImageDir) + { + ui.MetaIndex = db.MetaItems.Size(); + db.MetaItems.AddNew(); + } + CMetaItem &mi = db.MetaItems[ui.MetaIndex]; + mi.Size = size; + mi.IsDir = isDir; + mi.Name = fileName; + mi.UpdateIndex = db.UpdateItems.Size(); + { + NCOM::CPropVariant prop; + RINOK(GetOutProperty(callback, i, arcIndex, kpidAttrib, &prop)); + if (prop.vt == VT_EMPTY) + mi.Attrib = 0; + else if (prop.vt == VT_UI4) + mi.Attrib = prop.ulVal; + else + return E_INVALIDARG; + if (isDir) + mi.Attrib |= FILE_ATTRIBUTE_DIRECTORY; + } + RINOK(GetTime(callback, i, arcIndex, kpidCTime, mi.CTime)); + RINOK(GetTime(callback, i, arcIndex, kpidATime, mi.ATime)); + RINOK(GetTime(callback, i, arcIndex, kpidMTime, mi.MTime)); + + { + NCOM::CPropVariant prop; + RINOK(GetOutProperty(callback, i, arcIndex, kpidShortName, &prop)); + if (prop.vt == VT_BSTR) + mi.ShortName = prop.bstrVal; + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + + while (imageIndex >= (int)secureBlocks.Size()) + secureBlocks.AddNew(); + + if (!isAltStream && (getRawProps || arcIndex >= 0)) + { + CUniqBlocks &secUniqBlocks = secureBlocks[imageIndex]; + const void *data; + UInt32 dataSize; + UInt32 propType; + + data = NULL; + dataSize = 0; + propType = 0; + + if (arcIndex >= 0) + { + GetRawProp(arcIndex, kpidNtSecure, &data, &dataSize, &propType); + } + else + { + getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType); + } + if (dataSize != 0) + { + if (propType != NPropDataType::kRaw) + return E_FAIL; + mi.SecurityId = secUniqBlocks.AddUniq((const Byte *)data, dataSize); + } + + data = NULL; + dataSize = 0; + propType = 0; + if (arcIndex >= 0) + { + GetRawProp(arcIndex, kpidNtReparse, &data, &dataSize, &propType); + } + else + { + getRawProps->GetRawProp(i, kpidNtReparse, &data, &dataSize, &propType); + } + if (dataSize != 0) + { + if (propType != NPropDataType::kRaw) + return E_FAIL; + mi.Reparse.CopyFrom((const Byte *)data, dataSize); + } + } + + if (!isRootImageDir) + { + if (isDir) + { + unsigned indexOfDir; + if (curItem->FindDir(db.MetaItems, fileName, indexOfDir)) + curItem->Dirs[indexOfDir].MetaIndex = ui.MetaIndex; + else + curItem->Dirs.InsertNew(indexOfDir).MetaIndex = ui.MetaIndex; + } + else + curItem->Files.Add(ui.MetaIndex); + } + } + + } + + if (iNode != 0 && ui.MetaIndex >= 0 && ui.AltStreamIndex < 0) + db.MetaItems[ui.MetaIndex].FileID = iNode; + + ui.CallbackIndex = i; + db.UpdateItems.Add(ui); + } + + unsigned numNewImages = trees.Size(); + for (i = numNewImages; i < isChangedImage.Size(); i++) + if (!isChangedImage[i]) + numNewImages = i + 1; + + AddTrees(trees, db.MetaItems, ri, numNewImages - 1); + + for (i = 0; i < trees.Size(); i++) + if (i >= isChangedImage.Size() || isChangedImage[i]) + db.WriteOrderList(trees[i]); + UInt64 complexity = 0; - int i; - for (i = 0; i < updateItems.Size(); i++) - complexity += updateItems[i].Size; + unsigned numDataStreams = _db.DataStreams.Size(); + CIntArr streamsRefs(numDataStreams); + for (i = 0; i < numDataStreams; i++) + streamsRefs[i] = 0; + + // ---------- Calculate Streams Refs Counts in unchanged images + for (i = 0; i < _db.Images.Size(); i++) + { + if (isChangedImage[i]) + continue; + complexity += _db.MetaStreams[i].Resource.PackSize; + const CImage &image = _db.Images[i]; + unsigned endItem = image.StartItem + image.NumItems; + for (unsigned k = image.StartItem; k < endItem; k++) + { + const CItem &item = _db.Items[k]; + if (item.StreamIndex >= 0) + streamsRefs[item.StreamIndex]++; + } + } + + // ---------- Update Streams Refs Counts in changed images + + for (i = 0; i < db.UpdateIndexes.Size(); i++) + { + const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]]; + if (ui.InArcIndex >= 0) + { + if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size()) + continue; + const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]]; + if (item.StreamIndex >= 0) + streamsRefs[item.StreamIndex]++; + } + else + { + const CMetaItem &mi = db.MetaItems[ui.MetaIndex]; + UInt64 size; + if (ui.AltStreamIndex < 0) + size = mi.Size; + else + size = mi.AltStreams[ui.AltStreamIndex].Size; + complexity += size; + } + } + + for (i = 0; i < _db.DataStreams.Size(); i++) + if (streamsRefs[i] != 0) + complexity += _db.DataStreams[i].Resource.PackSize; + RINOK(callback->SetTotal(complexity)); + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; @@ -382,44 +1280,233 @@ static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream, complexity = 0; - bool useCompression = false; + // bool useResourceCompression = false; + // use useResourceCompression only if CHeader::Flags compression is also set CHeader header; - header.SetDefaultFields(useCompression); + header.SetDefaultFields(false); + + if (isUpdate) + { + const CHeader &srcHeader = _volumes[1].Header; + header.Flags = srcHeader.Flags; + header.ChunkSize = srcHeader.ChunkSize; + } + Byte buf[kHeaderSizeMax]; header.WriteTo(buf); RINOK(WriteStream(outStream, buf, kHeaderSizeMax)); + UInt64 curPos = kHeaderSizeMax; + + CInStreamWithSha1 *inShaStreamSpec = new CInStreamWithSha1; + CMyComPtr<ISequentialInStream> inShaStream = inShaStreamSpec; + + CLimitedSequentialInStream *inStreamLimitedSpec = NULL; + CMyComPtr<CLimitedSequentialInStream> inStreamLimited; + if (_volumes.Size() == 2) + { + inStreamLimitedSpec = new CLimitedSequentialInStream; + inStreamLimited = inStreamLimitedSpec; + inStreamLimitedSpec->SetStream(_volumes[1].Stream); + } + + + // these two lists have same sizes and same hashes in same order. CHashList hashes; CObjectVector<CStreamInfo> streams; - UInt64 curPos = kHeaderSizeMax; - UInt64 unpackTotalSize = 0; - for (i = 0; i < updateItems.Size(); i++) + + // ---------- Copy unchanged data streams ---------- + + for (i = 0; i < _db.DataStreams.Size(); i++) + { + if (streamsRefs[i] == 0) + continue; + + lps->InSize = lps->OutSize = complexity; + RINOK(lps->SetCur()); + + const CStreamInfo &siOld = _db.DataStreams[i]; + if (hashes.AddUniq(siOld.Hash) >= 0) + return E_FAIL; // two streams with same SHA-1 + + RINOK(_volumes[siOld.PartNumber].Stream->Seek(siOld.Resource.Offset, STREAM_SEEK_SET, NULL)); + inStreamLimitedSpec->Init(siOld.Resource.PackSize); + RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize != siOld.Resource.PackSize) + return E_FAIL; + + CStreamInfo &s = streams.AddNew(); + s.Resource = siOld.Resource; + s.Resource.Offset = curPos; + s.PartNumber = 1; + s.RefCount = streamsRefs[i]; + memcpy(s.Hash, siOld.Hash, kHashSize); + + curPos += s.Resource.PackSize; + lps->ProgressOffset += s.Resource.PackSize; + } + + + // ---------- Write new items ---------- + + CUIntVector hlIndexes; // sorted indexes for hard link items + + for (i = 0; i < db.UpdateIndexes.Size(); i++) { lps->InSize = lps->OutSize = complexity; RINOK(lps->SetCur()); - CUpdateItem &ui = updateItems[i]; - if (ui.IsDir || ui.Size == 0) - continue; + const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]]; + CMetaItem &mi = db.MetaItems[ui.MetaIndex]; + UInt64 size = 0; + + if (ui.AltStreamIndex >= 0) + { + if (mi.Skip) + continue; + size = mi.AltStreams[ui.AltStreamIndex].Size; + } + else + { + size = mi.Size; + if (mi.IsDir) + { + // we support LINK files here + if (mi.Reparse.Size() == 0) + continue; + } + } - CInStreamWithSha1 *inShaStreamSpec = new CInStreamWithSha1; - CMyComPtr<ISequentialInStream> inShaStream = inShaStreamSpec; + if (ui.InArcIndex >= 0) + { + // data streams with OLD Data were written already + // we just need to find HashIndex in hashes. + if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size()) + return E_FAIL; + const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]]; + if (item.StreamIndex < 0) + { + if (size == 0) + continue; + // if (_db.ItemHasStream(item)) + return E_FAIL; + } + + // We support empty file (size = 0, but with stream and SHA-1) from old archive + + const CStreamInfo &siOld = _db.DataStreams[item.StreamIndex]; + // we must have written that stream already + int index = hashes.AddUniq(siOld.Hash); + if (index < 0) + return E_FAIL; + if (ui.AltStreamIndex < 0) + mi.HashIndex = index; + else + mi.AltStreams[ui.AltStreamIndex].HashIndex = index; + continue; + } + + CMyComPtr<ISequentialInStream> fileInStream; + HRESULT res = callback->GetStream(ui.CallbackIndex, &fileInStream); + if (res == S_FALSE) { - CMyComPtr<ISequentialInStream> fileInStream; - HRESULT res = callback->GetStream(i, &fileInStream); - if (res != S_FALSE) + if (ui.AltStreamIndex >= 0) + { + mi.NumSkipAltStreams++; + mi.AltStreams[ui.AltStreamIndex].Skip = true; + } + else + mi.Skip = true; + } + else + { + RINOK(res); + + int miIndex = -1; + + if (!fileInStream) + { + if (!mi.IsDir) + return E_INVALIDARG; + } + else if (ui.AltStreamIndex < 0) + { + CMyComPtr<IStreamGetProps2> getProps2; + fileInStream->QueryInterface(IID_IStreamGetProps2, (void **)&getProps2); + if (getProps2) + { + CStreamFileProps props; + if (getProps2->GetProps2(&props) == S_OK) + { + mi.Attrib = props.Attrib; + mi.Size = props.Size; + size = props.Size; + mi.CTime = props.CTime; + mi.ATime = props.ATime; + mi.MTime = props.MTime; + mi.FileID = props.FileID_Low; + if (props.NumLinks <= 1) + mi.FileID = 0; + mi.VolID = props.VolID; + if (mi.FileID != 0) + miIndex = AddToHardLinkList(db.MetaItems, ui.MetaIndex, hlIndexes); + } + } + } + + if (miIndex >= 0) + { + mi.HashIndex = db.MetaItems[miIndex].HashIndex; + if (mi.HashIndex >= 0) + streams[mi.HashIndex].RefCount++; + // fix for future: maybe we need to check also that real size is equal to size from IStreamGetProps2 + } + else if (ui.AltStreamIndex < 0 && mi.Reparse.Size() != 0) + { + if (mi.Reparse.Size() < 8) + return E_FAIL; + NCrypto::NSha1::CContext sha1; + sha1.Init(); + size_t packSize = mi.Reparse.Size() - 8; + sha1.Update((const Byte *)mi.Reparse + 8, packSize); + Byte hash[kHashSize]; + sha1.Final(hash); + int index = hashes.AddUniq(hash); + if (index >= 0) + streams[index].RefCount++; + else + { + RINOK(WriteStream(outStream, (const Byte *)mi.Reparse + 8, packSize)); + index = streams.Size(); + CStreamInfo &s = streams.AddNew(); + s.Resource.PackSize = packSize; + s.Resource.Offset = curPos; + s.Resource.UnpackSize = packSize; + s.Resource.Flags = 0; // check it + /* + if (useResourceCompression) + s.Resource.Flags = NResourceFlags::Compressed; + */ + s.PartNumber = 1; + s.RefCount = 1; + memcpy(s.Hash, hash, kHashSize); + curPos += packSize; + } + mi.HashIndex = index; + } + else { - RINOK(res); inShaStreamSpec->SetStream(fileInStream); fileInStream.Release(); inShaStreamSpec->Init(); UInt64 offsetBlockSize = 0; - if (useCompression) + /* + if (useResourceCompression) { - for (UInt64 t = kChunkSize; t < ui.Size; t += kChunkSize) + for (UInt64 t = kChunkSize; t < size; t += kChunkSize) { Byte buf[8]; SetUi32(buf, (UInt32)t); @@ -427,94 +1514,180 @@ static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream, offsetBlockSize += 4; } } - + */ + RINOK(copyCoder->Code(inShaStream, outStream, NULL, NULL, progress)); - ui.Size = copyCoderSpec->TotalSize; - - CSha1Hash hash; - unpackTotalSize += ui.Size; - UInt64 packSize = offsetBlockSize + ui.Size; - inShaStreamSpec->Final(hash.Hash); - int index = hashes.AddUnique(hash); - if (index >= 0) - { - ui.HashIndex = index; - streams[index].RefCount++; - outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos); - outStream->SetSize(curPos); - } - else + size = copyCoderSpec->TotalSize; + + if (size != 0) { - ui.HashIndex = hashes.Digests.Size() - 1; - CStreamInfo s; - s.Resource.PackSize = packSize; - s.Resource.Offset = curPos; - s.Resource.UnpackSize = ui.Size; - s.Resource.Flags = 0; - if (useCompression) + Byte hash[kHashSize]; + UInt64 packSize = offsetBlockSize + size; + inShaStreamSpec->Final(hash); + int index = hashes.AddUniq(hash); + + if (index >= 0) + { + streams[index].RefCount++; + outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos); + outStream->SetSize(curPos); + } + else + { + index = streams.Size(); + CStreamInfo &s = streams.AddNew(); + s.Resource.PackSize = packSize; + s.Resource.Offset = curPos; + s.Resource.UnpackSize = size; + s.Resource.Flags = 0; + /* + if (useResourceCompression) s.Resource.Flags = NResourceFlags::Compressed; - s.PartNumber = 1; - s.RefCount = 1; - memcpy(s.Hash, hash.Hash, kHashSize); - streams.Add(s); - curPos += packSize; + */ + s.PartNumber = 1; + s.RefCount = 1; + memcpy(s.Hash, hash, kHashSize); + curPos += packSize; + } + + if (ui.AltStreamIndex < 0) + mi.HashIndex = index; + else + mi.AltStreams[ui.AltStreamIndex].HashIndex = index; } } - fileInStream.Release(); - complexity += ui.Size; - RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } + fileInStream.Release(); + complexity += size; + RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } - lps->InSize = lps->OutSize = complexity; - RINOK(lps->SetCur()); - CUpdateItem ri; - FILETIME ft; - NTime::GetCurUtcFileTime(ft); - ri.MTime = ri.ATime = ri.CTime = ft; - ri.Attrib = FILE_ATTRIBUTE_DIRECTORY; + while (secureBlocks.Size() < numNewImages) + secureBlocks.AddNew(); - const UInt32 kSecuritySize = 8; - size_t pos = kSecuritySize; - WriteTree(rootFolder, hashes.Digests, ri, updateItems, NULL, pos); - - CByteBuffer meta; - meta.SetCapacity(pos); - // we can write 0 here only if there is no security data, imageX does it, - // but some programs expect size = 8 - Set32((Byte *)meta, 8); // size of security data - Set32((Byte *)meta + 4, 0); // num security entries - pos = kSecuritySize; - WriteTree(rootFolder, hashes.Digests, ri, updateItems, (Byte *)meta, pos); + // ---------- Write Images ---------- + for (i = 0; i < numNewImages; i++) { - NCrypto::NSha1::CContext sha; - sha.Init(); - sha.Update((const Byte *)meta, pos); - CSha1Hash digest; - sha.Final(digest.Hash); + lps->InSize = lps->OutSize = complexity; + RINOK(lps->SetCur()); + if (i < isChangedImage.Size() && !isChangedImage[i]) + { + CStreamInfo s = _db.MetaStreams[i]; + + RINOK(_volumes[1].Stream->Seek(s.Resource.Offset, STREAM_SEEK_SET, NULL)); + inStreamLimitedSpec->Init(s.Resource.PackSize); + RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize != s.Resource.PackSize) + return E_FAIL; + + s.Resource.Offset = curPos; + s.PartNumber = 1; + s.RefCount = 1; + streams.Add(s); + + if (_bootIndex != 0 && _bootIndex == (UInt32)i + 1) + { + header.MetadataResource = s.Resource; + header.BootIndex = _bootIndex; + } - CStreamInfo s; - s.Resource.PackSize = pos; - s.Resource.Offset = curPos; - s.Resource.UnpackSize = pos; - s.Resource.Flags = NResourceFlags::kMetadata; - s.PartNumber = 1; - s.RefCount = 1; - memcpy(s.Hash, digest.Hash, kHashSize); - streams.Add(s); - RINOK(WriteStream(outStream, (const Byte *)meta, pos)); - meta.Free(); - curPos += pos; + lps->ProgressOffset += s.Resource.PackSize; + curPos += s.Resource.PackSize; + // printf("\nWrite old image %x\n", i + 1); + continue; + } + + const CDir &tree = trees[i]; + const UInt32 kSecuritySize = 8; + + size_t pos = kSecuritySize; + + const CUniqBlocks &secUniqBlocks = secureBlocks[i]; + const CObjectVector<CByteBuffer> &secBufs = secUniqBlocks.Bufs; + pos += (size_t)secUniqBlocks.GetTotalSizeInBytes(); + pos += secBufs.Size() * 8; + pos = (pos + 7) & ~(size_t)7; + + db.DefaultDirItem = ri; + pos += db.WriteTree_Dummy(tree); + + CByteBuffer meta(pos); + + Set32((Byte *)meta + 4, secBufs.Size()); // num security entries + pos = kSecuritySize; + + if (secBufs.Size() == 0) + { + // we can write 0 here only if there is no security data, imageX does it, + // but some programs expect size = 8 + Set32((Byte *)meta, 8); // size of security data + // Set32((Byte *)meta, 0); + } + else + { + unsigned i; + for (i = 0; i < secBufs.Size(); i++, pos += 8) + { + Set64(meta + pos, secBufs[i].Size()); + } + for (i = 0; i < secBufs.Size(); i++) + { + const CByteBuffer &buf = secBufs[i]; + size_t size = buf.Size(); + memcpy(meta + pos, buf, size); + pos += size; + } + while ((pos & 7) != 0) + meta[pos++] = 0; + Set32((Byte *)meta, (UInt32)pos); // size of security data + } + + db.Hashes = &hashes.Digests; + db.WriteTree(tree, (Byte *)meta, pos); + + { + NCrypto::NSha1::CContext sha; + sha.Init(); + sha.Update((const Byte *)meta, pos); + CSha1Hash digest; + sha.Final(digest.Hash); + + CStreamInfo s; + s.Resource.PackSize = pos; + s.Resource.Offset = curPos; + s.Resource.UnpackSize = pos; + s.Resource.Flags = NResourceFlags::kMetadata; + s.PartNumber = 1; + s.RefCount = 1; + memcpy(s.Hash, digest.Hash, kHashSize); + streams.Add(s); + + if (_bootIndex != 0 && _bootIndex == (UInt32)i + 1) + { + header.MetadataResource = s.Resource; + header.BootIndex = _bootIndex; + } + + RINOK(WriteStream(outStream, (const Byte *)meta, pos)); + meta.Free(); + curPos += pos; + } } + lps->InSize = lps->OutSize = complexity; + RINOK(lps->SetCur()); header.OffsetResource.UnpackSize = header.OffsetResource.PackSize = (UInt64)streams.Size() * kStreamInfoSize; header.OffsetResource.Offset = curPos; header.OffsetResource.Flags = NResourceFlags::kMetadata; + + + // ---------- Write Streams Info Tables ---------- + for (i = 0; i < streams.Size(); i++) { Byte buf[kStreamInfoSize]; @@ -524,116 +1697,70 @@ static HRESULT UpdateArchive(ISequentialOutStream *seqOutStream, } AString xml = "<WIM>"; - AddTagUInt64(xml, "TOTALBYTES", curPos); - xml += "<IMAGE INDEX=\"1\"><NAME>1</NAME>"; - AddTagUInt64(xml, "DIRCOUNT", rootFolder.GetNumDirs()); - AddTagUInt64(xml, "FILECOUNT", rootFolder.GetNumFiles()); - AddTagUInt64(xml, "TOTALBYTES", unpackTotalSize); - NTime::GetCurUtcFileTime(ft); - AddTag(xml, "CREATIONTIME", TimeToXml(ft)); - AddTag(xml, "LASTMODIFICATIONTIME", TimeToXml(ft)); - xml += "</IMAGE></WIM>"; - - size_t xmlSize = (xml.Length() + 1) * 2; - meta.SetCapacity(xmlSize); - Set16((Byte *)meta, 0xFEFF); - for (i = 0; i < xml.Length(); i++) - Set16((Byte *)meta + 2 + i * 2, xml[i]); - RINOK(WriteStream(outStream, (const Byte *)meta, xmlSize)); - meta.Free(); - - header.XmlResource.UnpackSize = header.XmlResource.PackSize = xmlSize; - header.XmlResource.Offset = curPos; - header.XmlResource.Flags = NResourceFlags::kMetadata; - - outStream->Seek(0, STREAM_SEEK_SET, NULL); - header.WriteTo(buf); - return WriteStream(outStream, buf, kHeaderSizeMax); -} - -STDMETHODIMP COutHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *callback) -{ - COM_TRY_BEGIN - CObjectVector<CUpdateItem> updateItems; - CDir tree; - tree.Dirs.Add(CDir()); - CDir &rootFolder = tree.Dirs.Back(); - - for (UInt32 i = 0; i < numItems; i++) + AddTagUInt64_ToString(xml, "TOTALBYTES", curPos); + for (i = 0; i < trees.Size(); i++) { - CUpdateItem ui; - Int32 newData, newProps; - UInt32 indexInArchive; - if (!callback) - return E_FAIL; - RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); + CDir &tree = trees[i]; + CXmlItem item; + if (_xmls.Size() == 1) { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidIsDir, &prop)); - if (prop.vt == VT_EMPTY) - ui.IsDir = false; - else if (prop.vt != VT_BOOL) - return E_INVALIDARG; - else - ui.IsDir = (prop.boolVal != VARIANT_FALSE); - } - - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidAttrib, &prop)); - if (prop.vt == VT_EMPTY) - ui.Attrib = (ui.IsDir ? FILE_ATTRIBUTE_DIRECTORY : 0); - else if (prop.vt != VT_UI4) - return E_INVALIDARG; - else - ui.Attrib = prop.ulVal; - } - - RINOK(GetTime(callback, i, kpidCTime, ui.CTime)); - RINOK(GetTime(callback, i, kpidATime, ui.ATime)); - RINOK(GetTime(callback, i, kpidMTime, ui.MTime)); - - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidSize, &prop)); - if (prop.vt != VT_UI8) - return E_INVALIDARG; - ui.Size = prop.uhVal.QuadPart; + const CWimXml &_oldXml = _xmls[0]; + if ((int)i < _oldXml.Images.Size()) + { + // int ttt = _oldXml.Images[i].ItemIndexInXml; + item = _oldXml.Xml.Root.SubItems[_oldXml.Images[i].ItemIndexInXml]; + } } - - UString path; - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidPath, &prop)); - if (prop.vt == VT_BSTR) - path = prop.bstrVal; - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - - CDir *curItem = &rootFolder; - int len = path.Length(); - UString fileName; - for (int j = 0; j < len; j++) + if (i >= isChangedImage.Size() || isChangedImage[i]) { - wchar_t c = path[j]; - if (c == WCHAR_PATH_SEPARATOR || c == L'/') + char temp[16]; + if (item.Name.IsEmpty()) { - curItem = curItem->AddDir(updateItems, fileName, -1); - fileName.Empty(); + ConvertUInt32ToString(i + 1, temp); + item.Name = "IMAGE"; + item.IsTag = true; + CXmlProp &prop = item.Props.AddNew(); + prop.Name = "INDEX"; + prop.Value = temp; } - else - fileName += c; + + AddTag_String_IfEmpty(item, "NAME", temp); + AddTag_UInt64(item, "DIRCOUNT", tree.GetNumDirs() - 1); + AddTag_UInt64(item, "FILECOUNT", tree.GetNumFiles()); + AddTag_UInt64(item, "TOTALBYTES", tree.GetTotalSize(db.MetaItems)); + + AddTag_Time(item, "CREATIONTIME", ftCur); + AddTag_Time(item, "LASTMODIFICATIONTIME", ftCur); } - ui.Name = fileName; - updateItems.Add(ui); - if (ui.IsDir) - curItem->AddDir(updateItems, fileName, (int)i); - else - curItem->Files.Add(i); + item.AppendTo(xml); } - return UpdateArchive(outStream, tree, updateItems, callback); + xml += "</WIM>"; + + size_t xmlSize; + { + UString utf16String; + if (!ConvertUTF8ToUnicode(xml, utf16String)) + return S_FALSE; + xmlSize = (utf16String.Len() + 1) * 2; + + CByteBuffer xmlBuf(xmlSize); + Set16((Byte *)xmlBuf, 0xFEFF); + for (i = 0; i < (unsigned)utf16String.Len(); i++) + Set16((Byte *)xmlBuf + 2 + i * 2, utf16String[i]); + RINOK(WriteStream(outStream, (const Byte *)xmlBuf, xmlSize)); + } + + header.XmlResource.UnpackSize = header.XmlResource.PackSize = xmlSize; + header.XmlResource.Offset = curPos; + header.XmlResource.Flags = NResourceFlags::kMetadata; + + outStream->Seek(0, STREAM_SEEK_SET, NULL); + header.NumImages = trees.Size(); + header.WriteTo(buf); + return WriteStream(outStream, buf, kHeaderSizeMax); + COM_TRY_END } diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp index c210804d..cec037cc 100755..100644 --- a/CPP/7zip/Archive/Wim/WimIn.cpp +++ b/CPP/7zip/Archive/Wim/WimIn.cpp @@ -2,13 +2,17 @@ #include "StdAfx.h" +// #include <stdio.h> + #include "../../../../C/CpuArch.h" -#include "Common/IntToString.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringToInt.h" +#include "../../../Common/UTFConvert.h" -#include "../../Common/StreamUtils.h" -#include "../../Common/StreamObjects.h" #include "../../Common/LimitedStreams.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" #include "../Common/OutStreamWithSha1.h" @@ -33,7 +37,6 @@ public: { if (NeedFlush) m_Decoder->Flush(); - m_Decoder->ReleaseStreams(); } }; @@ -44,8 +47,8 @@ HRESULT CDecoder::CodeSpec(UInt32 outSize) for (unsigned i = 0; i < kMainTableSize; i += 2) { Byte b = m_InBitStream.DirectReadByte(); - levels[i] = b & 0xF; - levels[i + 1] = b >> 4; + levels[i] = (Byte)(b & 0xF); + levels[i + 1] = (Byte)(b >> 4); } if (!m_MainDecoder.SetCodeLengths(levels)) return S_FALSE; @@ -154,11 +157,7 @@ HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool l size_t sizesBufSize = (size_t)sizesBufSize64; if (sizesBufSize != sizesBufSize64) return E_OUTOFMEMORY; - if (sizesBufSize > sizesBuf.GetCapacity()) - { - sizesBuf.Free(); - sizesBuf.SetCapacity(sizesBufSize); - } + sizesBuf.AllocAtLeast(sizesBufSize); RINOK(ReadStream_FALSE(inStream, (Byte *)sizesBuf, sizesBufSize)); const Byte *p = (const Byte *)sizesBuf; @@ -237,8 +236,7 @@ static HRESULT UnpackData(IInStream *inStream, const CResource &resource, bool l size_t size = (size_t)resource.UnpackSize; if (size != resource.UnpackSize) return E_OUTOFMEMORY; - buf.Free(); - buf.SetCapacity(size); + buf.Alloc(size); CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream(); CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; @@ -256,7 +254,7 @@ void CResource::Parse(const Byte *p) UnpackSize = Get64(p + 16); } -#define GetResource(p, res) res.Parse(p) +#define GET_RESOURCE(_p_, res) res.ParseAndUpdatePhySize(_p_, phySize) static void GetStream(bool oldVersion, const Byte *p, CStreamInfo &s) { @@ -265,111 +263,151 @@ static void GetStream(bool oldVersion, const Byte *p, CStreamInfo &s) { s.PartNumber = 1; s.Id = Get32(p + 24); - s.RefCount = Get32(p + 28); - memcpy(s.Hash, p + 32, kHashSize); + // printf("\n%d", s.Id); + p += 28; } else { s.PartNumber = Get16(p + 24); - s.RefCount = Get32(p + 26); - memcpy(s.Hash, p + 30, kHashSize); + p += 26; } + s.RefCount = Get32(p); + memcpy(s.Hash, p + 4, kHashSize); } -static const wchar_t *kLongPath = L"[LongPath]"; -UString CDatabase::GetItemPath(const int index1) const +static const char *kLongPath = "[LongPath]"; + +void CDatabase::GetShortName(unsigned index, NWindows::NCOM::CPropVariant &name) const { - int size = 0; + const CItem &item = Items[index]; + const CImage &image = Images[item.ImageIndex]; + if (item.Parent < 0 && image.NumEmptyRootItems != 0) + { + name.Clear(); + return; + } + const Byte *meta = image.Meta + item.Offset + + (IsOldVersion ? kDirRecordSizeOld : kDirRecordSize); + UInt32 fileNameLen = Get16(meta - 2); + UInt32 shortLen = Get16(meta - 4) / 2; + wchar_t *s = name.AllocBstr(shortLen); + if (fileNameLen != 0) + meta += fileNameLen + 2; + for (UInt32 i = 0; i < shortLen; i++) + s[i] = Get16(meta + i * 2); + s[shortLen] = 0; + // empty shortName has no ZERO at the end ? +} + +void CDatabase::GetItemName(unsigned index, NWindows::NCOM::CPropVariant &name) const +{ + const CItem &item = Items[index]; + const CImage &image = Images[item.ImageIndex]; + if (item.Parent < 0 && image.NumEmptyRootItems != 0) + { + name = image.RootName; + return; + } + const Byte *meta = image.Meta + item.Offset + + (item.IsAltStream ? + (IsOldVersion ? 0x10 : 0x24) : + (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2)); + UInt32 len = Get16(meta) / 2; + wchar_t *s = name.AllocBstr(len); + meta += 2; + len++; + for (UInt32 i = 0; i < len; i++) + s[i] = Get16(meta + i * 2); +} + +void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCOM::CPropVariant &path) const +{ + unsigned size = 0; int index = index1; - int newLevel; - for (newLevel = 0;; newLevel = 1) + unsigned newLevel; + int imageIndex = Items[index].ImageIndex; + const CImage &image = Images[imageIndex]; + for (newLevel = 0;;) { const CItem &item = Items[index]; index = item.Parent; - if (index >= 0 || !SkipRoot) - size += item.Name.Length() + newLevel; + if (index >= 0 || image.NumEmptyRootItems == 0) + { + const Byte *meta = image.Meta + item.Offset; + meta += item.IsAltStream ? + (IsOldVersion ? 0x10 : 0x24) : + (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2); + size += Get16(meta) / 2; + size += newLevel; + newLevel = 1; + if ((UInt32)size >= ((UInt32)1 << 15)) + { + path = kLongPath; + return; + } + } if (index < 0) break; - if ((UInt32)size >= ((UInt32)1 << 16)) - return kLongPath; } - wchar_t temp[16]; - int imageLen = 0; - if (ShowImageNumber) + if (showImageNumber) { - ConvertUInt32ToString(-1 - index, temp); - imageLen = MyStringLen(temp); - size += imageLen + 1; + size += image.RootName.Len(); + size += newLevel; } - if ((UInt32)size >= ((UInt32)1 << 16)) - return kLongPath; - UString path; - wchar_t *s = path.GetBuffer(size); + wchar_t *s = path.AllocBstr(size); s[size] = 0; - if (ShowImageNumber) + + if (showImageNumber) { - memcpy(s, temp, imageLen * sizeof(wchar_t)); - s[imageLen] = WCHAR_PATH_SEPARATOR; + MyStringCopy(s, (const wchar_t *)image.RootName); + if (newLevel) + s[image.RootName.Len()] = WCHAR_PATH_SEPARATOR; } index = index1; - - for (newLevel = 0;; newLevel = 1) + wchar_t separator = 0; + for (;;) { const CItem &item = Items[index]; index = item.Parent; - if (index >= 0 || !SkipRoot) + if (index >= 0 || image.NumEmptyRootItems == 0) { - if (newLevel) - s[--size] = WCHAR_PATH_SEPARATOR; - size -= item.Name.Length(); - memcpy(s + size, item.Name, sizeof(wchar_t) * item.Name.Length()); + if (separator) + s[--size] = separator; + const Byte *meta = image.Meta + item.Offset; + meta += (item.IsAltStream) ? + (IsOldVersion ? 0x10: 0x24) : + (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2); + UInt32 len = Get16(meta) / 2; + size -= len; + wchar_t *dest = s + size; + meta += 2; + for (UInt32 i = 0; i < len; i++) + dest[i] = Get16(meta + i * 2); } if (index < 0) - { - path.ReleaseBuffer(); - return path; - } + return; + separator = item.IsAltStream ? L':' : WCHAR_PATH_SEPARATOR; } } -static void GetFileTimeFromMem(const Byte *p, FILETIME *ft) -{ - ft->dwLowDateTime = Get32(p); - ft->dwHighDateTime = Get32(p + 4); -} - -static HRESULT ReadName(const Byte *p, int size, UString &dest) -{ - if (size == 0) - return S_OK; - if (Get16(p + size) != 0) - return S_FALSE; - wchar_t *s = dest.GetBuffer(size / 2); - for (int i = 0; i <= size; i += 2) - *s++ = Get16(p + i); - dest.ReleaseBuffer(); - return S_OK; -} +// Root folders in OLD archives (ver = 1.10) conatin real items. +// Root folders in NEW archives (ver > 1.11) contain only one folder with empty name. HRESULT CDatabase::ParseDirItem(size_t pos, int parent) { if ((pos & 7) != 0) return S_FALSE; - - int prevIndex = -1; - for (int numItems = 0;; numItems++) + + for (unsigned numItems = 0;; numItems++) { - if (OpenCallback) + if (OpenCallback && (Items.Size() & 0xFFFF) == 0) { UInt64 numFiles = Items.Size(); - if ((numFiles & 0x3FF) == 0) - { - RINOK(OpenCallback->SetCompleted(&numFiles, NULL)); - } + RINOK(OpenCallback->SetCompleted(&numFiles, NULL)); } size_t rem = DirSize - pos; if (pos < DirStartOffset || pos > DirSize || rem < 8) @@ -379,32 +417,93 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) if (len == 0) { if (parent < 0 && numItems != 1) - SkipRoot = false; + Images.Back().NumEmptyRootItems = 0; DirProcessed += 8; return S_OK; } if ((len & 7) != 0 || rem < len) return S_FALSE; - if (!IsOldVersion) - if (len < 0x28) - return S_FALSE; DirProcessed += (size_t)len; if (DirProcessed > DirSize) return S_FALSE; - int extraOffset = 0; - if (IsOldVersion) + + UInt32 dirRecordSize = IsOldVersion ? kDirRecordSizeOld : kDirRecordSize; + if (len < dirRecordSize) + return S_FALSE; + + CItem item; + UInt32 attrib = Get32(p + 8); + item.IsDir = ((attrib & 0x10) != 0); + UInt64 subdirOffset = Get64(p + 0x10); + UInt32 numAltStreams = Get16(p + dirRecordSize - 6); + UInt32 shortNameLen = Get16(p + dirRecordSize - 4); + UInt32 fileNameLen = Get16(p + dirRecordSize - 2); + if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0) + return S_FALSE; + UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2); + UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); + if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) > len) + return S_FALSE; + + p += dirRecordSize; + { - if (len < 0x40 || (/* Get32(p + 12) == 0 && */ Get32(p + 0x14) != 0)) - { - extraOffset = 0x10; - } + if (*(const UInt16 *)(p + fileNameLen) != 0) + return S_FALSE; + for (UInt32 j = 0; j < fileNameLen; j += 2) + if (*(const UInt16 *)(p + j) == 0) + return S_FALSE; + } + if (shortNameLen != 0) + { + // empty shortName has no ZERO at the end ? + const Byte *p2 = p + fileNameLen2; + if (*(const UInt16 *)(p2 + shortNameLen) != 0) + return S_FALSE; + for (UInt32 j = 0; j < shortNameLen; j += 2) + if (*(const UInt16 *)(p2 + j) == 0) + return S_FALSE; } - else if (Get64(p + 8) == 0) - extraOffset = 0x24; - if (extraOffset) + + item.Offset = pos; + item.Parent = parent; + item.ImageIndex = Images.Size() - 1; + unsigned prevIndex = Items.Add(item); + + pos += (size_t)len; + + for (UInt32 i = 0; i < numAltStreams; i++) { - if (prevIndex == -1) + size_t rem = DirSize - pos; + if (pos < DirStartOffset || pos > DirSize || rem < 8) return S_FALSE; + const Byte *p = DirData + pos; + UInt64 len = Get64(p); + if (len == 0) + return S_FALSE; + if ((len & 7) != 0 || rem < len) + return S_FALSE; + if (IsOldVersion) + { + if (len < 0x18) + return S_FALSE; + } + else + if (len < 0x28) + return S_FALSE; + DirProcessed += (size_t)len; + if (DirProcessed > DirSize) + return S_FALSE; + + unsigned extraOffset = 0; + if (IsOldVersion) + extraOffset = 0x10; + else + { + if (Get64(p + 8) != 0) + return S_FALSE; + extraOffset = 0x24; + } UInt32 fileNameLen = Get16(p + extraOffset); if ((fileNameLen & 1) != 0) return S_FALSE; @@ -414,188 +513,137 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) if (((extraOffset + 2 + fileNameLen2 + 6) & ~7) > len) return S_FALSE; - UString name; - RINOK(ReadName(p + extraOffset + 2, fileNameLen, name)); + { + const Byte *p2 = p + extraOffset + 2; + if (*(const UInt16 *)(p2 + fileNameLen) != 0) + return S_FALSE; + for (UInt32 j = 0; j < fileNameLen; j += 2) + if (*(const UInt16 *)(p2 + j) == 0) + return S_FALSE; + } - CItem &prevItem = Items[prevIndex]; - if (name.IsEmpty() && !prevItem.HasStream()) + if (fileNameLen == 0) { + Byte *prevMeta = DirData + item.Offset; if (IsOldVersion) - prevItem.Id = Get32(p + 8); + memcpy(prevMeta + 0x10, p + 8, 4); // It's 32-bit Id else - memcpy(prevItem.Hash, p + 0x10, kHashSize); + memcpy(prevMeta + 0x40, p + 0x10, kHashSize); } else { - CItem item; - item.Name = prevItem.Name + L':' + name; - item.CTime = prevItem.CTime; - item.ATime = prevItem.ATime; - item.MTime = prevItem.MTime; - if (IsOldVersion) - { - item.Id = Get32(p + 8); - memset(item.Hash, 0, kHashSize); - } - else - memcpy(item.Hash, p + 0x10, kHashSize); - item.Attrib = 0; - item.Order = Order++; - item.Parent = parent; - Items.Add(item); + ThereAreAltStreams = true; + CItem item2; + item2.Offset = pos; + item2.IsAltStream = true; + item2.Parent = prevIndex; + item2.ImageIndex = Images.Size() - 1; + Items.Add(item2); } pos += (size_t)len; - continue; } - UInt32 dirRecordSize = IsOldVersion ? kDirRecordSizeOld : kDirRecordSize; - if (len < dirRecordSize) - return S_FALSE; - - CItem item; - item.Attrib = Get32(p + 8); - // item.SecurityId = Get32(p + 0xC); - UInt64 subdirOffset = Get64(p + 0x10); - UInt32 timeOffset = IsOldVersion ? 0x18: 0x28; - GetFileTimeFromMem(p + timeOffset, &item.CTime); - GetFileTimeFromMem(p + timeOffset + 8, &item.ATime); - GetFileTimeFromMem(p + timeOffset + 16, &item.MTime); - if (IsOldVersion) - { - item.Id = Get32(p + 0x10); - memset(item.Hash, 0, kHashSize); - } - else - { - memcpy(item.Hash, p + 0x40, kHashSize); - } - // UInt32 numStreams = Get16(p + dirRecordSize - 6); - UInt32 shortNameLen = Get16(p + dirRecordSize - 4); - UInt32 fileNameLen = Get16(p + dirRecordSize - 2); - - if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0) - return S_FALSE; - - UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2); - UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); - - if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) > len) - return S_FALSE; - p += dirRecordSize; - - RINOK(ReadName(p, fileNameLen, item.Name)); - RINOK(ReadName(p + fileNameLen2, shortNameLen, item.ShortName)); - - if (parent < 0 && (shortNameLen || fileNameLen || !item.IsDir())) - SkipRoot = false; - - /* - // there are some extra data for some files. - p -= dirRecordSize; - p += ((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7); - if (((dirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~7) != len) - p = p; - */ - - /* - if (parent >= 0) + if (parent < 0 && numItems == 0 && shortNameLen == 0 && fileNameLen == 0 && item.IsDir) { - UString s = GetItemPath(parent) + L"\\" + item.Name; - printf("\n%s %8x %S", item.IsDir() ? "D" : " ", (int)subdirOffset, (const wchar_t *)s); + CImage &image = Images.Back(); + image.NumEmptyRootItems = Items.Size() - image.StartItem; } - */ - - if (fileNameLen == 0 && item.IsDir() && !item.HasStream()) - item.Attrib = 0x10; // some swm archives have system/hidden attributes for root - item.Parent = parent; - prevIndex = Items.Add(item); - if (item.IsDir() && subdirOffset != 0) + if (item.IsDir && subdirOffset != 0) { RINOK(ParseDirItem((size_t)subdirOffset, prevIndex)); } - Items[prevIndex].Order = Order++; - pos += (size_t)len; } } -HRESULT CDatabase::ParseImageDirs(const CByteBuffer &buf, int parent) +HRESULT CDatabase::ParseImageDirs(CByteBuffer &buf, int parent) { DirData = buf; - DirSize = buf.GetCapacity(); - - size_t pos = 0; + DirSize = buf.Size(); if (DirSize < 8) return S_FALSE; const Byte *p = DirData; - UInt32 totalLength = Get32(p); + size_t pos = 0; + CImage &image = Images.Back(); + if (IsOldVersion) { - for (pos = 4;; pos += 8) + // there is no specification about that code + UInt32 sum = 0; + image.SecurOffsets.Add(0); + for (;;) { - if (pos + 4 > DirSize) - return S_FALSE; - UInt32 n = Get32(p + pos); - if (n == 0) - break; if (pos + 8 > DirSize) return S_FALSE; - totalLength += Get32(p + pos + 4); - if (totalLength > DirSize) + UInt32 len = Get32(p + pos); + if (len > DirSize - sum) return S_FALSE; + sum += len; + image.SecurOffsets.Add(sum); + UInt32 n = Get32(p + pos + 4); // what does this field mean? + pos += 8; + if (n == 0) + break; } - pos += totalLength + 4; - pos = (pos + 7) & ~(size_t)7; - if (pos > DirSize) + if (sum > DirSize - pos) return S_FALSE; + FOR_VECTOR (i, image.SecurOffsets) + image.SecurOffsets[i] += (UInt32)pos; + pos += sum; + pos = (pos + 7) & ~(size_t)7; } else { - - // UInt32 numEntries = Get32(p + 4); - pos += 8; - { - /* - CRecordVector<UInt64> entryLens; - UInt64 sum = 0; - for (UInt32 i = 0; i < numEntries; i++) + UInt32 totalLen = Get32(p); + if (totalLen == 0) + pos = 8; + else { - if (pos + 8 > DirSize) + if (totalLen < 8) return S_FALSE; - UInt64 len = Get64(p + pos); - entryLens.Add(len); - sum += len; - pos += 8; - } - pos += (size_t)sum; // skip security descriptors - while ((pos & 7) != 0) - pos++; - if (pos != totalLength) - return S_FALSE; - */ - if (totalLength == 0) + UInt32 numEntries = Get32(p + 4); pos = 8; - else if (totalLength < 8) - return S_FALSE; - else - pos = totalLength; - } + if (totalLen > DirSize || numEntries > ((totalLen - 8) >> 3)) + return S_FALSE; + UInt32 sum = (UInt32)pos + numEntries * 8; + image.SecurOffsets.ClearAndReserve(numEntries + 1); + image.SecurOffsets.AddInReserved(sum); + for (UInt32 i = 0; i < numEntries; i++, pos += 8) + { + UInt64 len = Get64(p + pos); + if (len > totalLen - sum) + return S_FALSE; + sum += (UInt32)len; + image.SecurOffsets.AddInReserved(sum); + } + pos = sum; + pos = (pos + 7) & ~(size_t)7; + if (pos != (((size_t)totalLen + 7) & ~(size_t)7)) + return S_FALSE; + } } + + if (pos > DirSize) + return S_FALSE; DirStartOffset = DirProcessed = pos; + image.StartItem = Items.Size(); RINOK(ParseDirItem(pos, parent)); + image.NumItems = Items.Size() - image.StartItem; if (DirProcessed == DirSize) return S_OK; - /* Original program writes additional 8 bytes (END_OF_ROOT_FOLDER), but - reference to that folder is empty */ - if (DirProcessed == DirSize - 8 && DirProcessed - DirStartOffset == 112 && - Get64(p + DirSize - 8) == 0) + /* Original program writes additional 8 bytes (END_OF_ROOT_FOLDER), + but the reference to that folder is empty */ + + // we can't use DirProcessed - DirStartOffset == 112 check if there is alt stream in root + if (DirProcessed == DirSize - 8 && Get64(p + DirSize - 8) == 0) return S_OK; return S_FALSE; } -HRESULT CHeader::Parse(const Byte *p) +HRESULT CHeader::Parse(const Byte *p, UInt64 &phySize) { UInt32 headerSize = Get32(p + 8); + phySize = headerSize; Version = Get32(p + 0x0C); Flags = Get32(p + 0x10); if (!IsSupported()) @@ -603,7 +651,7 @@ HRESULT CHeader::Parse(const Byte *p) ChunkSize = Get32(p + 0x14); if (ChunkSize != kChunkSize && ChunkSize != 0) return S_FALSE; - int offset; + unsigned offset; if (IsOldVersion()) { if (headerSize != 0x60) @@ -627,124 +675,190 @@ HRESULT CHeader::Parse(const Byte *p) offset += 4; } } - GetResource(p + offset, OffsetResource); - GetResource(p + offset + 0x18, XmlResource); - GetResource(p + offset + 0x30, MetadataResource); + GET_RESOURCE(p + offset , OffsetResource); + GET_RESOURCE(p + offset + 0x18, XmlResource); + GET_RESOURCE(p + offset + 0x30, MetadataResource); + BootIndex = 0; if (IsNewVersion()) { if (headerSize < 0xD0) return S_FALSE; - BootIndex = Get32(p + 0x48); - IntegrityResource.Parse(p + offset + 0x4C); + BootIndex = Get32(p + offset + 0x48); + GET_RESOURCE(p + offset + 0x4C, IntegrityResource); } + return S_OK; } const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }; -HRESULT ReadHeader(IInStream *inStream, CHeader &h) +HRESULT ReadHeader(IInStream *inStream, CHeader &h, UInt64 &phySize) { Byte p[kHeaderSizeMax]; RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax)); if (memcmp(p, kSignature, kSignatureSize) != 0) return S_FALSE; - return h.Parse(p); + return h.Parse(p, phySize); } -static HRESULT ReadStreams(bool oldVersion, IInStream *inStream, const CHeader &h, CDatabase &db) +static HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db) { CByteBuffer offsetBuf; RINOK(UnpackData(inStream, h.OffsetResource, h.IsLzxMode(), offsetBuf, NULL)); size_t i; - size_t streamInfoSize = oldVersion ? kStreamInfoSize + 2 : kStreamInfoSize; - for (i = 0; offsetBuf.GetCapacity() - i >= streamInfoSize; i += streamInfoSize) + size_t streamInfoSize = h.IsOldVersion() ? kStreamInfoSize + 2 : kStreamInfoSize; + for (i = 0; offsetBuf.Size() - i >= streamInfoSize; i += streamInfoSize) { CStreamInfo s; - GetStream(oldVersion, (const Byte *)offsetBuf + i, s); + GetStream(h.IsOldVersion(), (const Byte *)offsetBuf + i, s); if (s.PartNumber == h.PartNumber) - db.Streams.Add(s); + { + if (s.Resource.IsMetadata()) + { + if (s.RefCount == 0) + return S_FALSE; + if (s.RefCount > 1) + { + s.RefCount--; + db.DataStreams.Add(s); + } + s.RefCount = 1; + db.MetaStreams.Add(s); + } + else + db.DataStreams.Add(s); + } } - return (i == offsetBuf.GetCapacity()) ? S_OK : S_FALSE; + return (i == offsetBuf.Size()) ? S_OK : S_FALSE; } static bool IsEmptySha(const Byte *data) { - for (int i = 0; i < kHashSize; i++) + for (unsigned i = 0; i < kHashSize; i++) if (data[i] != 0) return false; return true; } -HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback) +HRESULT CDatabase::OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml) +{ + return UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL); +} + +static void SetRootNames(CImage &image, unsigned value) +{ + wchar_t temp[16]; + ConvertUInt32ToString(value, temp); + image.RootName = temp; + image.RootNameBuf.Alloc(image.RootName.Len() * 2 + 2); + Byte *p = image.RootNameBuf; + unsigned len = image.RootName.Len() + 1; + for (unsigned k = 0; k < len; k++) + { + p[k * 2] = (Byte)temp[k]; + p[k * 2 + 1] = 0; + } +} + +HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback) { OpenCallback = openCallback; IsOldVersion = h.IsOldVersion(); - RINOK(UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL)); - RINOK(ReadStreams(h.IsOldVersion(), inStream, h, *this)); + RINOK(ReadStreams(inStream, h, *this)); + + // printf("\nh.PartNumber = %02d", (unsigned)h.PartNumber); bool needBootMetadata = !h.MetadataResource.IsEmpty(); - Order = 0; - if (h.PartNumber == 1) + + FOR_VECTOR (i, MetaStreams) { - int imageIndex = 1; - for (int i = 0; i < Streams.Size(); i++) + const CStreamInfo &si = MetaStreams[i]; + /* + printf("\ni = %5d" + " Refs = %3d" + " Part = %1d" + " Offs = %7X" + " PackSize = %7X" + " Size = %7X" + " Flags = %d " + , + i, + si.RefCount, + (unsigned)si.PartNumber, + (unsigned)si.Resource.Offset, + (unsigned)si.Resource.PackSize, + (unsigned)si.Resource.UnpackSize, + (unsigned)si.Resource.Flags + ); + for (unsigned y = 0; y < 2; y++) + printf("%02X", (unsigned)si.Hash[y]); + */ + + if (h.PartNumber != 1 || si.PartNumber != h.PartNumber) + continue; + + Byte hash[kHashSize]; + CImage &image = Images.AddNew(); + SetRootNames(image, Images.Size()); + CByteBuffer &metadata = image.Meta; + RINOK(UnpackData(inStream, si.Resource, h.IsLzxMode(), metadata, hash)); + if (memcmp(hash, si.Hash, kHashSize) != 0 && + !(h.IsOldVersion() && IsEmptySha(si.Hash))) + return S_FALSE; + image.NumEmptyRootItems = 0; + if (Items.IsEmpty()) + Items.ClearAndReserve(numItemsReserve); + RINOK(ParseImageDirs(metadata, -1)); + if (needBootMetadata) { - // if (imageIndex > 1) break; - const CStreamInfo &si = Streams[i]; - if (!si.Resource.IsMetadata() || si.PartNumber != h.PartNumber) - continue; - Byte hash[kHashSize]; - CByteBuffer metadata; - RINOK(UnpackData(inStream, si.Resource, h.IsLzxMode(), metadata, hash)); - if (memcmp(hash, si.Hash, kHashSize) != 0 && - !(h.IsOldVersion() && IsEmptySha(si.Hash))) - return S_FALSE; - NumImages++; - RINOK(ParseImageDirs(metadata, -(int)(++imageIndex))); - if (needBootMetadata) - if (h.MetadataResource.Offset == si.Resource.Offset) - needBootMetadata = false; + bool sameRes = (h.MetadataResource.Offset == si.Resource.Offset); + if (sameRes) + needBootMetadata = false; + bool isBootIndex = (h.BootIndex == (UInt32)Images.Size()); + if (h.IsNewVersion()) + { + if (sameRes && !isBootIndex) + return S_FALSE; + if (isBootIndex && !sameRes) + return S_FALSE; + } } } if (needBootMetadata) - { - CByteBuffer metadata; - RINOK(UnpackData(inStream, h.MetadataResource, h.IsLzxMode(), metadata, NULL)); - RINOK(ParseImageDirs(metadata, -1)); - NumImages++; - } + return S_FALSE; return S_OK; } +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */) { - int res = MyCompare(p1->PartNumber, p2->PartNumber); - if (res != 0) - return res; - return MyCompare(p1->Resource.Offset, p2->Resource.Offset); + RINOZ(MyCompare(p1->PartNumber, p2->PartNumber)); + RINOZ(MyCompare(p1->Resource.Offset, p2->Resource.Offset)); + return MyCompare(p1->Resource.PackSize, p2->Resource.PackSize); } -static int CompareIDs(const int *p1, const int *p2, void *param) +static int CompareIDs(const unsigned *p1, const unsigned *p2, void *param) { const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param; return MyCompare(streams[*p1].Id, streams[*p2].Id); } -static int CompareHashRefs(const int *p1, const int *p2, void *param) +static int CompareHashRefs(const unsigned *p1, const unsigned *p2, void *param) { const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param; return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize); } static int FindId(const CRecordVector<CStreamInfo> &streams, - const CIntVector &sortedByHash, UInt32 id) + const CUIntVector &sortedByHash, UInt32 id) { - int left = 0, right = streams.Size(); + unsigned left = 0, right = streams.Size(); while (left != right) { - int mid = (left + right) / 2; - int streamIndex = sortedByHash[mid]; + unsigned mid = (left + right) / 2; + unsigned streamIndex = sortedByHash[mid]; UInt32 id2 = streams[streamIndex].Id; if (id == id2) return streamIndex; @@ -757,15 +871,15 @@ static int FindId(const CRecordVector<CStreamInfo> &streams, } static int FindHash(const CRecordVector<CStreamInfo> &streams, - const CIntVector &sortedByHash, const Byte *hash) + const CUIntVector &sortedByHash, const Byte *hash) { - int left = 0, right = streams.Size(); + unsigned left = 0, right = streams.Size(); while (left != right) { - int mid = (left + right) / 2; - int streamIndex = sortedByHash[mid]; - UInt32 i; + unsigned mid = (left + right) / 2; + unsigned streamIndex = sortedByHash[mid]; const Byte *hash2 = streams[streamIndex].Hash; + unsigned i; for (i = 0; i < kHashSize; i++) if (hash[i] != hash2[i]) break; @@ -779,77 +893,424 @@ static int FindHash(const CRecordVector<CStreamInfo> &streams, return -1; } -static int CompareItems(const int *a1, const int *a2, void *param) +bool CDatabase::ItemHasStream(const CItem &item) const { - const CObjectVector<CItem> &items = ((CDatabase *)param)->Items; + if (item.ImageIndex < 0) + return true; + const Byte *meta = Images[item.ImageIndex].Meta + item.Offset; + if (IsOldVersion) + { + // old wim use same field for file_id and dir_offset; + if (item.IsDir) + return false; + meta += (item.IsAltStream ? 0x8 : 0x10); + UInt32 id = GetUi32(meta); + return id != 0; + } + meta += (item.IsAltStream ? 0x10 : 0x40); + for (unsigned i = 0; i < kHashSize; i++) + if (meta[i] != 0) + return true; + return false; +} + +static int CompareItems(const unsigned *a1, const unsigned *a2, void *param) +{ + const CRecordVector<CItem> &items = ((CDatabase *)param)->Items; const CItem &i1 = items[*a1]; const CItem &i2 = items[*a2]; - if (i1.IsDir() != i2.IsDir()) - return i1.IsDir() ? 1 : -1; - int res = MyCompare(i1.StreamIndex, i2.StreamIndex); - if (res != 0) - return res; - return MyCompare(i1.Order, i2.Order); + if (i1.IsDir != i2.IsDir) + return i1.IsDir ? -1 : 1; + if (i1.IsAltStream != i2.IsAltStream) + return i1.IsAltStream ? 1 : -1; + RINOZ(MyCompare(i1.StreamIndex, i2.StreamIndex)); + RINOZ(MyCompare(i1.ImageIndex, i2.ImageIndex)); + return MyCompare(i1.Offset, i2.Offset); } -HRESULT CDatabase::Sort(bool skipRootDir) +HRESULT CDatabase::FillAndCheck() { - Streams.Sort(CompareStreamsByPos, NULL); - { - CIntVector sortedByHash; + DataStreams.Sort(CompareStreamsByPos, NULL); + for (unsigned i = 1; i < DataStreams.Size(); i++) + { + const CStreamInfo &s0 = DataStreams[i - 1]; + const CStreamInfo &s1 = DataStreams[i]; + if (s0.PartNumber == s1.PartNumber) + if (s0.Resource.GetEndLimit() > s1.Resource.Offset) + return S_FALSE; + } + } + + { + CUIntVector sortedByHash; { - for (int i = 0; i < Streams.Size(); i++) - sortedByHash.Add(i); + unsigned num = DataStreams.Size(); + sortedByHash.ClearAndSetSize(num); + unsigned *vals = &sortedByHash[0]; + for (unsigned i = 0; i < num; i++) + vals[i] = i; if (IsOldVersion) - sortedByHash.Sort(CompareIDs, &Streams); + sortedByHash.Sort(CompareIDs, &DataStreams); else - sortedByHash.Sort(CompareHashRefs, &Streams); + sortedByHash.Sort(CompareHashRefs, &DataStreams); } - for (int i = 0; i < Items.Size(); i++) + FOR_VECTOR (i, Items) { CItem &item = Items[i]; item.StreamIndex = -1; - if (item.HasStream()) - if (IsOldVersion) - item.StreamIndex = FindId(Streams, sortedByHash, item.Id); - else - item.StreamIndex = FindHash(Streams, sortedByHash, item.Hash); + const Byte *hash = Images[item.ImageIndex].Meta + item.Offset; + if (IsOldVersion) + { + if (!item.IsDir) + { + hash += (item.IsAltStream ? 0x8 : 0x10); + UInt32 id = GetUi32(hash); + if (id != 0) + item.StreamIndex = FindId(DataStreams, sortedByHash, id); + } + } + /* + else if (item.IsDir) + { + // reparse points can have dirs some dir + } + */ + else + { + hash += (item.IsAltStream ? 0x10 : 0x40); + unsigned hi; + for (hi = 0; hi < kHashSize; hi++) + if (hash[hi] != 0) + break; + if (hi != kHashSize) + { + item.StreamIndex = FindHash(DataStreams, sortedByHash, hash); + } + } } } - { - CRecordVector<bool> used; - int i; - for (i = 0; i < Streams.Size(); i++) + CUIntVector refCounts; + refCounts.ClearAndSetSize(DataStreams.Size()); + unsigned i; + + for (i = 0; i < DataStreams.Size(); i++) { - const CStreamInfo &s = Streams[i]; - used.Add(s.Resource.IsMetadata() && s.PartNumber == 1); - // used.Add(false); + UInt32 startVal = 0; + // const CStreamInfo &s = DataStreams[i]; + /* + if (s.Resource.IsMetadata() && s.PartNumber == 1) + startVal = 1; + */ + refCounts[i] = startVal; } + for (i = 0; i < Items.Size(); i++) { - CItem &item = Items[i]; - if (item.StreamIndex >= 0) - used[item.StreamIndex] = true; + int streamIndex = Items[i].StreamIndex; + if (streamIndex >= 0) + refCounts[streamIndex]++; } - for (i = 0; i < Streams.Size(); i++) - if (!used[i]) + + for (i = 0; i < DataStreams.Size(); i++) + { + const CStreamInfo &s = DataStreams[i]; + if (s.RefCount != refCounts[i]) + { + /* + printf("\ni = %5d si.Refcount = %d realRefs = %d size = %6d offset = %6x id = %4d ", + i, s.RefCount, refCounts[i], (unsigned)s.Resource.UnpackSize, (unsigned)s.Resource.Offset, s.Id); + */ + // return S_FALSE; + RefCountError = true; + } + if (refCounts[i] == 0) { CItem item; + item.Offset = 0; item.StreamIndex = i; - item.HasMetadata = false; + item.ImageIndex = -1; + ThereAreDeletedStreams = true; Items.Add(item); } + } } + return S_OK; +} + +HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber) +{ + SortedItems.Clear(); + VirtualRoots.Clear(); + IndexOfUserImage = imageIndex; + NumExludededItems = 0; + ExludedItem = -1; + + if (Images.Size() != 1 && imageIndex < 0) + showImageNumber = true; + + unsigned startItem = 0; + unsigned endItem = 0; + if (imageIndex < 0) + { + endItem = Items.Size(); + if (Images.Size() == 1) + { + IndexOfUserImage = 0; + const CImage &image = Images[0]; + if (!showImageNumber) + NumExludededItems = image.NumEmptyRootItems; + } + } + else if ((unsigned)imageIndex < Images.Size()) + { + const CImage &image = Images[imageIndex]; + startItem = image.StartItem; + endItem = startItem + image.NumItems; + if (!showImageNumber) + NumExludededItems = image.NumEmptyRootItems; + } + if (NumExludededItems != 0) + { + ExludedItem = startItem; + startItem += NumExludededItems; + } + + unsigned num = endItem - startItem; + SortedItems.ClearAndSetSize(num); + unsigned i; + for (i = 0; i < num; i++) + SortedItems[i] = startItem + i; - SortedItems.Reserve(Items.Size()); - for (int i = (skipRootDir ? 1 : 0); i < Items.Size(); i++) - SortedItems.Add(i); SortedItems.Sort(CompareItems, this); + for (i = 0; i < SortedItems.Size(); i++) + Items[SortedItems[i]].IndexInSorted = i; + + if (showImageNumber) + for (i = 0; i < Images.Size(); i++) + { + CImage &image = Images[i]; + if (image.NumEmptyRootItems != 0) + continue; + image.VirtualRootIndex = VirtualRoots.Size(); + VirtualRoots.Add(i); + } + return S_OK; +} + +static void IntVector_SetMinusOne_IfNeed(CIntVector &v, unsigned size) +{ + if (v.Size() == size) + return; + v.ClearAndSetSize(size); + int *vals = &v[0]; + for (unsigned i = 0; i < size; i++) + vals[i] = -1; +} + +HRESULT CDatabase::ExtractReparseStreams(const CObjectVector<CVolume> &volumes, IArchiveOpenCallback *openCallback) +{ + ItemToReparse.Clear(); + ReparseItems.Clear(); + + // we don't know about Reparse field for OLD WIM format + if (IsOldVersion) + return S_OK; + + CIntVector streamToReparse; + + FOR_VECTOR(i, Items) + { + // maybe it's better to use sorted items for faster access? + const CItem &item = Items[i]; + + if (!item.HasMetadata() || item.IsAltStream) + continue; + + if (item.ImageIndex < 0) + continue; + + const Byte *metadata = Images[item.ImageIndex].Meta + item.Offset; + + const UInt32 attrib = Get32(metadata + 8); + if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0) + continue; + + if (item.StreamIndex < 0) + continue; // it's ERROR + + const CStreamInfo &si = DataStreams[item.StreamIndex]; + if (si.Resource.UnpackSize >= (1 << 16)) + continue; // reparse data can not be larger than 64 KB + + IntVector_SetMinusOne_IfNeed(streamToReparse, DataStreams.Size()); + IntVector_SetMinusOne_IfNeed(ItemToReparse, Items.Size()); + + const unsigned offset = 0x58; // we don't know about Reparse field for OLD WIM format + UInt32 tag = Get32(metadata + offset); + int reparseIndex = streamToReparse[item.StreamIndex]; + CByteBuffer buf; + + if (openCallback && (i & 0xFFFF) == 0) + { + UInt64 numFiles = Items.Size(); + RINOK(openCallback->SetCompleted(&numFiles, NULL)); + } + + if (reparseIndex >= 0) + { + const CByteBuffer &reparse = ReparseItems[reparseIndex]; + if (tag == Get32(reparse)) + { + ItemToReparse[i] = reparseIndex; + continue; + } + buf = reparse; + // we support that strange and unusual situation with different tags and same reparse data. + } + else + { + /* + if (si.PartNumber >= volumes.Size()) + continue; + */ + const CVolume &vol = volumes[si.PartNumber]; + /* + if (!vol.Stream) + continue; + */ + + Byte digest[kHashSize]; + HRESULT res = UnpackData(vol.Stream, si.Resource, vol.Header.IsLzxMode(), buf, digest); + + if (res == S_FALSE) + continue; + + RINOK(res); + + if (memcmp(digest, si.Hash, kHashSize) != 0 + // && !(h.IsOldVersion() && IsEmptySha(si.Hash)) + ) + { + // setErrorStatus; + continue; + } + } + + CByteBuffer &reparse = ReparseItems.AddNew(); + reparse.Alloc(8 + buf.Size()); + Byte *dest = (Byte *)reparse; + SetUi32(dest, tag); + SetUi32(dest + 4, (UInt32)buf.Size()); + memcpy(dest + 8, buf, buf.Size()); + ItemToReparse[i] = ReparseItems.Size() - 1; + } + return S_OK; } + + +static bool ParseNumber64(const AString &s, UInt64 &res) +{ + const char *end; + if (s.IsPrefixedBy("0x")) + { + if (s.Len() == 2) + return false; + res = ConvertHexStringToUInt64(s.Ptr(2), &end); + } + else + { + if (s.IsEmpty()) + return false; + res = ConvertStringToUInt64(s, &end); + } + return *end == 0; +} + +static bool ParseNumber32(const AString &s, UInt32 &res) +{ + UInt64 res64; + if (!ParseNumber64(s, res64) || res64 >= ((UInt64)1 << 32)) + return false; + res = (UInt32)res64; + return true; +} + +static bool ParseTime(const CXmlItem &item, FILETIME &ft, const char *tag) +{ + int index = item.FindSubTag(tag); + if (index >= 0) + { + const CXmlItem &timeItem = item.SubItems[index]; + UInt32 low = 0, high = 0; + if (ParseNumber32(timeItem.GetSubStringForTag("LOWPART"), low) && + ParseNumber32(timeItem.GetSubStringForTag("HIGHPART"), high)) + { + ft.dwLowDateTime = low; + ft.dwHighDateTime = high; + return true; + } + } + return false; +} + +void CImageInfo::Parse(const CXmlItem &item) +{ + CTimeDefined = ParseTime(item, CTime, "CREATIONTIME"); + MTimeDefined = ParseTime(item, MTime, "LASTMODIFICATIONTIME"); + NameDefined = ConvertUTF8ToUnicode(item.GetSubStringForTag("NAME"), Name); + + ParseNumber64(item.GetSubStringForTag("DIRCOUNT"), DirCount); + ParseNumber64(item.GetSubStringForTag("FILECOUNT"), FileCount); + IndexDefined = ParseNumber32(item.GetPropVal("INDEX"), Index); +} + +void CWimXml::ToUnicode(UString &s) +{ + size_t size = Data.Size(); + if (size < 2 || (size & 1) != 0 || size > (1 << 24)) + return; + const Byte *p = Data; + if (Get16(p) != 0xFEFF) + return; + wchar_t *chars = s.GetBuffer((unsigned)size / 2); + for (size_t i = 2; i < size; i += 2) + *chars++ = (wchar_t)Get16(p + i); + *chars = 0; + s.ReleaseBuffer(); +} + +bool CWimXml::Parse() +{ + UString s; + ToUnicode(s); + AString utf; + if (!ConvertUnicodeToUTF8(s, utf)) + return false; + if (!Xml.Parse(utf)) + return false; + if (Xml.Root.Name != "WIM") + return false; + + FOR_VECTOR (i, Xml.Root.SubItems) + { + const CXmlItem &item = Xml.Root.SubItems[i]; + if (item.IsTagged("IMAGE")) + { + CImageInfo imageInfo; + imageInfo.Parse(item); + if (!imageInfo.IndexDefined || imageInfo.Index != (UInt32)Images.Size() + 1) + return false; + imageInfo.ItemIndexInXml = i; + Images.Add(imageInfo); + } + } + return true; +} + }} diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h index da3e28a5..4b7c6d95 100755..100644 --- a/CPP/7zip/Archive/Wim/WimIn.h +++ b/CPP/7zip/Archive/Wim/WimIn.h @@ -3,8 +3,10 @@ #ifndef __ARCHIVE_WIM_IN_H #define __ARCHIVE_WIM_IN_H -#include "Common/Buffer.h" -#include "Common/MyString.h" +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyXml.h" + +#include "../../../Windows/PropVariant.h" #include "../../Compress/CopyCoder.h" #include "../../Compress/LzxDecoder.h" @@ -14,6 +16,104 @@ namespace NArchive { namespace NWim { +const UInt32 kDirRecordSizeOld = 62; +const UInt32 kDirRecordSize = 102; + +/* + There is error in WIM specification about dwReparseTag, dwReparseReserved and liHardLink fields. + + Correct DIRENTRY structure: + { + hex offset + 0 UInt64 Len; + 8 UInt32 Attrib; + C UInt32 SecurityId; + + 10 UInt64 SubdirOffset; // = 0 for files + + 18 UInt64 unused1; // = 0? + 20 UInt64 unused2; // = 0? + + 28 UInt64 CTime; + 30 UInt64 ATime; + 38 UInt64 MTime; + + 40 Byte Sha1[20]; + + 54 UInt32 Unknown1; // is it 0 always? + + + union + { + 58 UInt64 NtNodeId; + { + 58 UInt32 ReparseTag; + 5C UInt32 ReparseFlags; // is it 0 always? Check with new imagex. + } + } + + 60 UInt16 Streams; + + 62 UInt16 ShortNameLen; + 64 UInt16 FileNameLen; + + 66 UInt16 Name[]; + UInt16 ShortName[]; + } + + // DIRENTRY for WIM_VERSION <= 1.10 + DIRENTRY_OLD structure: + { + hex offset + 0 UInt64 Len; + 8 UInt32 Attrib; + C UInt32 SecurityId; + + union + { + 10 UInt64 SubdirOffset; // + + 10 UInt32 OldWimFileId; // used for files in old WIMs + 14 UInt32 OldWimFileId_Reserved; // = 0 + } + + 18 UInt64 CTime; + 20 UInt64 ATime; + 28 UInt64 MTime; + + 30 UInt64 Unknown; // NtNodeId ? + + 38 UInt16 Streams; + 3A UInt16 ShortNameLen; + 3C UInt16 FileNameLen; + 3E UInt16 FileName[]; + UInt16 ShortName[]; + } + + ALT_STREAM structure: + { + hex offset + 0 UInt64 Len; + 8 UInt64 Unused; + 10 Byte Sha1[20]; + 24 UInt16 FileNameLen; + 26 UInt16 FileName[]; + } + + ALT_STREAM_OLD structure: + { + hex offset + 0 UInt64 Len; + 8 UInt64 StreamId; // 32-bit value + 10 UInt16 FileNameLen; + 12 UInt16 FileName[]; + } + + If item is file (not Directory) and there are alternative streams, + there is additional ALT_STREAM item of main "unnamed" stream in Streams array. + +*/ + namespace NXpress { class CBitStream @@ -24,7 +124,6 @@ class CBitStream public: bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); } void SetStream(ISequentialInStream *s) { m_Stream.SetStream(s); } - void ReleaseStream() { m_Stream.ReleaseStream(); } void Init() { m_Stream.Init(); m_BitPos = 0; } // UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - m_BitPos / 8; } @@ -74,11 +173,6 @@ class CDecoder HRESULT CodeSpec(UInt32 size); HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize); public: - void ReleaseStreams() - { - m_OutWindowStream.ReleaseStream(); - m_InBitStream.ReleaseStream(); - } HRESULT Flush() { return m_OutWindowStream.Flush(); } HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize); }; @@ -90,7 +184,7 @@ namespace NResourceFlags const Byte kFree = 1; const Byte kMetadata = 2; const Byte Compressed = 4; - const Byte Spanned = 4; + // const Byte Spanned = 4; } struct CResource @@ -107,7 +201,16 @@ struct CResource UnpackSize = 0; Flags = 0; } + UInt64 GetEndLimit() const { return Offset + PackSize; } void Parse(const Byte *p); + void ParseAndUpdatePhySize(const Byte *p, UInt64 &phySize) + { + Parse(p); + UInt64 v = GetEndLimit(); + if (phySize < v) + phySize = v; + } + void WriteTo(Byte *p) const; bool IsFree() const { return (Flags & NResourceFlags::kFree) != 0; } bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; } @@ -117,16 +220,21 @@ struct CResource namespace NHeaderFlags { - const UInt32 kCompression = 2; - const UInt32 kSpanned = 8; - const UInt32 kRpFix = 0x80; - const UInt32 kXPRESS = 0x20000; - const UInt32 kLZX = 0x40000; + const UInt32 kCompression = 2; + const UInt32 kReadOnly = 4; + const UInt32 kSpanned = 8; + const UInt32 kResourceOnly = 0x10; + const UInt32 kMetadataOnly = 0x20; + const UInt32 kWriteInProgress = 0x40; + const UInt32 kReparsePointFixup = 0x80; + const UInt32 kXPRESS = 0x20000; + const UInt32 kLZX = 0x40000; } const UInt32 kWimVersion = 0x010D00; -const UInt32 kHeaderSizeMax = 0xD0; -const UInt32 kSignatureSize = 8; + +const unsigned kHeaderSizeMax = 0xD0; +const unsigned kSignatureSize = 8; extern const Byte kSignature[kSignatureSize]; const unsigned kChunkSizeBits = 15; const UInt32 kChunkSize = (1 << kChunkSizeBits); @@ -150,7 +258,7 @@ struct CHeader void SetDefaultFields(bool useLZX); void WriteTo(Byte *p) const; - HRESULT Parse(const Byte *p); + HRESULT Parse(const Byte *p, UInt64 &phySize); bool IsCompressed() const { return (Flags & NHeaderFlags::kCompression) != 0; } bool IsSupported() const { return (!IsCompressed() || (Flags & NHeaderFlags::kLZX) != 0 || (Flags & NHeaderFlags::kXPRESS) != 0 ) ; } bool IsLzxMode() const { return (Flags & NHeaderFlags::kLZX) != 0; } @@ -164,115 +272,217 @@ struct CHeader } }; -const UInt32 kHashSize = 20; -const UInt32 kStreamInfoSize = 24 + 2 + 4 + kHashSize; +const unsigned kHashSize = 20; +const unsigned kStreamInfoSize = 24 + 2 + 4 + kHashSize; struct CStreamInfo { CResource Resource; - UInt16 PartNumber; + UInt16 PartNumber; // for NEW WIM format, we set it to 1 for OLD WIM format UInt32 RefCount; - UInt32 Id; - BYTE Hash[kHashSize]; + UInt32 Id; // for OLD WIM format + Byte Hash[kHashSize]; void WriteTo(Byte *p) const; }; -const UInt32 kDirRecordSizeOld = 62; -const UInt32 kDirRecordSize = 102; - struct CItem { - UString Name; - UString ShortName; - UInt32 Attrib; - // UInt32 SecurityId; - BYTE Hash[kHashSize]; - UInt32 Id; - FILETIME CTime; - FILETIME ATime; - FILETIME MTime; - // UInt32 ReparseTag; - // UInt64 HardLink; - // UInt16 NumStreams; + size_t Offset; + int IndexInSorted; int StreamIndex; int Parent; - unsigned Order; - bool HasMetadata; - CItem(): HasMetadata(true), StreamIndex(-1), Id(0) {} - bool IsDir() const { return HasMetadata && ((Attrib & 0x10) != 0); } - bool HasStream() const + int ImageIndex; // -1 means that file is unreferenced in Images (deleted item?) + bool IsDir; + bool IsAltStream; + + bool HasMetadata() const { return ImageIndex >= 0; } + + CItem(): + IndexInSorted(-1), + StreamIndex(-1), + Parent(-1), + IsDir(false), + IsAltStream(false) + {} +}; + +struct CImage +{ + CByteBuffer Meta; + CRecordVector<UInt32> SecurOffsets; + unsigned StartItem; + unsigned NumItems; + unsigned NumEmptyRootItems; + int VirtualRootIndex; // index in CDatabase::VirtualRoots[] + UString RootName; + CByteBuffer RootNameBuf; + + CImage(): VirtualRootIndex(-1) {} +}; + +struct CImageInfo +{ + bool CTimeDefined; + bool MTimeDefined; + bool NameDefined; + bool IndexDefined; + + FILETIME CTime; + FILETIME MTime; + UString Name; + + UInt64 DirCount; + UInt64 FileCount; + UInt32 Index; + + int ItemIndexInXml; + + UInt64 GetTotalFilesAndDirs() const { return DirCount + FileCount; } + + CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false), + IndexDefined(false), ItemIndexInXml(-1) {} + void Parse(const CXmlItem &item); +}; + +struct CWimXml +{ + CByteBuffer Data; + CXml Xml; + + UInt16 VolIndex; + CObjectVector<CImageInfo> Images; + + UString FileName; + + UInt64 GetTotalFilesAndDirs() const { - for (unsigned i = 0; i < kHashSize; i++) - if (Hash[i] != 0) - return true; - return Id != 0; + UInt64 sum = 0; + FOR_VECTOR (i, Images) + sum += Images[i].GetTotalFilesAndDirs(); + return sum; } + + void ToUnicode(UString &s); + bool Parse(); +}; + +struct CVolume +{ + CHeader Header; + CMyComPtr<IInStream> Stream; }; class CDatabase { - const Byte *DirData; + Byte *DirData; size_t DirSize; size_t DirProcessed; size_t DirStartOffset; - int Order; IArchiveOpenCallback *OpenCallback; - + HRESULT ParseDirItem(size_t pos, int parent); - HRESULT ParseImageDirs(const CByteBuffer &buf, int parent); + HRESULT ParseImageDirs(CByteBuffer &buf, int parent); public: - CRecordVector<CStreamInfo> Streams; - CObjectVector<CItem> Items; - CIntVector SortedItems; - int NumImages; - bool SkipRoot; - bool ShowImageNumber; + CRecordVector<CStreamInfo> DataStreams; + + CRecordVector<CStreamInfo> MetaStreams; + + CRecordVector<CItem> Items; + CObjectVector<CByteBuffer> ReparseItems; + CIntVector ItemToReparse; // from index_in_Items to index_in_ReparseItems + // -1 means no reparse; + + CObjectVector<CImage> Images; + bool IsOldVersion; + bool ThereAreDeletedStreams; + bool ThereAreAltStreams; + bool RefCountError; + + // User Items can contain all images or just one image from all. + CUIntVector SortedItems; + int IndexOfUserImage; // -1 : if more than one images was filled to Sorted Items + + unsigned NumExludededItems; + int ExludedItem; // -1 : if there are no exclude items + CUIntVector VirtualRoots; // we use them for old 1.10 WIM archives + + bool ThereIsError() const { return RefCountError; } + + unsigned GetNumUserItemsInImage(unsigned imageIndex) const + { + if (IndexOfUserImage >= 0 && imageIndex != (unsigned)IndexOfUserImage) + return 0; + if (imageIndex >= Images.Size()) + return 0; + return Images[imageIndex].NumItems - NumExludededItems; + } + + bool ItemHasStream(const CItem &item) const; UInt64 GetUnpackSize() const { UInt64 res = 0; - for (int i = 0; i < Streams.Size(); i++) - res += Streams[i].Resource.UnpackSize; + FOR_VECTOR (i, DataStreams) + res += DataStreams[i].Resource.UnpackSize; return res; } UInt64 GetPackSize() const { UInt64 res = 0; - for (int i = 0; i < Streams.Size(); i++) - res += Streams[i].Resource.PackSize; + FOR_VECTOR (i, DataStreams) + res += DataStreams[i].Resource.PackSize; return res; } void Clear() { - Streams.Clear(); + DataStreams.Clear(); + + MetaStreams.Clear(); + Items.Clear(); + ReparseItems.Clear(); + ItemToReparse.Clear(); + SortedItems.Clear(); - NumImages = 0; + + Images.Clear(); + VirtualRoots.Clear(); - SkipRoot = true; - ShowImageNumber = true; IsOldVersion = false; + ThereAreDeletedStreams = false; + ThereAreAltStreams = false; + RefCountError = false; } - UString GetItemPath(int index) const; + CDatabase(): RefCountError(false) {} - HRESULT Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback); + void GetShortName(unsigned index, NWindows::NCOM::CPropVariant &res) const; + void GetItemName(unsigned index1, NWindows::NCOM::CPropVariant &res) const; + void GetItemPath(unsigned index, bool showImageNumber, NWindows::NCOM::CPropVariant &res) const; - void DetectPathMode() - { - ShowImageNumber = (NumImages != 1); - } + HRESULT OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml); + HRESULT Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback); + HRESULT FillAndCheck(); - HRESULT Sort(bool skipRootDir); + /* + imageIndex showImageNumber NumImages + * true * Show Image_Number + -1 * >1 Show Image_Number + -1 false 1 Don't show Image_Number + N false * Don't show Image_Number + */ + HRESULT GenerateSortedItems(int imageIndex, bool showImageNumber); + + HRESULT ExtractReparseStreams(const CObjectVector<CVolume> &volumes, IArchiveOpenCallback *openCallback); }; -HRESULT ReadHeader(IInStream *inStream, CHeader &header); +HRESULT ReadHeader(IInStream *inStream, CHeader &header, UInt64 &phySize); class CUnpacker { @@ -285,6 +495,7 @@ class CUnpacker NXpress::CDecoder xpressDecoder; CByteBuffer sizesBuf; + HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode, ISequentialOutStream *outStream, ICompressProgressInfo *progress); public: diff --git a/CPP/7zip/Archive/Wim/WimRegister.cpp b/CPP/7zip/Archive/Wim/WimRegister.cpp index 8da91436..35d78314 100755..100644 --- a/CPP/7zip/Archive/Wim/WimRegister.cpp +++ b/CPP/7zip/Archive/Wim/WimRegister.cpp @@ -5,14 +5,23 @@ #include "../../Common/RegisterArc.h" #include "WimHandler.h" -static IInArchive *CreateArc() { return new NArchive::NWim::CHandler; } -#ifndef EXTRACT_ONLY -static IOutArchive *CreateArcOut() { return new NArchive::NWim::COutHandler; } -#else -#define CreateArcOut 0 -#endif + +namespace NArchive { +namespace NWim { + +IMP_CreateArcIn +IMP_CreateArcOut static CArcInfo g_ArcInfo = - { L"wim", L"wim swm", 0, 0xE6, { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }, 8, false, CreateArc, CreateArcOut }; + { "wim", "wim swm", 0, 0xE6, + 8, { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }, + 0, + NArcInfoFlags::kAltStreams | + NArcInfoFlags::kNtSecure | + NArcInfoFlags::kSymLinks | + NArcInfoFlags::kHardLinks + , REF_CreateArc_Pair }; REGISTER_ARC(Wim) + +}} diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp index e7d88b6c..918ef736 100755..100644 --- a/CPP/7zip/Archive/XarHandler.cpp +++ b/CPP/7zip/Archive/XarHandler.cpp @@ -4,13 +4,13 @@ #include "../../../C/CpuArch.h" -#include "Common/ComTry.h" -#include "Common/MyXml.h" -#include "Common/StringToInt.h" -#include "Common/UTFConvert.h" +#include "../../Common/ComTry.h" +#include "../../Common/MyXml.h" +#include "../../Common/StringToInt.h" +#include "../../Common/UTFConvert.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" #include "../Common/LimitedStreams.h" #include "../Common/ProgressUtils.h" @@ -24,6 +24,8 @@ #include "Common/OutStreamWithSha1.h" +using namespace NWindows; + #define XAR_SHOW_RAW #define Get16(p) GetBe16(p) @@ -33,6 +35,25 @@ namespace NArchive { namespace NXar { +static const UInt32 kXmlSizeMax = ((UInt32)1 << 30) - (1 << 14); +static const UInt32 kXmlPackSizeMax = kXmlSizeMax; + +/* +#define XAR_CKSUM_NONE 0 +#define XAR_CKSUM_SHA1 1 +#define XAR_CKSUM_MD5 2 + +static const char *k_ChecksumAlgos[] = +{ + "None" + , "SHA-1" + , "MD5" +}; +*/ + +#define METHOD_NAME_ZLIB "zlib" + + struct CFile { AString Name; @@ -41,125 +62,153 @@ struct CFile UInt64 PackSize; UInt64 Offset; - // UInt32 mode; UInt64 CTime; UInt64 MTime; UInt64 ATime; + UInt32 Mode; + + AString User; + AString Group; bool IsDir; bool HasData; - + bool ModeDefined; bool Sha1IsDefined; - Byte Sha1[20]; // bool packSha1IsDefined; - // Byte packSha1[20]; + + Byte Sha1[NCrypto::NSha1::kDigestSize]; + // Byte packSha1[NCrypto::NSha1::kDigestSize]; int Parent; - CFile(): IsDir(false), HasData(false), Sha1IsDefined(false), - /* packSha1IsDefined(false), */ - Parent(-1), Size(0), PackSize(0), CTime(0), MTime(0), ATime(0) {} + CFile(): IsDir(false), HasData(false), ModeDefined(false), Sha1IsDefined(false), + /* packSha1IsDefined(false), */ + Parent(-1), + Size(0), PackSize(0), Offset(0), + CTime(0), MTime(0), ATime(0), Mode(0) {} + + bool IsCopyMethod() const + { + return Method.IsEmpty() || Method == "octet-stream"; + } + + void UpdateTotalPackSize(UInt64 &totalSize) const + { + UInt64 t = Offset + PackSize; + if (totalSize < t) + totalSize = t; + } }; class CHandler: public IInArchive, + public IInArchiveGetStream, public CMyUnknownImp { UInt64 _dataStartPos; CMyComPtr<IInStream> _inStream; AString _xml; CObjectVector<CFile> _files; + // UInt32 _checkSumAlgo; + UInt64 _phySize; + Int32 _mainSubfile; + bool _is_pkg; HRESULT Open2(IInStream *stream); HRESULT Extract(IInStream *stream); public: - MY_UNKNOWN_IMP1(IInArchive) + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; -const UInt32 kXmlSizeMax = ((UInt32)1 << 30) - (1 << 14); +static const Byte kArcProps[] = +{ + kpidSubType, + kpidHeadersSize +}; -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidATime, VT_FILETIME}, - { NULL, kpidMethod, VT_BSTR} + kpidPath, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidPosixAttrib, + kpidUser, + kpidGroup, + kpidMethod }; IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO +IMP_IInArchive_ArcProps -static bool ParseNumber(const char *s, int size, UInt32 &res) -{ - const char *end; - res = (UInt32)ConvertStringToUInt64(s, &end); - return (end - s == size); -} +#define PARSE_NUM(_num_, _dest_) \ + { const char *end; _dest_ = ConvertStringToUInt32(p, &end); \ + if ((unsigned)(end - p) != _num_) return 0; p += _num_ + 1; } static bool ParseUInt64(const CXmlItem &item, const char *name, UInt64 &res) { - AString s = item.GetSubStringForTag(name); + const AString s = item.GetSubStringForTag(name); + if (s.IsEmpty()) + return false; const char *end; res = ConvertStringToUInt64(s, &end); - return (end - (const char *)s == s.Length()); + return *end == 0; } static UInt64 ParseTime(const CXmlItem &item, const char *name) { - AString s = item.GetSubStringForTag(name); - if (s.Length() < 20) + const AString s = item.GetSubStringForTag(name); + if (s.Len() < 20) return 0; const char *p = s; if (p[ 4] != '-' || p[ 7] != '-' || p[10] != 'T' || p[13] != ':' || p[16] != ':' || p[19] != 'Z') return 0; UInt32 year, month, day, hour, min, sec; - if (!ParseNumber(p, 4, year )) return 0; - if (!ParseNumber(p + 5, 2, month)) return 0; - if (!ParseNumber(p + 8, 2, day )) return 0; - if (!ParseNumber(p + 11, 2, hour )) return 0; - if (!ParseNumber(p + 14, 2, min )) return 0; - if (!ParseNumber(p + 17, 2, sec )) return 0; + PARSE_NUM(4, year) + PARSE_NUM(2, month) + PARSE_NUM(2, day) + PARSE_NUM(2, hour) + PARSE_NUM(2, min) + PARSE_NUM(2, sec) UInt64 numSecs; - if (!NWindows::NTime::GetSecondsSince1601(year, month, day, hour, min, sec, numSecs)) + if (!NTime::GetSecondsSince1601(year, month, day, hour, min, sec, numSecs)) return 0; return numSecs * 10000000; } -static bool HexToByte(char c, Byte &res) +static int HexToByte(char c) { - if (c >= '0' && c <= '9') res = c - '0'; - else if (c >= 'A' && c <= 'F') res = c - 'A' + 10; - else if (c >= 'a' && c <= 'f') res = c - 'a' + 10; - else return false; - return true; + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + return -1; } -#define METHOD_NAME_ZLIB "zlib" - static bool ParseSha1(const CXmlItem &item, const char *name, Byte *digest) { int index = item.FindSubTag(name); - if (index < 0) + if (index < 0) return false; const CXmlItem &checkItem = item.SubItems[index]; - AString style = checkItem.GetPropertyValue("style"); + const AString style = checkItem.GetPropVal("style"); if (style == "SHA1") { - AString s = checkItem.GetSubString(); - if (s.Length() != 40) + const AString s = checkItem.GetSubString(); + if (s.Len() != NCrypto::NSha1::kDigestSize * 2) return false; - for (int i = 0; i < s.Length(); i += 2) + for (unsigned i = 0; i < s.Len(); i += 2) { - Byte b0, b1; - if (!HexToByte(s[i], b0) || !HexToByte(s[i + 1], b1)) + int b0 = HexToByte(s[i]); + int b1 = HexToByte(s[i + 1]); + if (b0 < 0 || b1 < 0) return false; - digest[i / 2] = (b0 << 4) | b1; + digest[i / 2] = (Byte)((b0 << 4) | b1); } return true; } @@ -203,17 +252,17 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren const CXmlItem &encodingItem = dataItem.SubItems[encodingIndex]; if (encodingItem.IsTag) { - AString s = encodingItem.GetPropertyValue("style"); - if (s.Length() >= 0) + AString s = encodingItem.GetPropVal("style"); + if (s.Len() >= 0) { AString appl = "application/"; - if (s.Left(appl.Length()) == appl) + if (s.IsPrefixedBy(appl)) { - s = s.Mid(appl.Length()); + s.DeleteFrontal(appl.Len()); AString xx = "x-"; - if (s.Left(xx.Length()) == xx) + if (s.IsPrefixedBy(xx)) { - s = s.Mid(xx.Length()); + s.DeleteFrontal(xx.Len()); if (s == "gzip") s = METHOD_NAME_ZLIB; } @@ -227,9 +276,23 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren file.CTime = ParseTime(item, "ctime"); file.MTime = ParseTime(item, "mtime"); file.ATime = ParseTime(item, "atime"); + + { + const AString s = item.GetSubStringForTag("mode"); + if (s[0] == '0') + { + const char *end; + file.Mode = ConvertOctStringToUInt32(s, &end); + file.ModeDefined = (*end == 0); + } + } + + file.User = item.GetSubStringForTag("user"); + file.Group = item.GetSubStringForTag("group"); + files.Add(file); } - for (int i = 0; i < item.SubItems.Size(); i++) + FOR_VECTOR (i, item.SubItems) if (!AddItem(item.SubItems[i], files, parent)) return false; return true; @@ -237,28 +300,28 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren HRESULT CHandler::Open2(IInStream *stream) { - UInt64 archiveStartPos; - RINOK(stream->Seek(0, STREAM_SEEK_SET, &archiveStartPos)); - const UInt32 kHeaderSize = 0x1C; Byte buf[kHeaderSize]; RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)); UInt32 size = Get16(buf + 4); - // UInt32 ver = Get16(buf + 6); // == 0 + // UInt32 ver = Get16(buf + 6); // == 1 if (Get32(buf) != 0x78617221 || size != kHeaderSize) return S_FALSE; UInt64 packSize = Get64(buf + 8); UInt64 unpackSize = Get64(buf + 0x10); - // UInt32 checkSumAlogo = Get32(buf + 0x18); - if (unpackSize >= kXmlSizeMax) + // _checkSumAlgo = Get32(buf + 0x18); + + if (packSize >= kXmlPackSizeMax || + unpackSize >= kXmlSizeMax) return S_FALSE; - _dataStartPos = archiveStartPos + kHeaderSize + packSize; + _dataStartPos = kHeaderSize + packSize; + _phySize = _dataStartPos; - char *ss = _xml.GetBuffer((int)unpackSize + 1); + char *ss = _xml.GetBuffer((unsigned)unpackSize); NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder(); CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec; @@ -291,6 +354,19 @@ HRESULT CHandler::Open2(IInStream *stream) return S_FALSE; if (!AddItem(toc, _files, -1)) return S_FALSE; + + UInt64 totalPackSize = 0; + FOR_VECTOR(i, _files) + { + const CFile &file = _files[i]; + file.UpdateTotalPackSize(totalPackSize); + if (file.Name == "Payload") + _mainSubfile = i; + if (file.Name == "PackageInfo") + _is_pkg = true; + } + _phySize = _dataStartPos + totalPackSize; + return S_OK; } @@ -311,9 +387,12 @@ STDMETHODIMP CHandler::Open(IInStream *stream, STDMETHODIMP CHandler::Close() { + _phySize = 0; _inStream.Release(); _files.Clear(); _xml.Empty(); + _mainSubfile = -1; + _is_pkg = false; return S_OK; } @@ -327,7 +406,7 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -static void TimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop) +static void TimeToProp(UInt64 t, NCOM::CPropVariant &prop) { if (t != 0) { @@ -338,34 +417,56 @@ static void TimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop) } } +static void Utf8StringToProp(const AString &s, NCOM::CPropVariant &prop) +{ + if (!s.IsEmpty()) + { + UString us; + if (ConvertUTF8ToUnicode(s, us)) + prop = us; + } +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidHeadersSize: prop = _dataStartPos; break; + case kpidPhySize: prop = _phySize; break; + case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; + case kpidSubType: if (_is_pkg) prop = "pkg"; break; + case kpidExtension: prop = _is_pkg ? "pkg" : "xar"; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; #ifdef XAR_SHOW_RAW - if ((int)index == _files.Size()) + if (index == _files.Size()) { - switch(propID) + switch (propID) { - case kpidPath: prop = L"[TOC].xml"; break; + case kpidPath: prop = "[TOC].xml"; break; case kpidSize: - case kpidPackSize: prop = (UInt64)_xml.Length(); break; + case kpidPackSize: prop = (UInt64)_xml.Len(); break; } } else #endif { const CFile &item = _files[index]; - switch(propID) + switch (propID) { - case kpidMethod: - { - UString name; - if (!item.Method.IsEmpty() && ConvertUTF8ToUnicode(item.Method, name)) - prop = name; - break; - } + case kpidMethod: Utf8StringToProp(item.Method, prop); break; + case kpidPath: { AString path; @@ -373,30 +474,40 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val do { const CFile &item = _files[cur]; - AString s = item.Name; - if (s.IsEmpty()) - s = "unknown"; - if (path.IsEmpty()) - path = s; + if (!path.IsEmpty()) + path.InsertAtFront(CHAR_PATH_SEPARATOR); + if (item.Name.IsEmpty()) + path.Insert(0, "unknown"); else - path = s + CHAR_PATH_SEPARATOR + path; + path.Insert(0, item.Name); cur = item.Parent; } while (cur >= 0); - UString name; - if (ConvertUTF8ToUnicode(path, name)) - prop = name; + Utf8StringToProp(path, prop); break; } - case kpidIsDir: prop = item.IsDir; break; - case kpidSize: if (!item.IsDir) prop = item.Size; break; - case kpidPackSize: if (!item.IsDir) prop = item.PackSize; break; + case kpidIsDir: prop = item.IsDir; break; + case kpidSize: if (!item.IsDir) prop = item.Size; break; + case kpidPackSize: if (!item.IsDir) prop = item.PackSize; break; - case kpidMTime: TimeToProp(item.MTime, prop); break; - case kpidCTime: TimeToProp(item.CTime, prop); break; - case kpidATime: TimeToProp(item.ATime, prop); break; + case kpidMTime: TimeToProp(item.MTime, prop); break; + case kpidCTime: TimeToProp(item.CTime, prop); break; + case kpidATime: TimeToProp(item.ATime, prop); break; + case kpidPosixAttrib: + if (item.ModeDefined) + { + UInt32 mode = item.Mode; + const UInt32 k_PosixAttrib_Dir = (1 << 14); + const UInt32 k_PosixAttrib_RegFile = (1 << 15); + if ((mode & 0xF000) == 0) + mode |= (item.IsDir ? k_PosixAttrib_Dir : k_PosixAttrib_RegFile); + prop = mode; + } + break; + case kpidUser: Utf8StringToProp(item.User, prop); break; + case kpidGroup: Utf8StringToProp(item.Group, prop); break; } } prop.Detach(value); @@ -408,7 +519,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _files.Size(); if (numItems == 0) @@ -417,10 +528,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt32 i; for (i = 0; i < numItems; i++) { - int index = (int)(allFilesMode ? i : indices[i]); + UInt32 index = (allFilesMode ? i : indices[i]); #ifdef XAR_SHOW_RAW if (index == _files.Size()) - totalSize += _xml.Length(); + totalSize += _xml.Len(); else #endif totalSize += _files[index].Size; @@ -433,8 +544,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt64 currentUnpSize = 0; const UInt32 kZeroBufSize = (1 << 14); - CByteBuffer zeroBuf; - zeroBuf.SetCapacity(kZeroBufSize); + CByteBuffer zeroBuf(kZeroBufSize); memset(zeroBuf, 0, kZeroBufSize); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); @@ -478,7 +588,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; + UInt32 index = allFilesMode ? i : indices[i]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); if (index < _files.Size()) @@ -504,9 +614,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (index == _files.Size()) { outStreamSha1Spec->Init(false); - outStreamLimSpec->Init(_xml.Length()); - RINOK(WriteStream(outStream, (const char *)_xml, _xml.Length())); - currentPackSize = currentUnpSize = _xml.Length(); + outStreamLimSpec->Init(_xml.Len()); + RINOK(WriteStream(outStream, (const char *)_xml, _xml.Len())); + currentPackSize = currentUnpSize = _xml.Len(); } else #endif @@ -524,17 +634,17 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, HRESULT res = S_OK; ICompressCoder *coder = NULL; - if (item.Method.IsEmpty() || item.Method == "octet-stream") + if (item.IsCopyMethod()) if (item.PackSize == item.Size) coder = copyCoder; else - opRes = NExtract::NOperationResult::kUnSupportedMethod; + opRes = NExtract::NOperationResult::kUnsupportedMethod; else if (item.Method == METHOD_NAME_ZLIB) coder = zlibCoder; else if (item.Method == "bzip2") coder = bzip2Coder; else - opRes = NExtract::NOperationResult::kUnSupportedMethod; + opRes = NExtract::NOperationResult::kUnsupportedMethod; if (coder) res = coder->Code(inStream, outStream, NULL, NULL, progress); @@ -578,10 +688,35 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -static IInArchive *CreateArc() { return new NArchive::NXar::CHandler; } +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + *stream = NULL; + COM_TRY_BEGIN + #ifdef XAR_SHOW_RAW + if (index == _files.Size()) + { + Create_BufInStream_WithNewBuf((const void *)(const char *)_xml, _xml.Len(), stream); + return S_OK; + } + else + #endif + { + const CFile &item = _files[index]; + if (item.HasData && item.IsCopyMethod() && item.PackSize == item.Size) + return CreateLimitedInStream(_inStream, _dataStartPos + item.Offset, item.Size, stream); + } + return S_FALSE; + COM_TRY_END +} + +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"Xar", L"xar", 0, 0xE1, { 'x', 'a', 'r', '!', 0, 0x1C }, 6, false, CreateArc, 0 }; + { "Xar", "xar pkg", 0, 0xE1, + 6, { 'x', 'a', 'r', '!', 0, 0x1C }, + 0, + 0, + CreateArc }; REGISTER_ARC(Xar) diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp index 8383488b..0de58a44 100755..100644 --- a/CPP/7zip/Archive/XzHandler.cpp +++ b/CPP/7zip/Archive/XzHandler.cpp @@ -7,8 +7,8 @@ #include "../../../C/XzEnc.h" #include "../../Common/ComTry.h" +#include "../../Common/Defs.h" #include "../../Common/IntToString.h" -#include "../../Common/StringConvert.h" #include "../ICoder.h" @@ -43,6 +43,81 @@ struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit; static const wchar_t *k_LZMA2_Name = L"LZMA2"; +struct CStatInfo +{ + UInt64 InSize; + UInt64 OutSize; + UInt64 PhySize; + + UInt64 NumStreams; + UInt64 NumBlocks; + + bool UnpackSize_Defined; + + bool NumStreams_Defined; + bool NumBlocks_Defined; + + bool IsArc; + bool UnexpectedEnd; + bool DataAfterEnd; + bool Unsupported; + bool HeadersError; + bool DataError; + bool CrcError; + + CStatInfo() { Clear(); } + + void Clear() + { + InSize = 0; + OutSize = 0; + PhySize = 0; + + NumStreams = 0; + NumBlocks = 0; + + UnpackSize_Defined = false; + + NumStreams_Defined = false; + NumBlocks_Defined = false; + + UnexpectedEnd = false; + DataAfterEnd = false; + Unsupported = false; + HeadersError = false; + DataError = false; + CrcError = false; + IsArc = false; + } + +}; + +struct IDecodeState: public CStatInfo +{ + SRes DecodeRes; + + IDecodeState(): DecodeRes(SZ_OK) {} + virtual HRESULT Progress() = 0; + + HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream); +}; + +struct CVirtProgress_To_LocalProgress: public IDecodeState +{ + CLocalProgress *lps; + CMyComPtr<ICompressProgressInfo> progress; + + HRESULT Progress(); +}; + +HRESULT CVirtProgress_To_LocalProgress::Progress() +{ + lps->InSize = InSize; + lps->OutSize = OutSize; + return lps->SetCur(); +} + + class CHandler: public IInArchive, public IArchiveOpenSeq, @@ -53,19 +128,17 @@ class CHandler: #endif public CMyUnknownImp { - Int64 _startPosition; - UInt64 _packSize; - UInt64 _unpackSize; - UInt64 _numBlocks; - AString _methodsString; - bool _useSeq; - UInt64 _unpackSizeDefined; - UInt64 _packSizeDefined; + CStatInfo _stat; + + bool _isArc; + bool _needSeekToStart; + bool _phySize_Defined; CMyComPtr<IInStream> _stream; CMyComPtr<ISequentialInStream> _seqStream; UInt32 _filterId; + AString _methodsString; void Init() { @@ -73,7 +146,15 @@ class CHandler: CMultiMethodProps::Init(); } - HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback); + HRESULT Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback); + + HRESULT Decode2(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, IDecodeState &progress) + { + RINOK(progress.Decode(seqInStream, outStream)); + _stat = progress; + _phySize_Defined = true; + return S_OK; + } public: MY_QUERYINTERFACE_BEGIN2(IInArchive) @@ -90,7 +171,7 @@ public: #ifndef EXTRACT_ONLY INTERFACE_IOutArchive(;) - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps); + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); #endif CHandler(); @@ -101,60 +182,60 @@ CHandler::CHandler() Init(); } -static STATPROPSTG const kProps[] = +static const Byte kProps[] = { - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMethod, VT_BSTR} + kpidSize, + kpidPackSize, + kpidMethod }; -static STATPROPSTG const kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidNumBlocks, VT_UI4} + kpidMethod, + kpidNumStreams, + kpidNumBlocks }; IMP_IInArchive_Props IMP_IInArchive_ArcProps -static char GetHex(Byte value) +static inline char GetHex(unsigned value) { return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); } -static inline void AddHexToString(AString &res, Byte value) +static inline void AddHexToString(AString &s, Byte value) { - res += GetHex((Byte)(value >> 4)); - res += GetHex((Byte)(value & 0xF)); + s += GetHex(value >> 4); + s += GetHex(value & 0xF); } -static AString ConvertUInt32ToString(UInt32 value) +static void AddUInt32ToString(AString &s, UInt32 value) { - char temp[32]; - ::ConvertUInt32ToString(value, temp); - return temp; + char temp[16]; + ConvertUInt32ToString(value, temp); + s += temp; } -static AString Lzma2PropToString(int prop) +static void Lzma2PropToString(AString &s, unsigned prop) { + char c = 0; + UInt32 size; if ((prop & 1) == 0) - return ConvertUInt32ToString(prop / 2 + 12); - AString res; - char c; - - UInt32 size = (2 | ((prop) & 1)) << ((prop) / 2 + 1); - - if (prop > 17) - { - res = ConvertUInt32ToString(size >> 10); - c = 'm'; - } + size = prop / 2 + 12; else { - res = ConvertUInt32ToString(size); c = 'k'; + size = (UInt32)(2 | (prop & 1)) << (prop / 2 + 1); + if (prop > 17) + { + size >>= 10; + c = 'm'; + } } - return res + c; + AddUInt32ToString(s, size); + if (c != 0) + s += c; } struct CMethodNamePair @@ -178,25 +259,29 @@ static const CMethodNamePair g_NamePairs[] = static AString GetMethodString(const CXzFilter &f) { - AString s; - - for (int i = 0; i < sizeof(g_NamePairs) / sizeof(g_NamePairs[i]); i++) + const char *p = NULL; + for (unsigned i = 0; i < ARRAY_SIZE(g_NamePairs); i++) if (g_NamePairs[i].Id == f.id) - s = g_NamePairs[i].Name; - if (s.IsEmpty()) + { + p = g_NamePairs[i].Name; + break; + } + char temp[32]; + if (!p) { - char temp[32]; ::ConvertUInt64ToString(f.id, temp); - s = temp; + p = temp; } + AString s = p; + if (f.propsSize > 0) { s += ':'; if (f.id == XZ_ID_LZMA2 && f.propsSize == 1) - s += Lzma2PropToString(f.props[0]); + Lzma2PropToString(s, f.props[0]); else if (f.id == XZ_ID_Delta && f.propsSize == 1) - s += ConvertUInt32ToString((UInt32)f.props[0] + 1); + AddUInt32ToString(s, (UInt32)f.props[0] + 1); else { s += '['; @@ -217,22 +302,22 @@ static void AddString(AString &dest, const AString &src) static const char *kChecks[] = { - "NoCheck", - "CRC32", - NULL, - NULL, - "CRC64", - NULL, - NULL, - NULL, - NULL, - NULL, - "SHA256", - NULL, - NULL, - NULL, - NULL, - NULL + "NoCheck" + , "CRC32" + , NULL + , NULL + , "CRC64" + , NULL + , NULL + , NULL + , NULL + , NULL + , "SHA256" + , NULL + , NULL + , NULL + , NULL + , NULL }; static AString GetCheckString(const CXzs &xzs) @@ -249,7 +334,10 @@ static AString GetCheckString(const CXzs &xzs) if (kChecks[i]) s2 = kChecks[i]; else - s2 = "Check-" + ConvertUInt32ToString((UInt32)i); + { + s2 = "Check-"; + AddUInt32ToString(s2, (UInt32)i); + } AddString(s, s2); } return s; @@ -258,12 +346,26 @@ static AString GetCheckString(const CXzs &xzs) STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) + NCOM::CPropVariant prop; + switch (propID) { - case kpidNumBlocks: if (!_useSeq) prop = _numBlocks; break; - case kpidPhySize: if (_packSizeDefined) prop = _packSize; break; + case kpidPhySize: if (_phySize_Defined) prop = _stat.PhySize; break; + case kpidNumStreams: if (_stat.NumStreams_Defined) prop = _stat.NumStreams; break; + case kpidNumBlocks: if (_stat.NumBlocks_Defined) prop = _stat.NumBlocks; break; + case kpidUnpackSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break; case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; + if (_stat.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_stat.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; + if (_stat.HeadersError) v |= kpv_ErrorFlags_HeadersError; + if (_stat.Unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; + if (_stat.DataError) v |= kpv_ErrorFlags_DataError; + if (_stat.CrcError) v |= kpv_ErrorFlags_CrcError; + prop = v; + } } prop.Detach(value); return S_OK; @@ -276,14 +378,14 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -STDMETHODIMP CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) + NCOM::CPropVariant prop; + switch (propID) { - case kpidSize: if (_unpackSizeDefined) prop = _unpackSize; break; - case kpidPackSize: if (_packSizeDefined) prop = _packSize; break; + case kpidSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break; + case kpidPackSize: if (_phySize_Defined) prop = _stat.PhySize; break; case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break; } prop.Detach(value); @@ -321,82 +423,124 @@ struct CXzsCPP ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); } }; -HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback) + +struct CVirtProgress_To_OpenProgress: public IDecodeState { - CSeekInStreamWrap inStreamImp(inStream); + IArchiveOpenCallback *Callback; + UInt64 Offset; - CLookToRead lookStream; - LookToRead_CreateVTable(&lookStream, True); - lookStream.realStream = &inStreamImp.p; - LookToRead_Init(&lookStream); + HRESULT Progress(); +}; - COpenCallbackWrap openWrap(callback); - RINOK(inStream->Seek(0, STREAM_SEEK_END, &_packSize)); - RINOK(callback->SetTotal(NULL, &_packSize)); +HRESULT CVirtProgress_To_OpenProgress::Progress() +{ + if (Callback) + { + UInt64 files = 0; + UInt64 value = Offset + InSize; + return Callback->SetCompleted(&files, &value); + } + return S_OK; +} - CXzsCPP xzs; - SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.s, &_startPosition, &openWrap.p, &g_Alloc); - if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0) - res = SZ_OK; - if (res == SZ_OK) +static HRESULT SRes_to_Open_HRESULT(SRes res) +{ + switch (res) { - _packSize -= _startPosition; - _unpackSize = Xzs_GetUnpackSize(&xzs.p); - _unpackSizeDefined = _packSizeDefined = true; - _numBlocks = (UInt64)Xzs_GetNumBlocks(&xzs.p); + case SZ_OK: return S_OK; + case SZ_ERROR_MEM: return E_OUTOFMEMORY; + case SZ_ERROR_PROGRESS: return E_ABORT; + /* + case SZ_ERROR_UNSUPPORTED: + case SZ_ERROR_CRC: + case SZ_ERROR_DATA: + case SZ_ERROR_ARCHIVE: + case SZ_ERROR_NO_ARCHIVE: + return S_FALSE; + */ + } + return S_FALSE; +} - RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); +HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback) +{ + _needSeekToStart = true; + + { CXzStreamFlags st; CSeqInStreamWrap inStreamWrap(inStream); - SRes res2 = Xz_ReadHeader(&st, &inStreamWrap.p); + SRes res = Xz_ReadHeader(&st, &inStreamWrap.p); + if (res != SZ_OK) + return SRes_to_Open_HRESULT(res); - if (res2 == SZ_OK) { CXzBlock block; Bool isIndex; UInt32 headerSizeRes; - res2 = XzBlock_ReadHeader(&block, &inStreamWrap.p, &isIndex, &headerSizeRes); + SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.p, &isIndex, &headerSizeRes); if (res2 == SZ_OK && !isIndex) { - int numFilters = XzBlock_GetNumFilters(&block); - for (int i = 0; i < numFilters; i++) + unsigned numFilters = XzBlock_GetNumFilters(&block); + for (unsigned i = 0; i < numFilters; i++) AddString(_methodsString, GetMethodString(block.filters[i])); } } - AddString(_methodsString, GetCheckString(xzs.p)); } - if (res != SZ_OK || _startPosition != 0) + RINOK(inStream->Seek(0, STREAM_SEEK_END, &_stat.PhySize)); + RINOK(callback->SetTotal(NULL, &_stat.PhySize)); + + CSeekInStreamWrap inStreamImp(inStream); + + CLookToRead lookStream; + LookToRead_CreateVTable(&lookStream, True); + lookStream.realStream = &inStreamImp.p; + LookToRead_Init(&lookStream); + + COpenCallbackWrap openWrap(callback); + + CXzsCPP xzs; + Int64 startPosition; + SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.s, &startPosition, &openWrap.p, &g_Alloc); + if (res == SZ_ERROR_PROGRESS) + return (openWrap.Res == S_OK) ? E_FAIL : openWrap.Res; + /* + if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0) + res = SZ_OK; + */ + if (res == SZ_OK && startPosition == 0) { - RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); - CXzStreamFlags st; - CSeqInStreamWrap inStreamWrap(inStream); - SRes res2 = Xz_ReadHeader(&st, &inStreamWrap.p); - if (res2 == SZ_OK) - { - res = res2; - _startPosition = 0; - _useSeq = True; - _unpackSizeDefined = _packSizeDefined = false; - } + _phySize_Defined = true; + + _stat.OutSize = Xzs_GetUnpackSize(&xzs.p); + _stat.UnpackSize_Defined = true; + + _stat.NumStreams = xzs.p.num; + _stat.NumStreams_Defined = true; + + _stat.NumBlocks = Xzs_GetNumBlocks(&xzs.p); + _stat.NumBlocks_Defined = true; + + AddString(_methodsString, GetCheckString(xzs.p)); + } + else + { + res = SZ_OK; } - if (res == SZ_ERROR_NO_ARCHIVE) - return S_FALSE; - RINOK(SResToHRESULT(res)); + RINOK(SRes_to_Open_HRESULT(res)); _stream = inStream; _seqStream = inStream; + _isArc = true; return S_OK; } STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback) { COM_TRY_BEGIN - try { Close(); - return Open2(inStream, callback); + return Open2(inStream, /* 0, */ callback); } - catch(...) { return S_FALSE; } COM_TRY_END } @@ -404,15 +548,21 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) { Close(); _seqStream = stream; + _isArc = true; + _needSeekToStart = false; return S_OK; } STDMETHODIMP CHandler::Close() { - _numBlocks = 0; - _useSeq = true; - _unpackSizeDefined = _packSizeDefined = false; - _methodsString.Empty(); + _stat.Clear(); + + _isArc = false; + _needSeekToStart = false; + + _phySize_Defined = false; + + _methodsString.Empty(); _stream.Release(); _seqStream.Release(); return S_OK; @@ -442,6 +592,7 @@ struct CXzUnpackerCPP Byte *InBuf; Byte *OutBuf; CXzUnpacker p; + CXzUnpackerCPP(): InBuf(0), OutBuf(0) { XzUnpacker_Construct(&p, &g_Alloc); @@ -454,129 +605,193 @@ struct CXzUnpackerCPP } }; -STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback) +HRESULT IDecodeState::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream) { - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - extractCallback->SetTotal(_packSize); - UInt64 currentTotalPacked = 0; - RINOK(extractCallback->SetCompleted(¤tTotalPacked)); - CMyComPtr<ISequentialOutStream> realOutStream; - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); - - if (!testMode && !realOutStream) - return S_OK; - - extractCallback->PrepareOperation(askMode); - - if (_stream) - { - RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL)); - } - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr<ICompressProgressInfo> progress = lps; - lps->Init(extractCallback, true); - - CCompressProgressWrap progressWrap(progress); + const size_t kInBufSize = 1 << 15; + const size_t kOutBufSize = 1 << 21; - SRes res = S_OK; + DecodeRes = SZ_OK; - const UInt32 kInBufSize = 1 << 15; - const UInt32 kOutBufSize = 1 << 21; - - UInt32 inPos = 0; - UInt32 inSize = 0; - UInt32 outPos = 0; CXzUnpackerCPP xzu; XzUnpacker_Init(&xzu.p); - { - xzu.InBuf = (Byte *)MyAlloc(kInBufSize); - xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize); - if (xzu.InBuf == 0 || xzu.OutBuf == 0) - res = SZ_ERROR_MEM; - } - if (res == SZ_OK) + xzu.InBuf = (Byte *)MyAlloc(kInBufSize); + xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize); + if (!xzu.InBuf || !xzu.OutBuf) + return E_OUTOFMEMORY; + + UInt32 inSize = 0; + SizeT inPos = 0; + SizeT outPos = 0; + for (;;) { if (inPos == inSize) { inPos = inSize = 0; - RINOK(_seqStream->Read(xzu.InBuf, kInBufSize, &inSize)); + RINOK(seqInStream->Read(xzu.InBuf, kInBufSize, &inSize)); } SizeT inLen = inSize - inPos; SizeT outLen = kOutBufSize - outPos; ECoderStatus status; - res = XzUnpacker_Code(&xzu.p, + + SRes res = XzUnpacker_Code(&xzu.p, xzu.OutBuf + outPos, &outLen, xzu.InBuf + inPos, &inLen, (inSize == 0 ? CODER_FINISH_END : CODER_FINISH_ANY), &status); - // printf("\n_inPos = %6d inLen = %5d, outLen = %5d", inPos, inLen, outLen); + inPos += inLen; + outPos += outLen; + + InSize += inLen; + OutSize += outLen; - inPos += (UInt32)inLen; - outPos += (UInt32)outLen; - lps->InSize += inLen; - lps->OutSize += outLen; + DecodeRes = res; - bool finished = (((inLen == 0) && (outLen == 0)) || res != SZ_OK); + bool finished = ((inLen == 0 && outLen == 0) || res != SZ_OK); - if (outPos == kOutBufSize || finished) + if (outStream) { - if (realOutStream && outPos > 0) + if (outPos == kOutBufSize || finished) { - RINOK(WriteStream(realOutStream, xzu.OutBuf, outPos)); + if (outPos != 0) + { + RINOK(WriteStream(outStream, xzu.OutBuf, outPos)); + outPos = 0; + } } - outPos = 0; } - RINOK(lps->SetCur()); + else + outPos = 0; + + RINOK(Progress()); + if (finished) { - _packSize = lps->InSize; - _unpackSize = lps->OutSize; - _packSizeDefined = _unpackSizeDefined = true; + PhySize = InSize; + NumStreams = xzu.p.numStartedStreams; + if (NumStreams > 0) + IsArc = true; + NumBlocks = xzu.p.numTotalBlocks; + + UnpackSize_Defined = true; + NumStreams_Defined = true; + NumBlocks_Defined = true; + + UInt64 extraSize = XzUnpacker_GetExtraSize(&xzu.p); + if (res == SZ_OK) { if (status == CODER_STATUS_NEEDS_MORE_INPUT) { - if (XzUnpacker_IsStreamWasFinished(&xzu.p)) - _packSize -= xzu.p.padSize; - else + extraSize = 0; + if (!XzUnpacker_IsStreamWasFinished(&xzu.p)) + { + // finished at padding bytes, but padding is not aligned for 4 + UnexpectedEnd = true; res = SZ_ERROR_DATA; + } } - else + else // status == CODER_STATUS_NOT_FINISHED res = SZ_ERROR_DATA; } + else if (res == SZ_ERROR_NO_ARCHIVE) + { + if (InSize == extraSize) + IsArc = false; + else + { + if (extraSize != 0 || inPos != inSize) + { + DataAfterEnd = true; + res = SZ_OK; + } + } + } + + DecodeRes = res; + PhySize -= extraSize; + + switch (res) + { + case SZ_OK: break; + case SZ_ERROR_NO_ARCHIVE: IsArc = false; break; + case SZ_ERROR_ARCHIVE: HeadersError = true; break; + case SZ_ERROR_UNSUPPORTED: Unsupported = true; break; + case SZ_ERROR_CRC: CrcError = true; break; + case SZ_ERROR_DATA: DataError = true; break; + default: DataError = true; break; + } + break; } } - Int32 opRes; - switch(res) + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + extractCallback->SetTotal(_stat.PhySize); + UInt64 currentTotalPacked = 0; + RINOK(extractCallback->SetCompleted(¤tTotalPacked)); + CMyComPtr<ISequentialOutStream> realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); + + if (!testMode && !realOutStream) + return S_OK; + + extractCallback->PrepareOperation(askMode); + + CVirtProgress_To_LocalProgress vp; + vp.lps = new CLocalProgress; + vp.progress = vp.lps; + vp.lps->Init(extractCallback, true); + + + if (_needSeekToStart) { - case SZ_OK: - opRes = NExtract::NOperationResult::kOK; break; - case SZ_ERROR_UNSUPPORTED: - opRes = NExtract::NOperationResult::kUnSupportedMethod; break; - case SZ_ERROR_CRC: - opRes = NExtract::NOperationResult::kCRCError; break; - case SZ_ERROR_DATA: - case SZ_ERROR_ARCHIVE: - case SZ_ERROR_NO_ARCHIVE: - opRes = NExtract::NOperationResult::kDataError; break; - default: - return SResToHRESULT(res); + if (!_stream) + return E_FAIL; + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); } + else + _needSeekToStart = true; + + RINOK(Decode2(_seqStream, realOutStream, vp)); + + Int32 opRes; + + if (!vp.IsArc) + opRes = NExtract::NOperationResult::kIsNotArc; + else if (vp.UnexpectedEnd) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + else if (vp.DataAfterEnd) + opRes = NExtract::NOperationResult::kDataAfterEnd; + else if (vp.CrcError) + opRes = NExtract::NOperationResult::kCRCError; + else if (vp.Unsupported) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else if (vp.HeadersError) + opRes = NExtract::NOperationResult::kDataError; + else if (vp.DataError) + opRes = NExtract::NOperationResult::kDataError; + else if (vp.DecodeRes != SZ_OK) + opRes = NExtract::NOperationResult::kDataError; + else + opRes = NExtract::NOperationResult::kOK; + realOutStream.Release(); return extractCallback->SetOperationResult(opRes); COM_TRY_END @@ -648,7 +863,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt RINOK(NCompress::NLzma2::SetLzma2Prop(NCoderPropID::kReduceSize, prop, lzma2Props)); } - for (int i = 0; i < _methods.Size(); i++) + FOR_VECTOR (i, _methods) { COneMethodInfo &m = _methods[i]; SetGlobalLevelAndThreads(m @@ -657,7 +872,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt #endif ); { - for (int j = 0; j < m.Props.Size(); j++) + FOR_VECTOR (j, m.Props) { const CProp &prop = m.Props[j]; RINOK(NCompress::NLzma2::SetLzma2Prop(prop.Id, prop.Value, lzma2Props)); @@ -692,7 +907,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (_filterId == XZ_ID_Delta) { bool deltaDefined = false; - for (int j = 0; j < _filterMethod.Props.Size(); j++) + FOR_VECTOR (j, _filterMethod.Props) { const CProp &prop = _filterMethod.Props[j]; if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4) @@ -715,29 +930,26 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (indexInArchive != 0) return E_INVALIDARG; if (_stream) - RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL)); - return NCompress::CopyStream(_stream, outStream, 0); + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); + return NCompress::CopyStream(_stream, outStream, NULL); } -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) - -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN Init(); - for (int i = 0; i < numProps; i++) + for (UInt32 i = 0; i < numProps; i++) { RINOK(SetProperty(names[i], values[i])); } if (!_filterMethod.MethodName.IsEmpty()) { - int k; + unsigned k; for (k = 0; k < ARRAY_SIZE(g_NamePairs); k++) { const CMethodNamePair &pair = g_NamePairs[k]; - UString m = GetUnicodeString(pair.Name); - if (_filterMethod.MethodName.CompareNoCase(m) == 0) + if (StringsAreEqualNoCase_Ascii(_filterMethod.MethodName, pair.Name)) { _filterId = pair.Id; break; @@ -747,8 +959,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v return E_INVALIDARG; } - int numEmptyMethods = GetNumEmptyMethods(); - _methods.Delete(0, numEmptyMethods); + _methods.DeleteFrontal(GetNumEmptyMethods()); if (_methods.Size() > 1) return E_INVALIDARG; if (_methods.Size() == 1) @@ -756,7 +967,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v UString &methodName = _methods[0].MethodName; if (methodName.IsEmpty()) methodName = k_LZMA2_Name; - else if (methodName.CompareNoCase(k_LZMA2_Name) != 0) + else if (!methodName.IsEqualToNoCase(k_LZMA2_Name)) return E_INVALIDARG; } return S_OK; @@ -765,15 +976,15 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v #endif -static IInArchive *CreateArc() { return new NArchive::NXz::CHandler; } -#ifndef EXTRACT_ONLY -static IOutArchive *CreateArcOut() { return new NArchive::NXz::CHandler; } -#else -#define CreateArcOut 0 -#endif +IMP_CreateArcIn +IMP_CreateArcOut static CArcInfo g_ArcInfo = - { L"xz", L"xz txz", L"* .tar", 0xC, {0xFD, '7' , 'z', 'X', 'Z', '\0'}, 6, true, CreateArc, CreateArcOut }; + { "xz", "xz txz", "* .tar", 0xC, + 6, { 0xFD, '7' , 'z', 'X', 'Z', 0 }, + 0, + NArcInfoFlags::kKeepName, + REF_CreateArc_Pair }; REGISTER_ARC(xz) diff --git a/CPP/7zip/Archive/ZHandler.cpp b/CPP/7zip/Archive/ZHandler.cpp index 49b76a11..459f3e35 100755..100644 --- a/CPP/7zip/Archive/ZHandler.cpp +++ b/CPP/7zip/Archive/ZHandler.cpp @@ -2,9 +2,9 @@ #include "StdAfx.h" -#include "Common/ComTry.h" +#include "../../Common/ComTry.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" @@ -22,21 +22,21 @@ class CHandler: public CMyUnknownImp { CMyComPtr<IInStream> _stream; - UInt64 _streamStartPosition; UInt64 _packSize; - Byte _properties; + // UInt64 _unpackSize; + // bool _unpackSize_Defined; public: MY_UNKNOWN_IMP1(IInArchive) INTERFACE_IInArchive(;) }; -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPackSize, VT_UI8} + kpidPackSize }; IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO +IMP_IInArchive_ArcProps_NO_Table STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { @@ -44,36 +44,110 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NWindows::NCOM::CPropVariant prop; - switch(propID) + switch (propID) { + case kpidPhySizeCantBeDetected: prop = true; break; + } + prop.Detach(value); + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +{ + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + // case kpidSize: if (_unpackSize_Defined) prop = _unpackSize; break; case kpidPackSize: prop = _packSize; break; } prop.Detach(value); return S_OK; } -static const int kSignatureSize = 3; +/* +class CCompressProgressInfoImp: + public ICompressProgressInfo, + public CMyUnknownImp +{ + CMyComPtr<IArchiveOpenCallback> Callback; +public: + MY_UNKNOWN_IMP1(ICompressProgressInfo) + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); + void Init(IArchiveOpenCallback *callback) { Callback = callback; } +}; + +STDMETHODIMP CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + if (Callback) + { + UInt64 files = 1; + return Callback->SetCompleted(&files, inSize); + } + return S_OK; +} +*/ + +API_FUNC_static_IsArc IsArc_Z(const Byte *p, size_t size) +{ + if (size < 3) + return k_IsArc_Res_NEED_MORE; + if (size > NCompress::NZ::kRecommendedCheckSize) + size = NCompress::NZ::kRecommendedCheckSize; + if (!NCompress::NZ::CheckStream(p, size)) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */) + IArchiveOpenCallback * /* openCallback */) { COM_TRY_BEGIN { - RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_streamStartPosition)); - Byte buffer[kSignatureSize]; - RINOK(ReadStream_FALSE(stream, buffer, kSignatureSize)); - if (buffer[0] != 0x1F || buffer[1] != 0x9D) + // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_streamStartPosition)); + Byte buffer[NCompress::NZ::kRecommendedCheckSize]; + // Byte buffer[1500]; + size_t size = NCompress::NZ::kRecommendedCheckSize; + // size = 700; + RINOK(ReadStream(stream, buffer, &size)); + if (!NCompress::NZ::CheckStream(buffer, size)) return S_FALSE; - _properties = buffer[2]; - UInt64 endPosition; - RINOK(stream->Seek(0, STREAM_SEEK_END, &endPosition)); - _packSize = endPosition - _streamStartPosition - kSignatureSize; - + UInt64 endPos; + RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos)); + _packSize = endPos; + + /* + bool fullCheck = false; + if (fullCheck) + { + CCompressProgressInfoImp *compressProgressSpec = new CCompressProgressInfoImp; + CMyComPtr<ICompressProgressInfo> compressProgress = compressProgressSpec; + compressProgressSpec->Init(openCallback); + + NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder; + CMyComPtr<ICompressCoder> decoder = decoderSpec; + + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); + outStreamSpec->SetStream(NULL); + outStreamSpec->Init(); + decoderSpec->SetProp(_prop); + if (openCallback) + { + UInt64 files = 1; + RINOK(openCallback->SetTotal(&files, &endPos)); + } + RINOK(stream->Seek(_streamStartPosition + kSignatureSize, STREAM_SEEK_SET, NULL)); + HRESULT res = decoder->Code(stream, outStream, NULL, NULL, openCallback ? compressProgress : NULL); + if (res != S_OK) + return S_FALSE; + _packSize = decoderSpec->PackSize; + } + */ _stream = stream; } return S_OK; @@ -82,6 +156,8 @@ STDMETHODIMP CHandler::Open(IInStream *stream, STDMETHODIMP CHandler::Close() { + _packSize = 0; + // _unpackSize_Defined = false; _stream.Release(); return S_OK; } @@ -93,7 +169,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_BEGIN if (numItems == 0) return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; extractCallback->SetTotal(_packSize); @@ -124,37 +200,37 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, true); - RINOK(_stream->Seek(_streamStartPosition + kSignatureSize, STREAM_SEEK_SET, NULL)); + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - CMyComPtr<ICompressCoder> decoder; NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder; - decoder = decoderSpec; - - HRESULT result = decoderSpec->SetDecoderProperties2(&_properties, 1); + CMyComPtr<ICompressCoder> decoder = decoderSpec; - int opResult; - if (result != S_OK) - opResult = NExtract::NOperationResult::kUnSupportedMethod; - else + int opRes; { - result = decoder->Code(_stream, outStream, NULL, NULL, progress); + HRESULT result = decoder->Code(_stream, outStream, NULL, NULL, progress); if (result == S_FALSE) - opResult = NExtract::NOperationResult::kDataError; + opRes = NExtract::NOperationResult::kDataError; else { RINOK(result); - opResult = NExtract::NOperationResult::kOK; + opRes = NExtract::NOperationResult::kOK; } } + // _unpackSize = outStreamSpec->GetSize(); + // _unpackSize_Defined = true; outStream.Release(); - return extractCallback->SetOperationResult(opResult); + return extractCallback->SetOperationResult(opRes); COM_TRY_END } -static IInArchive *CreateArc() { return new CHandler; } +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"Z", L"z taz", L"* .tar", 5, { 0x1F, 0x9D }, 2, false, CreateArc, 0 }; + { "Z", "z taz", "* .tar", 5, + 2, { 0x1F, 0x9D }, + 0, + 0, + CreateArc, NULL, IsArc_Z }; REGISTER_ARC(Z) diff --git a/CPP/7zip/Archive/Zip/StdAfx.h b/CPP/7zip/Archive/Zip/StdAfx.h index e7fb6986..2854ff3e 100755..100644 --- a/CPP/7zip/Archive/Zip/StdAfx.h +++ b/CPP/7zip/Archive/Zip/StdAfx.h @@ -3,6 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" +#include "../../../Common/Common.h" #endif diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp index f77e4f23..9a0d7515 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp @@ -4,7 +4,7 @@ #include "../../../../C/7zCrc.h" -#include "Windows/PropVariant.h" +#include "../../../Windows/PropVariant.h" #include "../../ICoder.h" #include "../../IPassword.h" @@ -85,18 +85,18 @@ CAddCommon::CAddCommon(const CCompressionMethodMode &options): static HRESULT GetStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC) { UInt32 crc = CRC_INIT_VAL; - const UInt32 kBufferSize = (1 << 14); - Byte buffer[kBufferSize]; + const UInt32 kBufSize = (1 << 14); + Byte buf[kBufSize]; for (;;) { - UInt32 realProcessedSize; - RINOK(inStream->Read(buffer, kBufferSize, &realProcessedSize)); - if (realProcessedSize == 0) + UInt32 processed; + RINOK(inStream->Read(buf, kBufSize, &processed)); + if (processed == 0) { resultCRC = CRC_GET_DIGEST(crc); return S_OK; } - crc = CrcUpdate(crc, buffer, (size_t)realProcessedSize); + crc = CrcUpdate(crc, buf, (size_t)processed); } } @@ -105,8 +105,14 @@ HRESULT CAddCommon::Compress( ISequentialInStream *inStream, IOutStream *outStream, ICompressProgressInfo *progress, CCompressingResult &opRes) { - CSequentialInStreamWithCRC *inSecCrcStreamSpec = 0; - CInStreamWithCRC *inCrcStreamSpec = 0; + if (!inStream) + { + // We can create empty stream here. But it was already implemented in caller code in 9.33+ + return E_INVALIDARG; + } + + CSequentialInStreamWithCRC *inSecCrcStreamSpec = NULL; + CInStreamWithCRC *inCrcStreamSpec = NULL; CMyComPtr<ISequentialInStream> inCrcStream; { CMyComPtr<IInStream> inStream2; @@ -128,26 +134,30 @@ HRESULT CAddCommon::Compress( } } - int numTestMethods = _options.MethodSequence.Size(); + unsigned numTestMethods = _options.MethodSequence.Size(); + if (numTestMethods > 1 || _options.PasswordIsDefined) { - if (inCrcStreamSpec == 0) + if (!inCrcStreamSpec) { if (_options.PasswordIsDefined) return E_NOTIMPL; numTestMethods = 1; } } + Byte method = 0; COutStreamReleaser outStreamReleaser; opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default; - for (int i = 0; i < numTestMethods; i++) + + for (unsigned i = 0; i < numTestMethods; i++) { opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default; - if (inCrcStreamSpec != 0) + if (inCrcStreamSpec) RINOK(inCrcStreamSpec->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; @@ -157,6 +167,7 @@ HRESULT CAddCommon::Compress( _cryptoStreamSpec = new CFilterCoder; _cryptoStream = _cryptoStreamSpec; } + if (_options.IsAesMode) { opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Aes; @@ -164,7 +175,7 @@ HRESULT CAddCommon::Compress( { _cryptoStreamSpec->Filter = _filterAesSpec = new NCrypto::NWzAes::CEncoder; _filterAesSpec->SetKeyMode(_options.AesKeyMode); - RINOK(_filterAesSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Length())); + RINOK(_filterAesSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len())); } RINOK(_filterAesSpec->WriteHeader(outStream)); } @@ -173,19 +184,21 @@ HRESULT CAddCommon::Compress( if (!_cryptoStreamSpec->Filter) { _cryptoStreamSpec->Filter = _filterSpec = new NCrypto::NZip::CEncoder; - _filterSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Length()); + _filterSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len()); } UInt32 crc = 0; RINOK(GetStreamCRC(inStream, crc)); RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL)); RINOK(_filterSpec->WriteHeader(outStream, crc)); } + RINOK(_cryptoStreamSpec->SetOutStream(outStream)); outStreamReleaser.FilterCoder = _cryptoStreamSpec; } method = _options.MethodSequence[i]; - switch(method) + + switch (method) { case NFileHeader::NCompressionMethod::kStored: { @@ -202,6 +215,7 @@ HRESULT CAddCommon::Compress( RINOK(_copyCoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress)); break; } + default: { if (!_compressEncoder) @@ -272,7 +286,7 @@ HRESULT CAddCommon::Compress( RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize)); - if (inCrcStreamSpec != 0) + if (inCrcStreamSpec) { opRes.CRC = inCrcStreamSpec->GetCRC(); opRes.UnpackSize = inCrcStreamSpec->GetSize(); @@ -292,6 +306,7 @@ HRESULT CAddCommon::Compress( else if (opRes.PackSize < opRes.UnpackSize) break; } + if (_options.PasswordIsDefined && _options.IsAesMode) { RINOK(_filterAesSpec->WriteFooter(outStream)); diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.h b/CPP/7zip/Archive/Zip/ZipAddCommon.h index e4c02db3..e4c02db3 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.h +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.h diff --git a/CPP/7zip/Archive/Zip/ZipCompressionMode.h b/CPP/7zip/Archive/Zip/ZipCompressionMode.h index 893daaab..86548d95 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipCompressionMode.h +++ b/CPP/7zip/Archive/Zip/ZipCompressionMode.h @@ -3,7 +3,7 @@ #ifndef __ZIP_COMPRESSION_MODE_H #define __ZIP_COMPRESSION_MODE_H -#include "Common/MyString.h" +#include "../../../Common/MyString.h" #ifndef _7ZIP_ST #include "../../../Windows/System.h" diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp index 2281ed5b..f556068c 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp @@ -2,11 +2,11 @@ #include "StdAfx.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" #include "../../IPassword.h" @@ -40,98 +40,112 @@ static const CMethodId kMethodId_BZip2 = 0x040202; static const char *kHostOS[] = { - "FAT", - "AMIGA", - "VMS", - "Unix", - "VM/CMS", - "Atari", - "HPFS", - "Macintosh", - "Z-System", - "CP/M", - "TOPS-20", - "NTFS", - "SMS/QDOS", - "Acorn", - "VFAT", - "MVS", - "BeOS", - "Tandem", - "OS/400", - "OS/X" + "FAT" + , "AMIGA" + , "VMS" + , "Unix" + , "VM/CMS" + , "Atari" + , "HPFS" + , "Macintosh" + , "Z-System" + , "CP/M" + , "TOPS-20" + , "NTFS" + , "SMS/QDOS" + , "Acorn" + , "VFAT" + , "MVS" + , "BeOS" + , "Tandem" + , "OS/400" + , "OS/X" }; -static const char *kUnknownOS = "Unknown"; - static const char *kMethods[] = { - "Store", - "Shrink", - "Reduced1", - "Reduced2", - "Reduced3", - "Reduced4", - "Implode", - "Tokenizing", - "Deflate", - "Deflate64", - "PKImploding" + "Store" + , "Shrink" + , "Reduced1" + , "Reduced2" + , "Reduced3" + , "Reduced4" + , "Implode" + , "Tokenizing" + , "Deflate" + , "Deflate64" + , "PKImploding" }; -static const char *kBZip2Method = "BZip2"; -static const char *kLZMAMethod = "LZMA"; -static const char *kJpegMethod = "Jpeg"; -static const char *kWavPackMethod = "WavPack"; -static const char *kPPMdMethod = "PPMd"; -static const char *kAESMethod = "AES"; -static const char *kZipCryptoMethod = "ZipCrypto"; -static const char *kStrongCryptoMethod = "StrongCrypto"; +static const char *kMethod_AES = "AES"; +static const char *kMethod_ZipCrypto = "ZipCrypto"; +static const char *kMethod_StrongCrypto = "StrongCrypto"; -static struct CStrongCryptoPair +struct CIdToNamePair { - UInt16 Id; + unsigned Id; const char *Name; -} g_StrongCryptoPairs[] = +}; + +static const CIdToNamePair k_MethodIdNamePairs[] = +{ + { NFileHeader::NCompressionMethod::kBZip2, "BZip2" }, + { NFileHeader::NCompressionMethod::kLZMA, "LZMA" }, + { NFileHeader::NCompressionMethod::kJpeg, "Jpeg" }, + { NFileHeader::NCompressionMethod::kWavPack, "WavPack" }, + { NFileHeader::NCompressionMethod::kPPMd, "PPMd" } +}; + +static const CIdToNamePair k_StrongCryptoPairs[] = { - { NStrongCryptoFlags::kDES, "DES" }, - { NStrongCryptoFlags::kRC2old, "RC2a" }, - { NStrongCryptoFlags::k3DES168, "3DES-168" }, - { NStrongCryptoFlags::k3DES112, "3DES-112" }, - { NStrongCryptoFlags::kAES128, "pkAES-128" }, - { NStrongCryptoFlags::kAES192, "pkAES-192" }, - { NStrongCryptoFlags::kAES256, "pkAES-256" }, - { NStrongCryptoFlags::kRC2, "RC2" }, - { NStrongCryptoFlags::kBlowfish, "Blowfish" }, - { NStrongCryptoFlags::kTwofish, "Twofish" }, - { NStrongCryptoFlags::kRC4, "RC4" } + { NStrongCrypto_AlgId::kDES, "DES" }, + { NStrongCrypto_AlgId::kRC2old, "RC2a" }, + { NStrongCrypto_AlgId::k3DES168, "3DES-168" }, + { NStrongCrypto_AlgId::k3DES112, "3DES-112" }, + { NStrongCrypto_AlgId::kAES128, "pkAES-128" }, + { NStrongCrypto_AlgId::kAES192, "pkAES-192" }, + { NStrongCrypto_AlgId::kAES256, "pkAES-256" }, + { NStrongCrypto_AlgId::kRC2, "RC2" }, + { NStrongCrypto_AlgId::kBlowfish, "Blowfish" }, + { NStrongCrypto_AlgId::kTwofish, "Twofish" }, + { NStrongCrypto_AlgId::kRC4, "RC4" } }; -static const STATPROPSTG kProps[] = +const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id) +{ + for (unsigned i = 0; i < num; i++) + { + const CIdToNamePair &pair = pairs[i]; + if (id == pair.Id) + return pair.Name; + } + return NULL; +} + +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidATime, VT_FILETIME}, - { NULL, kpidAttrib, VT_UI4}, - // { NULL, kpidPosixAttrib, VT_UI4}, - { NULL, kpidEncrypted, VT_BOOL}, - { NULL, kpidComment, VT_BSTR}, - { NULL, kpidCRC, VT_UI4}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidHostOS, VT_BSTR}, - { NULL, kpidUnpackVer, VT_UI4} + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidAttrib, + // kpidPosixAttrib, + kpidEncrypted, + kpidComment, + kpidCRC, + kpidMethod, + kpidHostOS, + kpidUnpackVer }; -static const STATPROPSTG kArcProps[] = +static const Byte kArcProps[] = { - { NULL, kpidBit64, VT_BOOL}, - { NULL, kpidComment, VT_BSTR}, - { NULL, kpidPhySize, VT_UI8}, - { NULL, kpidOffset, VT_UI8} + kpidEmbeddedStubSize, + kpidBit64, + kpidComment }; CHandler::CHandler() @@ -142,12 +156,12 @@ CHandler::CHandler() static AString BytesToString(const CByteBuffer &data) { AString s; - int size = (int)data.GetCapacity(); + unsigned size = (unsigned)data.Size(); if (size > 0) { - char *p = s.GetBuffer(size + 1); + char *p = s.GetBuffer(size); memcpy(p, (const Byte *)data, size); - p[size] = '\0'; + p[size] = 0; s.ReleaseBuffer(); } return s; @@ -160,13 +174,52 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN NWindows::NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break; - case kpidComment: prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break; + case kpidComment: if (m_Archive.ArcInfo.Comment.Size() != 0) prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break; case kpidPhySize: prop = m_Archive.ArcInfo.GetPhySize(); break; - case kpidOffset: if (m_Archive.ArcInfo.StartPosition != 0) prop = m_Archive.ArcInfo.StartPosition; break; - case kpidError: if (!m_Archive.IsOkHeaders) prop = "Incorrect headers"; break; + case kpidOffset: /* if (m_Archive.ArcInfo.Base != 0) */ + prop = m_Archive.ArcInfo.Base; break; + + case kpidEmbeddedStubSize: + { + UInt64 stubSize = m_Archive.ArcInfo.GetEmbeddedStubSize(); + if (stubSize != 0) + prop = stubSize; + break; + } + + case kpidWarningFlags: + { + UInt32 v = 0; + // if (m_Archive.ExtraMinorError) v |= kpv_ErrorFlags_HeadersError; + if (m_Archive.HeadersWarning) v |= kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!m_Archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; + if (m_Archive.HeadersError) v |= kpv_ErrorFlags_HeadersError; + if (m_Archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + if (m_Archive.ArcInfo.Base < 0) + { + /* We try to support case when we have sfx-zip with embedded stub, + but the stream has access only to zip part. + In that case we ignore UnavailableStart error. + maybe we must show warning in that case. */ + UInt64 stubSize = m_Archive.ArcInfo.GetEmbeddedStubSize(); + if (stubSize < (UInt64)-m_Archive.ArcInfo.Base) + v |= kpv_ErrorFlags_UnavailableStart; + } + if (m_Archive.NoCentralDir) v |= kpv_ErrorFlags_UnconfirmedStart; + prop = v; + break; + } } prop.Detach(value); COM_TRY_END @@ -184,24 +237,36 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_BEGIN NWindows::NCOM::CPropVariant prop; const CItemEx &item = m_Items[index]; - switch(propID) + switch (propID) { - case kpidPath: prop = NItemName::GetOSName2(item.GetUnicodeString(item.Name)); break; + case kpidPath: + { + UString res; + item.GetUnicodeString(item.Name, res, _forceCodePage, _specifiedCodePage); + NItemName::ConvertToOSName2(res); + prop = res; + break; + } + case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: prop = item.UnPackSize; break; + case kpidSize: prop = item.Size; break; case kpidPackSize: prop = item.PackSize; break; + case kpidTimeType: { FILETIME ft; UInt32 unixTime; + UInt32 type; if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft)) - prop = (UInt32)NFileTimeType::kWindows; + type = NFileTimeType::kWindows; else if (item.CentralExtra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) - prop = (UInt32)NFileTimeType::kUnix; + type = NFileTimeType::kUnix; else - prop = (UInt32)NFileTimeType::kDOS; + type = NFileTimeType::kDOS; + prop = type; break; } + case kpidCTime: { FILETIME ft; @@ -209,6 +274,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = ft; break; } + case kpidATime: { FILETIME ft; @@ -216,26 +282,33 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = ft; break; } + case kpidMTime: { FILETIME utc; + bool defined = true; if (!item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc)) { - UInt32 unixTime; + UInt32 unixTime = 0; if (item.CentralExtra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) NTime::UnixTimeToFileTime(unixTime, utc); else { FILETIME localFileTime; - if (!NTime::DosTimeToFileTime(item.Time, localFileTime) || + if (item.Time == 0) + defined = false; + else if (!NTime::DosTimeToFileTime(item.Time, localFileTime) || !LocalFileTimeToFileTime(&localFileTime, &utc)) utc.dwHighDateTime = utc.dwLowDateTime = 0; } } - prop = utc; + if (defined) + prop = utc; break; } + case kpidAttrib: prop = item.GetWinAttrib(); break; + case kpidPosixAttrib: { UInt32 attrib; @@ -243,83 +316,107 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = attrib; break; } + case kpidEncrypted: prop = item.IsEncrypted(); break; - case kpidComment: prop = item.GetUnicodeString(BytesToString(item.Comment)); break; - case kpidCRC: if (item.IsThereCrc()) prop = item.FileCRC; break; + + case kpidComment: + { + if (item.Comment.Size() != 0) + { + UString res; + item.GetUnicodeString(BytesToString(item.Comment), res, _forceCodePage, _specifiedCodePage); + prop = res; + } + break; + } + + case kpidCRC: if (item.IsThereCrc()) prop = item.Crc; break; + case kpidMethod: { - UInt16 methodId = item.CompressionMethod; - AString method; + UInt16 methodId = item.Method; + AString m; + if (item.IsEncrypted()) { if (methodId == NFileHeader::NCompressionMethod::kWzAES) { - method = kAESMethod; - CWzAesExtraField aesField; - if (item.CentralExtra.GetWzAesField(aesField)) + m += kMethod_AES; + CWzAesExtra aesField; + if (item.CentralExtra.GetWzAes(aesField)) { - method += '-'; - char s[32]; - ConvertUInt64ToString((aesField.Strength + 1) * 64 , s); - method += s; - method += ' '; + char s[16]; + s[0] = '-'; + ConvertUInt32ToString(((unsigned)aesField.Strength + 1) * 64 , s + 1); + m += s; methodId = aesField.Method; } } - else + else if (item.IsStrongEncrypted()) { - if (item.IsStrongEncrypted()) + CStrongCryptoExtra f; + f.AlgId = 0; + if (item.CentralExtra.GetStrongCrypto(f)) { - CStrongCryptoField f; - bool finded = false; - if (item.CentralExtra.GetStrongCryptoField(f)) + const char *s = FindNameForId(k_StrongCryptoPairs, ARRAY_SIZE(k_StrongCryptoPairs), f.AlgId); + if (s) + m += s; + else { - for (int i = 0; i < sizeof(g_StrongCryptoPairs) / sizeof(g_StrongCryptoPairs[0]); i++) - { - const CStrongCryptoPair &pair = g_StrongCryptoPairs[i]; - if (f.AlgId == pair.Id) - { - method += pair.Name; - finded = true; - break; - } - } + m += kMethod_StrongCrypto; + char temp[16]; + temp[0] = ':'; + ConvertUInt32ToString(f.AlgId, temp + 1); + m += temp; } - if (!finded) - method += kStrongCryptoMethod; } else - method += kZipCryptoMethod; - method += ' '; + m += kMethod_StrongCrypto; } + else + m += kMethod_ZipCrypto; + m += ' '; } - if (methodId < sizeof(kMethods) / sizeof(kMethods[0])) - method += kMethods[methodId]; - else switch (methodId) + { - case NFileHeader::NCompressionMethod::kLZMA: - method += kLZMAMethod; - if (item.IsLzmaEOS()) - method += ":EOS"; - break; - case NFileHeader::NCompressionMethod::kBZip2: method += kBZip2Method; break; - case NFileHeader::NCompressionMethod::kJpeg: method += kJpegMethod; break; - case NFileHeader::NCompressionMethod::kWavPack: method += kWavPackMethod; break; - case NFileHeader::NCompressionMethod::kPPMd: method += kPPMdMethod; break; - default: + char temp[16]; + const char *s = NULL; + if (methodId < ARRAY_SIZE(kMethods)) + s = kMethods[methodId]; + else { - char s[32]; - ConvertUInt64ToString(methodId, s); - method += s; + s = FindNameForId(k_MethodIdNamePairs, ARRAY_SIZE(k_MethodIdNamePairs), methodId); + if (!s) + { + ConvertUInt32ToString(methodId, temp); + s = temp; + } } + m += s; + if (methodId == NFileHeader::NCompressionMethod::kLZMA && item.IsLzmaEOS()) + m += ":EOS"; } - prop = method; + + prop = m; break; } + case kpidHostOS: - prop = (item.MadeByVersion.HostOS < sizeof(kHostOS) / sizeof(kHostOS[0])) ? - (kHostOS[item.MadeByVersion.HostOS]) : kUnknownOS; + { + Byte hostOS = item.GetHostOS(); + char temp[16]; + const char *s = NULL; + if (hostOS < ARRAY_SIZE(kHostOS)) + s = kHostOS[hostOS]; + else + { + ConvertUInt32ToString(hostOS, temp); + s = temp; + } + prop = s; break; + } + case kpidUnpackVer: prop = (UInt32)item.ExtractVersion.Version; break; @@ -333,23 +430,25 @@ class CProgressImp: public CProgressVirt { CMyComPtr<IArchiveOpenCallback> _callback; public: - STDMETHOD(SetTotal)(UInt64 numFiles); - STDMETHOD(SetCompleted)(UInt64 numFiles); + virtual HRESULT SetCompletedLocal(UInt64 numFiles, UInt64 numBytes); + virtual HRESULT SetTotalCD(UInt64 numFiles); + virtual HRESULT SetCompletedCD(UInt64 numFiles); CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {} }; -STDMETHODIMP CProgressImp::SetTotal(UInt64 numFiles) +HRESULT CProgressImp::SetCompletedLocal(UInt64 numFiles, UInt64 numBytes) { - if (_callback) - return _callback->SetTotal(&numFiles, NULL); - return S_OK; + return _callback->SetCompleted(&numFiles, &numBytes); } -STDMETHODIMP CProgressImp::SetCompleted(UInt64 numFiles) +HRESULT CProgressImp::SetTotalCD(UInt64 numFiles) { - if (_callback) - return _callback->SetCompleted(&numFiles, NULL); - return S_OK; + return _callback->SetTotal(&numFiles, NULL); +} + +HRESULT CProgressImp::SetCompletedCD(UInt64 numFiles) +{ + return _callback->SetCompleted(&numFiles, NULL); } STDMETHODIMP CHandler::Open(IInStream *inStream, @@ -359,12 +458,10 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, try { Close(); - RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); RINOK(m_Archive.Open(inStream, maxCheckStartPosition)); CProgressImp progressImp(callback); - return m_Archive.ReadHeaders(m_Items, &progressImp); + return m_Archive.ReadHeaders(m_Items, callback ? &progressImp : NULL); } - catch(const CInArchiveException &) { Close(); return S_FALSE; } catch(...) { Close(); throw; } COM_TRY_END } @@ -467,26 +564,26 @@ HRESULT CZipDecoder::Decode( bool needCRC = true; bool wzAesMode = false; bool pkAesMode = false; - UInt16 methodId = item.CompressionMethod; + UInt16 methodId = item.Method; if (item.IsEncrypted()) { if (item.IsStrongEncrypted()) { - CStrongCryptoField f; - if (item.CentralExtra.GetStrongCryptoField(f)) + CStrongCryptoExtra f; + if (item.CentralExtra.GetStrongCrypto(f)) { pkAesMode = true; } if (!pkAesMode) { - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; return S_OK; } } - if (methodId == NFileHeader::NCompressionMethod::kWzAES) + if (!pkAesMode && methodId == NFileHeader::NCompressionMethod::kWzAES) { - CWzAesExtraField aesField; - if (item.CentralExtra.GetWzAesField(aesField)) + CWzAesExtra aesField; + if (item.CentralExtra.GetWzAes(aesField)) { wzAesMode = true; needCRC = aesField.NeedCrc(); @@ -520,8 +617,8 @@ HRESULT CZipDecoder::Decode( { if (wzAesMode) { - CWzAesExtraField aesField; - if (!item.CentralExtra.GetWzAesField(aesField)) + CWzAesExtra aesField; + if (!item.CentralExtra.GetWzAes(aesField)) return S_OK; methodId = aesField.Method; if (!_wzAesDecoder) @@ -562,31 +659,35 @@ HRESULT CZipDecoder::Decode( CMyComBSTR password; RINOK(getTextPassword->CryptoGetTextPassword(&password)); AString charPassword; - if (wzAesMode || pkAesMode) + if (password) { - charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP); - /* - for (int i = 0;; i++) + if (wzAesMode || pkAesMode) { - wchar_t c = password[i]; - if (c == 0) - break; - if (c >= 0x80) + charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP); + /* + for (unsigned i = 0;; i++) { - res = NExtract::NOperationResult::kDataError; - return S_OK; + wchar_t c = password[i]; + if (c == 0) + break; + if (c >= 0x80) + { + res = NExtract::NOperationResult::kDataError; + return S_OK; + } + charPassword += (char)c; } - 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); } - */ - } - else - { - // we use OEM. WinZip/Windows probably use ANSI for some files - charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP); } HRESULT result = cryptoSetPassword->CryptoSetPassword( - (const Byte *)(const char *)charPassword, charPassword.Length()); + (const Byte *)(const char *)charPassword, charPassword.Len()); if (result != S_OK) return S_OK; } @@ -596,7 +697,7 @@ HRESULT CZipDecoder::Decode( } } - int m; + unsigned m; for (m = 0; m < methodItems.Size(); m++) if (methodItems[m].ZipMethod == methodId) break; @@ -624,7 +725,7 @@ HRESULT CZipDecoder::Decode( { if (methodId > 0xFF) { - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; return S_OK; } szMethodID = kMethodId_ZipBase + (Byte)methodId; @@ -634,7 +735,7 @@ HRESULT CZipDecoder::Decode( if (mi.Coder == 0) { - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; return S_OK; } } @@ -680,7 +781,7 @@ HRESULT CZipDecoder::Decode( } else if (pkAesMode) { - result =_pkAesDecoderSpec->ReadHeader(inStream, item.FileCRC, item.UnPackSize); + result =_pkAesDecoderSpec->ReadHeader(inStream, item.Crc, item.Size); if (result == S_OK) { bool passwOK; @@ -696,7 +797,16 @@ HRESULT CZipDecoder::Decode( if (result == S_OK) { - RINOK(filterStreamSpec->SetInStream(inStream)); + if (pkAesMode) + { + /* 9.31: The BUG in 9.24-9.30 was fixed. pkAes archives didn't work. + We don't need to call CAesCbcCoder::Init() to reset IV for data. */ + filterStreamSpec->SetInStream_NoSubFilterInit(inStream); + } + else + { + RINOK(filterStreamSpec->SetInStream(inStream)); + } inStreamReleaser.FilterCoder = filterStreamSpec; inStreamNew = filterStream; if (wzAesMode) @@ -709,12 +819,12 @@ HRESULT CZipDecoder::Decode( else inStreamNew = inStream; if (result == S_OK) - result = coder->Code(inStreamNew, outStream, NULL, &item.UnPackSize, compressProgress); + result = coder->Code(inStreamNew, outStream, NULL, &item.Size, compressProgress); if (result == S_FALSE) return S_OK; if (result == E_NOTIMPL) { - res = NExtract::NOperationResult::kUnSupportedMethod; + res = NExtract::NOperationResult::kUnsupportedMethod; return S_OK; } @@ -723,7 +833,7 @@ HRESULT CZipDecoder::Decode( bool crcOK = true; bool authOk = true; if (needCRC) - crcOK = (outStreamSpec->GetCRC() == item.FileCRC); + crcOK = (outStreamSpec->GetCRC() == item.Crc); if (wzAesMode) { inStream.Attach(archive.CreateLimitedStream(authenticationPos, NCrypto::NWzAes::kMacSize)); @@ -744,7 +854,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_BEGIN CZipDecoder myDecoder; UInt64 totalUnPacked = 0, totalPacked = 0; - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = m_Items.Size(); if(numItems == 0) @@ -753,7 +863,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, for (i = 0; i < numItems; i++) { const CItemEx &item = m_Items[allFilesMode ? i : indices[i]]; - totalUnPacked += item.UnPackSize; + totalUnPacked += item.Size; totalPacked += item.PackSize; } RINOK(extractCallback->SetTotal(totalUnPacked)); @@ -765,7 +875,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, false); - for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked, + for (i = 0; i < numItems; i++, + currentTotalUnPacked += currentItemUnPacked, currentTotalPacked += currentItemPacked) { currentItemUnPacked = 0; @@ -779,11 +890,26 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 askMode = testMode ? NExtract::NAskMode::kTest : NExtract::NAskMode::kExtract; - Int32 index = allFilesMode ? i : indices[i]; + UInt32 index = allFilesMode ? i : indices[i]; + + CItemEx item = m_Items[index]; + bool isLocalOffsetOK = m_Archive.IsLocalOffsetOK(item); + bool skip = !isLocalOffsetOK && !item.IsDir(); + if (skip) + askMode = NExtract::NAskMode::kSkip; + + currentItemUnPacked = item.Size; + currentItemPacked = item.PackSize; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - CItemEx item = m_Items[index]; + if (!isLocalOffsetOK) + { + RINOK(extractCallback->PrepareOperation(askMode)); + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnavailable)); + continue; + } if (!item.FromLocal) { HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item); @@ -793,14 +919,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { RINOK(extractCallback->PrepareOperation(askMode)); realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kHeadersError)); } continue; } RINOK(res); } - if (item.IsDir() || item.IgnoreItem()) + if (item.IsDir()) { // if (!testMode) { @@ -811,9 +937,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; } - currentItemUnPacked = item.UnPackSize; - currentItemPacked = item.PackSize; - if (!testMode && !realOutStream) continue; diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h index 33cf6fdc..7f1d2eba 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.h +++ b/CPP/7zip/Archive/Zip/ZipHandler.h @@ -3,7 +3,7 @@ #ifndef __ZIP_HANDLER_H #define __ZIP_HANDLER_H -#include "Common/DynamicBuffer.h" +#include "../../../Common/DynamicBuffer.h" #include "../../ICoder.h" #include "../IArchive.h" @@ -33,7 +33,7 @@ public: INTERFACE_IInArchive(;) INTERFACE_IOutArchive(;) - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties); + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); DECL_ISetCompressCodecsInfo @@ -47,8 +47,11 @@ private: int m_MainMethod; bool m_ForceAesMode; bool m_WriteNtfsTimeExtra; + bool _removeSfxBlock; bool m_ForceLocal; bool m_ForceUtf8; + bool _forceCodePage; + UInt32 _specifiedCodePage; DECL_EXTERNAL_CODECS_VARS @@ -58,8 +61,11 @@ private: m_MainMethod = -1; m_ForceAesMode = false; m_WriteNtfsTimeExtra = true; + _removeSfxBlock = false; m_ForceLocal = false; m_ForceUtf8 = false; + _forceCodePage = false; + _specifiedCodePage = CP_OEMCP; } }; diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp index dd1ca136..ae58cbe2 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp @@ -2,12 +2,12 @@ #include "StdAfx.h" -#include "Common/ComTry.h" -#include "Common/StringConvert.h" -#include "Common/StringToInt.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" #include "../../IPassword.h" @@ -36,7 +36,7 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) static bool IsAsciiString(const UString &s) { - for (int i = 0; i < s.Length(); i++) + for (unsigned i = 0; i < s.Len(); i++) { wchar_t c = s[i]; if (c < 0x20 || c > 0x7F) @@ -66,40 +66,48 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt IArchiveUpdateCallback *callback) { COM_TRY_BEGIN2 + + if (m_Archive.IsOpen()) + { + if (!m_Archive.CanUpdate()) + return E_NOTIMPL; + } + CObjectVector<CUpdateItem> updateItems; bool thereAreAesUpdates = false; UInt64 largestSize = 0; bool largestSizeDefined = false; + for (UInt32 i = 0; i < numItems; i++) { CUpdateItem ui; Int32 newData; - Int32 newProperties; + Int32 newProps; UInt32 indexInArchive; if (!callback) return E_FAIL; - RINOK(callback->GetUpdateItemInfo(i, &newData, &newProperties, &indexInArchive)); - ui.NewProperties = IntToBool(newProperties); + RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); + ui.NewProps = IntToBool(newProps); ui.NewData = IntToBool(newData); - ui.IndexInArchive = indexInArchive; + ui.IndexInArc = indexInArchive; ui.IndexInClient = i; - bool existInArchive = (indexInArchive != (UInt32)-1); + bool existInArchive = (indexInArchive != (UInt32)(Int32)-1); if (existInArchive && newData) if (m_Items[indexInArchive].IsAesEncrypted()) thereAreAesUpdates = true; - if (IntToBool(newProperties)) + if (IntToBool(newProps)) { UString name; { NCOM::CPropVariant prop; RINOK(callback->GetProperty(i, kpidAttrib, &prop)); if (prop.vt == VT_EMPTY) - ui.Attributes = 0; + ui.Attrib = 0; else if (prop.vt != VT_UI4) return E_INVALIDARG; else - ui.Attributes = prop.ulVal; + ui.Attrib = prop.ulVal; } { @@ -131,15 +139,15 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt else ui.NtfsTimeIsDefined = m_WriteNtfsTimeExtra; } - RINOK(GetTime(callback, i, kpidMTime, ui.NtfsMTime)); - RINOK(GetTime(callback, i, kpidATime, ui.NtfsATime)); - RINOK(GetTime(callback, i, kpidCTime, ui.NtfsCTime)); + RINOK(GetTime(callback, i, kpidMTime, ui.Ntfs_MTime)); + RINOK(GetTime(callback, i, kpidATime, ui.Ntfs_ATime)); + RINOK(GetTime(callback, i, kpidCTime, ui.Ntfs_CTime)); { FILETIME localFileTime = { 0, 0 }; - if (ui.NtfsMTime.dwHighDateTime != 0 || - ui.NtfsMTime.dwLowDateTime != 0) - if (!FileTimeToLocalFileTime(&ui.NtfsMTime, &localFileTime)) + if (ui.Ntfs_MTime.dwHighDateTime != 0 || + ui.Ntfs_MTime.dwLowDateTime != 0) + if (!FileTimeToLocalFileTime(&ui.Ntfs_MTime, &localFileTime)) return E_INVALIDARG; FileTimeToDosTime(localFileTime, ui.Time); } @@ -159,25 +167,27 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (needSlash) name += kSlash; + UINT codePage = _forceCodePage ? _specifiedCodePage : CP_OEMCP; + bool tryUtf8 = true; - if (m_ForceLocal || !m_ForceUtf8) + if ((m_ForceLocal || !m_ForceUtf8) && codePage != CP_UTF8) { bool defaultCharWasUsed; - ui.Name = UnicodeStringToMultiByte(name, CP_OEMCP, '_', defaultCharWasUsed); + ui.Name = UnicodeStringToMultiByte(name, codePage, '_', defaultCharWasUsed); tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed || - MultiByteToUnicodeString(ui.Name, CP_OEMCP) != name)); + MultiByteToUnicodeString(ui.Name, codePage) != name)); } if (tryUtf8) { - int i; - for (i = 0; i < name.Length() && (unsigned)name[i] < 0x80; i++); - ui.IsUtf8 = (i != name.Length()); + unsigned i; + for (i = 0; i < name.Len() && (unsigned)name[i] < 0x80; i++); + ui.IsUtf8 = (i != name.Len()); if (!ConvertUnicodeToUTF8(name, ui.Name)) return E_INVALIDARG; } - if (ui.Name.Length() >= (1 << 16)) + if (ui.Name.Len() >= (1 << 16)) return E_INVALIDARG; ui.IndexInClient = i; @@ -211,6 +221,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt largestSizeDefined = true; } ui.Size = size; + // ui.Size -= ui.Size / 2; } updateItems.Add(ui); } @@ -225,6 +236,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt options._dataSizeReduce = largestSize; options._dataSizeReduceDefined = largestSizeDefined; + options.PasswordIsDefined = false; + options.Password.Empty(); if (getTextPassword) { CMyComBSTR password; @@ -236,18 +249,17 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (!m_ForceAesMode) options.IsAesMode = thereAreAesUpdates; - if (!IsAsciiString((const wchar_t *)password)) + if (!IsAsciiString((BSTR)password)) return E_INVALIDARG; + if (password) + options.Password = UnicodeStringToMultiByte((BSTR)password, CP_OEMCP); if (options.IsAesMode) { - if (options.Password.Length() > NCrypto::NWzAes::kPasswordSizeMax) + if (options.Password.Len() > NCrypto::NWzAes::kPasswordSizeMax) return E_INVALIDARG; } - options.Password = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP); } } - else - options.PasswordIsDefined = false; Byte mainMethod; if (m_MainMethod < 0) @@ -263,68 +275,68 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return Update( EXTERNAL_CODECS_VARS m_Items, updateItems, outStream, - m_Archive.IsOpen() ? &m_Archive : NULL, &options, callback); + m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock, + &options, callback); + COM_TRY_END2 } struct CMethodIndexToName { unsigned Method; - const wchar_t *Name; + const char *Name; }; static const CMethodIndexToName k_SupportedMethods[] = { - { NFileHeader::NCompressionMethod::kStored, L"COPY" }, - { NFileHeader::NCompressionMethod::kDeflated, L"DEFLATE" }, - { NFileHeader::NCompressionMethod::kDeflated64, L"DEFLATE64" }, - { NFileHeader::NCompressionMethod::kBZip2, L"BZIP2" }, - { NFileHeader::NCompressionMethod::kLZMA, L"LZMA" }, - { NFileHeader::NCompressionMethod::kPPMd, L"PPMD" } + { NFileHeader::NCompressionMethod::kStored, "copy" }, + { NFileHeader::NCompressionMethod::kDeflated, "deflate" }, + { NFileHeader::NCompressionMethod::kDeflated64, "deflate64" }, + { NFileHeader::NCompressionMethod::kBZip2, "bzip2" }, + { NFileHeader::NCompressionMethod::kLZMA, "lzma" }, + { NFileHeader::NCompressionMethod::kPPMd, "ppmd" } }; -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) - -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) { InitMethodProps(); #ifndef _7ZIP_ST const UInt32 numProcessors = _props.NumThreads; #endif - for (int i = 0; i < numProps; i++) + for (UInt32 i = 0; i < numProps; i++) { UString name = names[i]; - name.MakeUpper(); + name.MakeLower_Ascii(); if (name.IsEmpty()) return E_INVALIDARG; const PROPVARIANT &prop = values[i]; - if (name[0] == L'X') + if (name[0] == L'x') { UInt32 level = 9; - RINOK(ParsePropToUInt32(name.Mid(1), prop, level)); + RINOK(ParsePropToUInt32(name.Ptr(1), prop, level)); _props.Level = level; _props.MethodInfo.AddLevelProp(level); } - else if (name == L"M") + else if (name == L"m") { if (prop.vt == VT_BSTR) { UString m = prop.bstrVal, m2; - m.MakeUpper(); + m.MakeLower_Ascii(); int colonPos = m.Find(L':'); if (colonPos >= 0) { - m2 = m.Mid(colonPos + 1); - m = m.Left(colonPos); + m2 = m.Ptr(colonPos + 1); + m.DeleteFrom(colonPos); } - int k; + unsigned k; for (k = 0; k < ARRAY_SIZE(k_SupportedMethods); k++) { const CMethodIndexToName &pair = k_SupportedMethods[k]; - if (m == pair.Name) + if (m.IsEqualTo(pair.Name)) { if (!m2.IsEmpty()) { @@ -339,7 +351,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v } else if (prop.vt == VT_UI4) { - int k; + unsigned k; for (k = 0; k < ARRAY_SIZE(k_SupportedMethods); k++) { unsigned method = k_SupportedMethods[k].Method; @@ -355,16 +367,16 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v else return E_INVALIDARG; } - else if (name.Left(2) == L"EM") + else if (name.IsPrefixedBy(L"em")) { if (prop.vt != VT_BSTR) return E_INVALIDARG; { UString m = prop.bstrVal; - m.MakeUpper(); - if (m.Left(3) == L"AES") + m.MakeLower_Ascii(); + if (m.IsPrefixedBy(L"aes")) { - m = m.Mid(3); + m.DeleteFrontal(3); if (m == L"128") _props.AesKeyMode = 1; else if (m == L"192") @@ -376,7 +388,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v _props.IsAesMode = true; m_ForceAesMode = true; } - else if (m == L"ZIPCRYPTO") + else if (m == L"zipcrypto") { _props.IsAesMode = false; m_ForceAesMode = true; @@ -385,29 +397,40 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v return E_INVALIDARG; } } - else if (name.Left(2) == L"MT") + else if (name.IsPrefixedBy(L"mt")) { #ifndef _7ZIP_ST - RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _props.NumThreads)); + RINOK(ParseMtProp(name.Ptr(2), prop, numProcessors, _props.NumThreads)); _props.NumThreadsWasChanged = true; #endif } - else if (name.CompareNoCase(L"TC") == 0) + else if (name.IsEqualTo("tc")) { RINOK(PROPVARIANT_to_bool(prop, m_WriteNtfsTimeExtra)); } - else if (name.CompareNoCase(L"CL") == 0) + else if (name.IsEqualTo("cl")) { RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal)); if (m_ForceLocal) m_ForceUtf8 = false; } - else if (name.CompareNoCase(L"CU") == 0) + else if (name.IsEqualTo("cu")) { RINOK(PROPVARIANT_to_bool(prop, m_ForceUtf8)); if (m_ForceUtf8) m_ForceLocal = false; } + else if (name.IsEqualTo("cp")) + { + UInt32 cp = CP_OEMCP; + RINOK(ParsePropToUInt32(L"", prop, cp)); + _forceCodePage = true; + _specifiedCodePage = cp; + } + else if (name.IsEqualTo("rsfx")) + { + RINOK(PROPVARIANT_to_bool(prop, _removeSfxBlock)); + } else { RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop)); diff --git a/CPP/7zip/Archive/Zip/ZipHeader.cpp b/CPP/7zip/Archive/Zip/ZipHeader.cpp deleted file mode 100755 index 582187b5..00000000 --- a/CPP/7zip/Archive/Zip/ZipHeader.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Archive/Zip/Header.h - -#include "StdAfx.h" - -#include "ZipHeader.h" - -namespace NArchive { -namespace NZip { - -namespace NSignature -{ - UInt32 kLocalFileHeader = 0x04034B50 + 1; - UInt32 kDataDescriptor = 0x08074B50 + 1; - UInt32 kCentralFileHeader = 0x02014B50 + 1; - UInt32 kEndOfCentralDir = 0x06054B50 + 1; - UInt32 kZip64EndOfCentralDir = 0x06064B50 + 1; - UInt32 kZip64EndOfCentralDirLocator = 0x07064B50 + 1; - - class CMarkersInitializer - { - public: - CMarkersInitializer() - { - kLocalFileHeader--; - kDataDescriptor--; - kCentralFileHeader--; - kEndOfCentralDir--; - kZip64EndOfCentralDir--; - kZip64EndOfCentralDirLocator--; - } - }; - static CMarkersInitializer g_MarkerInitializer; -} - -}} - diff --git a/CPP/7zip/Archive/Zip/ZipHeader.h b/CPP/7zip/Archive/Zip/ZipHeader.h index ce8c1e4f..1391cdf4 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipHeader.h +++ b/CPP/7zip/Archive/Zip/ZipHeader.h @@ -1,57 +1,39 @@ -// Archive/Zip/Header.h +// ZipHeader.h #ifndef __ARCHIVE_ZIP_HEADER_H #define __ARCHIVE_ZIP_HEADER_H -#include "Common/Types.h" +#include "../../../Common/MyTypes.h" namespace NArchive { namespace NZip { +const unsigned kMarkerSize = 4; + namespace NSignature { - extern UInt32 kLocalFileHeader; - extern UInt32 kDataDescriptor; - extern UInt32 kCentralFileHeader; - extern UInt32 kEndOfCentralDir; - extern UInt32 kZip64EndOfCentralDir; - extern UInt32 kZip64EndOfCentralDirLocator; - - static const UInt32 kMarkerSize = 4; + const UInt32 kLocalFileHeader = 0x04034B50; + const UInt32 kDataDescriptor = 0x08074B50; + const UInt32 kCentralFileHeader = 0x02014B50; + const UInt32 kEcd = 0x06054B50; + const UInt32 kEcd64 = 0x06064B50; + const UInt32 kEcd64Locator = 0x07064B50; + + // const UInt32 kSpan = 0x08074B50; + const UInt32 kNoSpan = 0x30304b50; // PK00, replaces kSpan, if there is only 1 segment } -const UInt32 kEcdSize = 22; -const UInt32 kZip64EcdSize = 44; -const UInt32 kZip64EcdLocatorSize = 20; -/* -struct CEndOfCentralDirectoryRecord -{ - UInt16 ThisDiskNumber; - UInt16 StartCentralDirectoryDiskNumber; - UInt16 NumEntriesInCentaralDirectoryOnThisDisk; - UInt16 NumEntriesInCentaralDirectory; - UInt32 CentralDirectorySize; - UInt32 CentralDirectoryStartOffset; - UInt16 CommentSize; -}; +const unsigned kLocalHeaderSize = 4 + 26; // including signature +const unsigned kDataDescriptorSize = 4 + 12; // including signature +const unsigned kCentralHeaderSize = 4 + 42; // including signature -struct CEndOfCentralDirectoryRecordFull -{ - UInt32 Signature; - CEndOfCentralDirectoryRecord Header; -}; -*/ +const unsigned kEcdSize = 22; // including signature +const unsigned kEcd64_MainSize = 44; +const unsigned kEcd64_FullSize = 12 + kEcd64_MainSize; +const unsigned kEcd64Locator_Size = 20; namespace NFileHeader { - /* - struct CVersion - { - Byte Version; - Byte HostOS; - }; - */ - namespace NCompressionMethod { enum EType @@ -77,7 +59,7 @@ namespace NFileHeader kPPMd = 0x62, kWzAES = 0x63 }; - const int kNumCompressionMethods = 11; + const Byte kMadeByProgramVersion = 63; const Byte kExtractVersion_Default = 10; @@ -90,8 +72,6 @@ namespace NFileHeader const Byte kExtractVersion_Aes = 51; const Byte kExtractVersion_LZMA = 63; const Byte kExtractVersion_PPMd = 63; - - // const Byte kSupportedVersion = 20; } namespace NExtraID @@ -127,155 +107,93 @@ namespace NFileHeader }; } - const UInt32 kLocalBlockSize = 26; - /* - struct CLocalBlock - { - CVersion ExtractVersion; - - UInt16 Flags; - UInt16 CompressionMethod; - UInt32 Time; - UInt32 FileCRC; - UInt32 PackSize; - UInt32 UnPackSize; - UInt16 NameSize; - UInt16 ExtraSize; - }; - */ - - const UInt32 kDataDescriptorSize = 16; - // const UInt32 kDataDescriptor64Size = 16 + 8; - /* - struct CDataDescriptor - { - UInt32 Signature; - UInt32 FileCRC; - UInt32 PackSize; - UInt32 UnPackSize; - }; - - struct CLocalBlockFull - { - UInt32 Signature; - CLocalBlock Header; - }; - */ - - const UInt32 kCentralBlockSize = 42; - /* - struct CBlock - { - CVersion MadeByVersion; - CVersion ExtractVersion; - UInt16 Flags; - UInt16 CompressionMethod; - UInt32 Time; - UInt32 FileCRC; - UInt32 PackSize; - UInt32 UnPackSize; - UInt16 NameSize; - UInt16 ExtraSize; - UInt16 CommentSize; - UInt16 DiskNumberStart; - UInt16 InternalAttributes; - UInt32 ExternalAttributes; - UInt32 LocalHeaderOffset; - }; - - struct CBlockFull - { - UInt32 Signature; - CBlock Header; - }; - */ - namespace NFlags { - const int kEncrypted = 1 << 0; - const int kLzmaEOS = 1 << 1; - const int kDescriptorUsedMask = 1 << 3; - const int kStrongEncrypted = 1 << 6; - const int kUtf8 = 1 << 11; - - const int kImplodeDictionarySizeMask = 1 << 1; - const int kImplodeLiteralsOnMask = 1 << 2; + const unsigned kEncrypted = 1 << 0; + const unsigned kLzmaEOS = 1 << 1; + const unsigned kDescriptorUsedMask = 1 << 3; + const unsigned kStrongEncrypted = 1 << 6; + const unsigned kUtf8 = 1 << 11; + + const unsigned kImplodeDictionarySizeMask = 1 << 1; + const unsigned kImplodeLiteralsOnMask = 1 << 2; - const int kDeflateTypeBitStart = 1; - const int kNumDeflateTypeBits = 2; - const int kNumDeflateTypes = (1 << kNumDeflateTypeBits); - const int kDeflateTypeMask = (1 << kNumDeflateTypeBits) - 1; + const unsigned kDeflateTypeBitStart = 1; + const unsigned kNumDeflateTypeBits = 2; + const unsigned kNumDeflateTypes = (1 << kNumDeflateTypeBits); + const unsigned kDeflateTypeMask = (1 << kNumDeflateTypeBits) - 1; } namespace NHostOS { enum EEnum { - kFAT = 0, - kAMIGA = 1, - kVMS = 2, // VAX/VMS - kUnix = 3, - kVM_CMS = 4, - kAtari = 5, // what if it's a minix filesystem? [cjh] - kHPFS = 6, // filesystem used by OS/2 (and NT 3.x) - kMac = 7, - kZ_System = 8, - kCPM = 9, - kTOPS20 = 10, // pkzip 2.50 NTFS - kNTFS = 11, // filesystem used by Windows NT - kQDOS = 12, // SMS/QDOS - kAcorn = 13, // Archimedes Acorn RISC OS - kVFAT = 14, // filesystem used by Windows 95, NT - kMVS = 15, - kBeOS = 16, // hybrid POSIX/database filesystem - kTandem = 17, - kOS400 = 18, - kOSX = 19 + kFAT = 0, + kAMIGA = 1, + kVMS = 2, // VAX/VMS + kUnix = 3, + kVM_CMS = 4, + kAtari = 5, // what if it's a minix filesystem? [cjh] + kHPFS = 6, // filesystem used by OS/2 (and NT 3.x) + kMac = 7, + kZ_System = 8, + kCPM = 9, + kTOPS20 = 10, // pkzip 2.50 NTFS + kNTFS = 11, // filesystem used by Windows NT + kQDOS = 12, // SMS/QDOS + kAcorn = 13, // Archimedes Acorn RISC OS + kVFAT = 14, // filesystem used by Windows 95, NT + kMVS = 15, + kBeOS = 16, // hybrid POSIX/database filesystem + kTandem = 17, + kOS400 = 18, + kOSX = 19 }; } - namespace NUnixAttribute + + namespace NUnixAttrib { - const UInt32 kIFMT = 0170000; /* Unix file type mask */ + const UInt32 kIFMT = 0170000; // file type mask - const UInt32 kIFDIR = 0040000; /* Unix directory */ - const UInt32 kIFREG = 0100000; /* Unix regular file */ - const UInt32 kIFSOCK = 0140000; /* Unix socket (BSD, not SysV or Amiga) */ - const UInt32 kIFLNK = 0120000; /* Unix symbolic link (not SysV, Amiga) */ - const UInt32 kIFBLK = 0060000; /* Unix block special (not Amiga) */ - const UInt32 kIFCHR = 0020000; /* Unix character special (not Amiga) */ - const UInt32 kIFIFO = 0010000; /* Unix fifo (BCC, not MSC or Amiga) */ + const UInt32 kIFDIR = 0040000; // directory + const UInt32 kIFREG = 0100000; // regular file + const UInt32 kIFSOCK = 0140000; // socket (BSD, not SysV or Amiga) + const UInt32 kIFLNK = 0120000; // symbolic link (not SysV, Amiga) + const UInt32 kIFBLK = 0060000; // block special (not Amiga) + const UInt32 kIFCHR = 0020000; // character special (not Amiga) + const UInt32 kIFIFO = 0010000; // fifo (BCC, not MSC or Amiga) - const UInt32 kISUID = 04000; /* Unix set user id on execution */ - const UInt32 kISGID = 02000; /* Unix set group id on execution */ - const UInt32 kISVTX = 01000; /* Unix directory permissions control */ - const UInt32 kENFMT = kISGID; /* Unix record locking enforcement flag */ - const UInt32 kIRWXU = 00700; /* Unix read, write, execute: owner */ - const UInt32 kIRUSR = 00400; /* Unix read permission: owner */ - const UInt32 kIWUSR = 00200; /* Unix write permission: owner */ - const UInt32 kIXUSR = 00100; /* Unix execute permission: owner */ - const UInt32 kIRWXG = 00070; /* Unix read, write, execute: group */ - const UInt32 kIRGRP = 00040; /* Unix read permission: group */ - const UInt32 kIWGRP = 00020; /* Unix write permission: group */ - const UInt32 kIXGRP = 00010; /* Unix execute permission: group */ - const UInt32 kIRWXO = 00007; /* Unix read, write, execute: other */ - const UInt32 kIROTH = 00004; /* Unix read permission: other */ - const UInt32 kIWOTH = 00002; /* Unix write permission: other */ - const UInt32 kIXOTH = 00001; /* Unix execute permission: other */ + const UInt32 kISUID = 04000; // set user id on execution + const UInt32 kISGID = 02000; // set group id on execution + const UInt32 kISVTX = 01000; // directory permissions control + const UInt32 kENFMT = kISGID; // record locking enforcement flag + const UInt32 kIRWXU = 00700; // read, write, execute: owner + const UInt32 kIRUSR = 00400; // read permission: owner + const UInt32 kIWUSR = 00200; // write permission: owner + const UInt32 kIXUSR = 00100; // execute permission: owner + const UInt32 kIRWXG = 00070; // read, write, execute: group + const UInt32 kIRGRP = 00040; // read permission: group + const UInt32 kIWGRP = 00020; // write permission: group + const UInt32 kIXGRP = 00010; // execute permission: group + const UInt32 kIRWXO = 00007; // read, write, execute: other + const UInt32 kIROTH = 00004; // read permission: other + const UInt32 kIWOTH = 00002; // write permission: other + const UInt32 kIXOTH = 00001; // execute permission: other } - namespace NAmigaAttribute + namespace NAmigaAttrib { - const UInt32 kIFMT = 06000; /* Amiga file type mask */ - const UInt32 kIFDIR = 04000; /* Amiga directory */ - const UInt32 kIFREG = 02000; /* Amiga regular file */ - const UInt32 kIHIDDEN = 00200; /* to be supported in AmigaDOS 3.x */ - const UInt32 kISCRIPT = 00100; /* executable script (text command file) */ - const UInt32 kIPURE = 00040; /* allow loading into resident memory */ - const UInt32 kIARCHIVE = 00020; /* not modified since bit was last set */ - const UInt32 kIREAD = 00010; /* can be opened for reading */ - const UInt32 kIWRITE = 00004; /* can be opened for writing */ - const UInt32 kIEXECUTE = 00002; /* executable image, a loadable runfile */ - const UInt32 kIDELETE = 00001; /* can be deleted */ + const UInt32 kIFMT = 06000; // Amiga file type mask + const UInt32 kIFDIR = 04000; // Amiga directory + const UInt32 kIFREG = 02000; // Amiga regular file + const UInt32 kIHIDDEN = 00200; // to be supported in AmigaDOS 3.x + const UInt32 kISCRIPT = 00100; // executable script (text command file) + const UInt32 kIPURE = 00040; // allow loading into resident memory + const UInt32 kIARCHIVE = 00020; // not modified since bit was last set + const UInt32 kIREAD = 00010; // can be opened for reading + const UInt32 kIWRITE = 00004; // can be opened for writing + const UInt32 kIEXECUTE = 00002; // executable image, a loadable runfile + const UInt32 kIDELETE = 00001; // can be deleted } } diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index e930488f..345fbf56 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -2,13 +2,15 @@ #include "StdAfx.h" -#include "../../../../C/CpuArch.h" +// #include <stdio.h> -#include "Common/DynamicBuffer.h" +#include "../../../Common/DynamicBuffer.h" #include "../../Common/LimitedStreams.h" #include "../../Common/StreamUtils.h" +#include "../IArchive.h" + #include "ZipIn.h" #define Get16(p) GetUi16(p) @@ -17,100 +19,342 @@ namespace NArchive { namespace NZip { - + +struct CEcd +{ + UInt16 thisDiskNumber; + UInt16 startCDDiskNumber; + UInt16 numEntriesInCDOnThisDisk; + UInt16 numEntriesInCD; + UInt32 cdSize; + UInt32 cdStartOffset; + UInt16 commentSize; + + void Parse(const Byte *p); + + bool IsEmptyArc() + { + return thisDiskNumber == 0 && startCDDiskNumber == 0 && + numEntriesInCDOnThisDisk == 0 && numEntriesInCD == 0 && cdSize == 0 + && cdStartOffset == 0 // test it + ; + } +}; + +void CEcd::Parse(const Byte *p) +{ + thisDiskNumber = Get16(p); + startCDDiskNumber = Get16(p + 2); + numEntriesInCDOnThisDisk = Get16(p + 4); + numEntriesInCD = Get16(p + 6); + cdSize = Get32(p + 8); + cdStartOffset = Get32(p + 12); + commentSize = Get16(p + 16); +} + +struct CEcd64 +{ + UInt16 versionMade; + UInt16 versionNeedExtract; + UInt32 thisDiskNumber; + UInt32 startCDDiskNumber; + UInt64 numEntriesInCDOnThisDisk; + UInt64 numEntriesInCD; + UInt64 cdSize; + UInt64 cdStartOffset; + + void Parse(const Byte *p); + CEcd64() { memset(this, 0, sizeof(*this)); } +}; + +void CEcd64::Parse(const Byte *p) +{ + versionMade = Get16(p); + versionNeedExtract = Get16(p + 2); + thisDiskNumber = Get32(p + 4); + startCDDiskNumber = Get32(p + 8); + numEntriesInCDOnThisDisk = Get64(p + 12); + numEntriesInCD = Get64(p + 20); + cdSize = Get64(p + 28); + cdStartOffset = Get64(p + 36); +} + HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) { _inBufMode = false; Close(); - RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition)); - m_Position = m_StreamStartPosition; + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &m_Position)); + RINOK(stream->Seek(0, STREAM_SEEK_END, &ArcInfo.FileEndPos)); + RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); + + // printf("\nOpen offset = %d", (int)m_Position); RINOK(FindAndReadMarker(stream, searchHeaderSizeLimit)); RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); - m_Stream = stream; + Stream = stream; return S_OK; } void CInArchive::Close() { - _inBuffer.ReleaseStream(); - m_Stream.Release(); + IsArc = false; + HeadersError = false; + HeadersWarning = false; + ExtraMinorError = false; + UnexpectedEnd = false; + NoCentralDir = false; + IsZip64 = false; + Stream.Release(); } HRESULT CInArchive::Seek(UInt64 offset) { - return m_Stream->Seek(offset, STREAM_SEEK_SET, NULL); + return Stream->Seek(offset, STREAM_SEEK_SET, NULL); } -////////////////////////////////////// -// Markers +static bool CheckDosTime(UInt32 dosTime) +{ + if (dosTime == 0) + return true; + unsigned month = (dosTime >> 21) & 0xF; + unsigned day = (dosTime >> 16) & 0x1F; + unsigned hour = (dosTime >> 11) & 0x1F; + unsigned min = (dosTime >> 5) & 0x3F; + unsigned sec = (dosTime & 0x1F) * 2; + if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59) + return false; + return true; +} -static inline bool TestMarkerCandidate(const Byte *p, UInt32 &value) +API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size) { + if (size < 8) + return k_IsArc_Res_NEED_MORE; + if (p[0] != 'P') + return k_IsArc_Res_NO; + + UInt32 value = Get32(p); + + if (value == NSignature::kNoSpan) + { + p += 4; + size -= 4; + } + value = Get32(p); - return - (value == NSignature::kLocalFileHeader) || - (value == NSignature::kEndOfCentralDir); + + if (value == NSignature::kEcd) + { + if (size < kEcdSize) + return k_IsArc_Res_NEED_MORE; + CEcd ecd; + ecd.Parse(p + 4); + // if (ecd.cdSize != 0) + if (!ecd.IsEmptyArc()) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; // k_IsArc_Res_YES_2; + } + + if (value != NSignature::kLocalFileHeader) + return k_IsArc_Res_NO; + + if (size < kLocalHeaderSize) + return k_IsArc_Res_NEED_MORE; + + p += 4; + + { + const unsigned kPureHeaderSize = kLocalHeaderSize - 4; + unsigned i; + for (i = 0; i < kPureHeaderSize && p[i] == 0; i++); + if (i == kPureHeaderSize) + return k_IsArc_Res_NEED_MORE; + } + + /* + if (p[0] >= 128) // ExtractVersion.Version; + return k_IsArc_Res_NO; + */ + + // ExtractVersion.Version = p[0]; + // ExtractVersion.HostOS = p[1]; + // Flags = Get16(p + 2); + // Method = Get16(p + 4); + /* + // 9.33: some zip archives contain incorrect value in timestamp. So we don't check it now + UInt32 dosTime = Get32(p + 6); + if (!CheckDosTime(dosTime)) + return k_IsArc_Res_NO; + */ + // Crc = Get32(p + 10); + // PackSize = Get32(p + 14); + // Size = Get32(p + 18); + unsigned nameSize = Get16(p + 22); + unsigned extraSize = Get16(p + 24); + UInt32 extraOffset = kLocalHeaderSize + (UInt32)nameSize; + if (extraOffset + extraSize > (1 << 16)) + return k_IsArc_Res_NO; + + p -= 4; + + { + size_t rem = size - kLocalHeaderSize; + if (rem > nameSize) + rem = nameSize; + const Byte *p2 = p + kLocalHeaderSize; + for (size_t i = 0; i < rem; i++) + if (p2[i] == 0) + return k_IsArc_Res_NO; + } + + if (size < extraOffset) + return k_IsArc_Res_NEED_MORE; + + if (extraSize > 0) + { + p += extraOffset; + size -= extraOffset; + while (extraSize != 0) + { + if (extraSize < 4) + { + // 7-Zip before 9.31 created incorrect WsAES Extra in folder's local headers. + // so we return k_IsArc_Res_YES to support such archives. + // return k_IsArc_Res_NO; // do we need to support such extra ? + return k_IsArc_Res_YES; + } + if (size < 4) + return k_IsArc_Res_NEED_MORE; + unsigned dataSize = Get16(p + 2); + size -= 4; + extraSize -= 4; + p += 4; + if (dataSize > extraSize) + return k_IsArc_Res_NO; + if (dataSize > size) + return k_IsArc_Res_NEED_MORE; + size -= dataSize; + extraSize -= dataSize; + p += dataSize; + } + } + + return k_IsArc_Res_YES; } -static const UInt32 kNumMarkerAddtionalBytes = 2; -static inline bool TestMarkerCandidate2(const Byte *p, UInt32 &value) +static UInt32 IsArc_Zip_2(const Byte *p, size_t size, bool isFinal) { - value = Get32(p); - if (value == NSignature::kEndOfCentralDir) - return (Get16(p + 4) == 0); - return (value == NSignature::kLocalFileHeader && p[4] < 128); + UInt32 res = IsArc_Zip(p, size); + if (res == k_IsArc_Res_NEED_MORE && isFinal) + return k_IsArc_Res_NO; + return res; } -HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit) +HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchLimit) { ArcInfo.Clear(); - m_Position = m_StreamStartPosition; + ArcInfo.MarkerPos = m_Position; + ArcInfo.MarkerPos2 = m_Position; - Byte marker[NSignature::kMarkerSize]; - RINOK(ReadStream_FALSE(stream, marker, NSignature::kMarkerSize)); - m_Position += NSignature::kMarkerSize; - if (TestMarkerCandidate(marker, m_Signature)) - return S_OK; + if (searchLimit && *searchLimit == 0) + { + const unsigned kStartBufSize = kMarkerSize; + Byte startBuf[kStartBufSize]; + size_t processed = kStartBufSize; + RINOK(ReadStream(stream, startBuf, &processed)); + m_Position += processed; + if (processed < kMarkerSize) + return S_FALSE; + m_Signature = Get32(startBuf); + if (m_Signature != NSignature::kEcd && + m_Signature != NSignature::kLocalFileHeader) + { + if (m_Signature != NSignature::kNoSpan) + return S_FALSE; + size_t processed = kStartBufSize; + RINOK(ReadStream(stream, startBuf, &processed)); + m_Position += 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; + } + + // we use weak test in case of *searchLimit == 0) + // since error will be detected later in Open function + // m_Position = ArcInfo.MarkerPos2 + 4; + return S_OK; // maybe we need to search backward. + } + + 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; - CByteDynamicBuffer dynamicBuffer; - const UInt32 kSearchMarkerBufferSize = 0x10000; - dynamicBuffer.EnsureCapacity(kSearchMarkerBufferSize); - Byte *buffer = dynamicBuffer; - UInt32 numBytesPrev = NSignature::kMarkerSize - 1; - memcpy(buffer, marker + 1, numBytesPrev); - UInt64 curTestPos = m_StreamStartPosition + 1; for (;;) { - if (searchHeaderSizeLimit != NULL) - if (curTestPos - m_StreamStartPosition > *searchHeaderSizeLimit) - break; - size_t numReadBytes = kSearchMarkerBufferSize - numBytesPrev; - RINOK(ReadStream(stream, buffer + numBytesPrev, &numReadBytes)); + size_t numReadBytes = kBufSize - numBytesInBuffer; + RINOK(ReadStream(stream, buffer + numBytesInBuffer, &numReadBytes)); m_Position += numReadBytes; - UInt32 numBytesInBuffer = numBytesPrev + (UInt32)numReadBytes; - const UInt32 kMarker2Size = NSignature::kMarkerSize + kNumMarkerAddtionalBytes; - if (numBytesInBuffer < kMarker2Size) + numBytesInBuffer += numReadBytes; + bool isFinished = (numBytesInBuffer != kBufSize); + + size_t limit = (isFinished ? numBytesInBuffer : numBytesInBuffer - kCheckSize); + + if (searchLimit && curScanPos + limit > *searchLimit) + limit = (size_t)(*searchLimit - curScanPos + 1); + + if (limit < 1) break; - UInt32 numTests = numBytesInBuffer - kMarker2Size + 1; - for (UInt32 pos = 0; pos < numTests; pos++) + + const Byte *buf = buffer; + for (size_t pos = 0; pos < limit; pos++) { - if (buffer[pos] != 0x50) + if (buf[pos] != 0x50) + continue; + if (buf[pos + 1] != 0x4B) continue; - if (TestMarkerCandidate2(buffer + pos, m_Signature)) + size_t rem = numBytesInBuffer - pos; + UInt32 res = IsArc_Zip_2(buf + pos, rem, isFinished); + if (res != k_IsArc_Res_NO) { - curTestPos += pos; - ArcInfo.StartPosition = curTestPos; - m_Position = curTestPos + NSignature::kMarkerSize; + if (rem < kMarkerSize) + return S_FALSE; + m_Signature = Get32(buf + pos); + ArcInfo.MarkerPos += curScanPos + pos; + ArcInfo.MarkerPos2 = ArcInfo.MarkerPos; + if (m_Signature == NSignature::kNoSpan) + { + m_Signature = Get32(buf + pos + 4); + ArcInfo.MarkerPos2 += 4; + } + m_Position = ArcInfo.MarkerPos2 + kMarkerSize; return S_OK; } } - curTestPos += numTests; - numBytesPrev = numBytesInBuffer - numTests; - memmove(buffer, buffer + numTests, numBytesPrev); + + if (isFinished) + break; + + curScanPos += limit; + numBytesInBuffer -= limit; + memmove(buffer, buffer + limit, numBytesInBuffer); } + return S_FALSE; } +HRESULT CInArchive::IncreaseRealPosition(UInt64 addValue) +{ + return Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position); +} + +class CUnexpectEnd {}; + HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize) { size_t realProcessedSize = size; @@ -121,42 +365,35 @@ HRESULT CInArchive::ReadBytes(void *data, UInt32 size, UInt32 *processedSize) catch (const CInBufferException &e) { return e.ErrorCode; } } else - result = ReadStream(m_Stream, data, &realProcessedSize); - if (processedSize != NULL) + result = ReadStream(Stream, data, &realProcessedSize); + if (processedSize) *processedSize = (UInt32)realProcessedSize; m_Position += realProcessedSize; return result; } -void CInArchive::Skip(UInt64 num) -{ - for (UInt64 i = 0; i < num; i++) - ReadByte(); -} - -void CInArchive::IncreaseRealPosition(UInt64 addValue) -{ - if (m_Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position) != S_OK) - throw CInArchiveException(CInArchiveException::kSeekStreamError); -} - -bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size) -{ - UInt32 realProcessedSize; - if (ReadBytes(data, size, &realProcessedSize) != S_OK) - throw CInArchiveException(CInArchiveException::kReadStreamError); - return (realProcessedSize == size); -} - -void CInArchive::SafeReadBytes(void *data, UInt32 size) +void CInArchive::SafeReadBytes(void *data, unsigned size) { - if (!ReadBytesAndTestSize(data, size)) - throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive); + size_t processed = size; + if (_inBufMode) + { + processed = _inBuffer.ReadBytes((Byte *)data, size); + m_Position += processed; + } + else + { + HRESULT result = ReadStream(Stream, data, &processed); + m_Position += processed; + if (result != S_OK) + throw CSystemException(result); + } + if (processed != size) + throw CUnexpectEnd(); } -void CInArchive::ReadBuffer(CByteBuffer &buffer, UInt32 size) +void CInArchive::ReadBuffer(CByteBuffer &buffer, unsigned size) { - buffer.SetCapacity(size); + buffer.Alloc(size); if (size > 0) SafeReadBytes(buffer, size); } @@ -168,65 +405,73 @@ Byte CInArchive::ReadByte() return b; } -UInt16 CInArchive::ReadUInt16() -{ - Byte buf[2]; - SafeReadBytes(buf, 2); - return Get16(buf); -} +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); } -UInt32 CInArchive::ReadUInt32() +void CInArchive::Skip(unsigned num) { - Byte buf[4]; - SafeReadBytes(buf, 4); - return Get32(buf); + if (_inBufMode) + { + size_t skip = _inBuffer.Skip(num); + m_Position += skip; + if (skip != num) + throw CUnexpectEnd(); + } + else + { + for (unsigned i = 0; i < num; i++) + ReadByte(); + } } -UInt64 CInArchive::ReadUInt64() +void CInArchive::Skip64(UInt64 num) { - Byte buf[8]; - SafeReadBytes(buf, 8); - return Get64(buf); + for (UInt64 i = 0; i < num; i++) + ReadByte(); } -bool CInArchive::ReadUInt32(UInt32 &value) -{ - Byte buf[4]; - if (!ReadBytesAndTestSize(buf, 4)) - return false; - value = Get32(buf); - return true; -} -void CInArchive::ReadFileName(UInt32 nameSize, AString &dest) +void CInArchive::ReadFileName(unsigned size, AString &s) { - if (nameSize == 0) - dest.Empty(); - char *p = dest.GetBuffer((int)nameSize); - SafeReadBytes(p, nameSize); - p[nameSize] = 0; - dest.ReleaseBuffer(); + if (size == 0) + { + s.Empty(); + return; + } + char *p = s.GetBuffer(size); + SafeReadBytes(p, size); + p[size] = 0; + s.ReleaseBuffer(); } -void CInArchive::ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock, +bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extraBlock, UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber) { extraBlock.Clear(); UInt32 remain = extraSize; - while(remain >= 4) + while (remain >= 4) { CExtraSubBlock subBlock; subBlock.ID = ReadUInt16(); - UInt32 dataSize = ReadUInt16(); + unsigned dataSize = ReadUInt16(); remain -= 4; if (dataSize > remain) // it's bug - dataSize = remain; + { + HeadersWarning = true; + Skip(remain); + return false; + } if (subBlock.ID == NFileHeader::NExtraID::kZip64) { if (unpackSize == 0xFFFFFFFF) { if (dataSize < 8) - break; + { + HeadersWarning = true; + Skip(remain); + return false; + } unpackSize = ReadUInt64(); remain -= 8; dataSize -= 8; @@ -255,8 +500,7 @@ void CInArchive::ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock, remain -= 4; dataSize -= 4; } - for (UInt32 i = 0; i < dataSize; i++) - ReadByte(); + Skip(dataSize); } else { @@ -265,88 +509,125 @@ void CInArchive::ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock, } remain -= dataSize; } + if (remain != 0) + { + ExtraMinorError = 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(remain); + return true; } -HRESULT CInArchive::ReadLocalItem(CItemEx &item) +bool CInArchive::ReadLocalItem(CItemEx &item) { - const int kBufSize = 26; - Byte p[kBufSize]; - SafeReadBytes(p, kBufSize); + const unsigned kPureHeaderSize = kLocalHeaderSize - 4; + Byte p[kPureHeaderSize]; + SafeReadBytes(p, kPureHeaderSize); + { + unsigned i; + for (i = 0; i < kPureHeaderSize && p[i] == 0; i++); + if (i == kPureHeaderSize) + return false; + } item.ExtractVersion.Version = p[0]; item.ExtractVersion.HostOS = p[1]; item.Flags = Get16(p + 2); - item.CompressionMethod = Get16(p + 4); + item.Method = Get16(p + 4); item.Time = Get32(p + 6); - item.FileCRC = Get32(p + 10); + item.Crc = Get32(p + 10); item.PackSize = Get32(p + 14); - item.UnPackSize = Get32(p + 18); - UInt32 fileNameSize = Get16(p + 22); - item.LocalExtraSize = Get16(p + 24); - ReadFileName(fileNameSize, item.Name); - item.FileHeaderWithNameSize = 4 + NFileHeader::kLocalBlockSize + fileNameSize; - if (item.LocalExtraSize > 0) + item.Size = Get32(p + 18); + unsigned nameSize = Get16(p + 22); + unsigned extraSize = Get16(p + 24); + ReadFileName(nameSize, item.Name); + item.LocalFullHeaderSize = kLocalHeaderSize + (UInt32)nameSize + extraSize; + + /* + if (item.IsDir()) + item.Size = 0; // check It + */ + + if (extraSize > 0) { UInt64 localHeaderOffset = 0; UInt32 diskStartNumber = 0; - ReadExtra(item.LocalExtraSize, item.LocalExtra, item.UnPackSize, item.PackSize, - localHeaderOffset, diskStartNumber); + if (!ReadExtra(extraSize, item.LocalExtra, item.Size, item.PackSize, + localHeaderOffset, diskStartNumber)) + return false; } - /* - if (item.IsDir()) - item.UnPackSize = 0; // check It - */ - return S_OK; + if (!CheckDosTime(item.Time)) + { + HeadersWarning = true; + // return false; + } + if (item.Name.Len() != nameSize) + return false; + return item.LocalFullHeaderSize <= ((UInt32)1 << 16); } -static bool FlagsAreSame(CItem &i1, CItem &i2) +static bool FlagsAreSame(const CItem &i1, const CItem &i2) { - if (i1.CompressionMethod != i2.CompressionMethod) + if (i1.Method != i2.Method) return false; - // i1.Time - if (i1.Flags == i2.Flags) return true; UInt32 mask = 0xFFFF; - switch(i1.CompressionMethod) + switch(i1.Method) { case NFileHeader::NCompressionMethod::kDeflated: mask = 0x7FF9; break; default: - if (i1.CompressionMethod <= NFileHeader::NCompressionMethod::kImploded) + if (i1.Method <= NFileHeader::NCompressionMethod::kImploded) mask = 0x7FFF; } return ((i1.Flags & mask) == (i2.Flags & mask)); } +static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem) +{ + if (!FlagsAreSame(cdItem, localItem)) + return false; + if (!localItem.HasDescriptor()) + { + if (cdItem.Crc != localItem.Crc || + cdItem.PackSize != localItem.PackSize || + cdItem.Size != localItem.Size) + return false; + } + /* pkzip 2.50 creates incorrect archives. It uses + - WIN encoding for name in local header + - OEM encoding for name in central header + We don't support these strange items. */ + + /* if (cdItem.Name.Len() != localItem.Name.Len()) + return false; + */ + if (cdItem.Name != localItem.Name) + return false; + return true; +} + HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item) { if (item.FromLocal) return S_OK; try { - RINOK(Seek(ArcInfo.Base + item.LocalHeaderPosition)); + UInt64 offset = ArcInfo.Base + item.LocalHeaderPos; + if (ArcInfo.Base < 0 && (Int64)offset < 0) + return S_FALSE; + RINOK(Seek(offset)); CItemEx localItem; if (ReadUInt32() != NSignature::kLocalFileHeader) return S_FALSE; - RINOK(ReadLocalItem(localItem)); - if (!FlagsAreSame(item, localItem)) + ReadLocalItem(localItem); + if (!AreItemsEqual(localItem, item)) return S_FALSE; - - if ((!localItem.HasDescriptor() && - ( - item.FileCRC != localItem.FileCRC || - item.PackSize != localItem.PackSize || - item.UnPackSize != localItem.UnPackSize - ) - ) || - item.Name.Length() != localItem.Name.Length() - ) - return S_FALSE; - item.FileHeaderWithNameSize = localItem.FileHeaderWithNameSize; - item.LocalExtraSize = localItem.LocalExtraSize; + item.LocalFullHeaderSize = localItem.LocalFullHeaderSize; item.LocalExtra = localItem.LocalExtra; item.FromLocal = true; } @@ -356,53 +637,45 @@ HRESULT CInArchive::ReadLocalItemAfterCdItem(CItemEx &item) HRESULT CInArchive::ReadLocalItemDescriptor(CItemEx &item) { - if (item.HasDescriptor()) + const unsigned kBufSize = (1 << 12); + Byte buf[kBufSize]; + + UInt32 numBytesInBuffer = 0; + UInt32 packedSize = 0; + + for (;;) { - const int kBufferSize = (1 << 12); - Byte buffer[kBufferSize]; - - UInt32 numBytesInBuffer = 0; - UInt32 packedSize = 0; - - bool descriptorWasFound = false; - for (;;) + UInt32 processedSize; + RINOK(ReadBytes(buf + numBytesInBuffer, kBufSize - numBytesInBuffer, &processedSize)); + numBytesInBuffer += processedSize; + if (numBytesInBuffer < kDataDescriptorSize) + return S_FALSE; + UInt32 i; + for (i = 0; i <= numBytesInBuffer - kDataDescriptorSize; i++) { - UInt32 processedSize; - RINOK(ReadBytes(buffer + numBytesInBuffer, kBufferSize - numBytesInBuffer, &processedSize)); - numBytesInBuffer += processedSize; - if (numBytesInBuffer < NFileHeader::kDataDescriptorSize) - return S_FALSE; - UInt32 i; - for (i = 0; i <= numBytesInBuffer - NFileHeader::kDataDescriptorSize; i++) + // descriptor signature field is Info-ZIP's extension to pkware Zip specification. + // New ZIP specification also allows descriptorSignature. + if (buf[i] != 0x50) + continue; + // !!!! It must be fixed for Zip64 archives + if (Get32(buf + i) == NSignature::kDataDescriptor) { - // descriptorSignature field is Info-ZIP's extension - // to Zip specification. - UInt32 descriptorSignature = Get32(buffer + i); - - // !!!! It must be fixed for Zip64 archives - UInt32 descriptorPackSize = Get32(buffer + i + 8); - if (descriptorSignature== NSignature::kDataDescriptor && descriptorPackSize == packedSize + i) + UInt32 descriptorPackSize = Get32(buf + i + 8); + if (descriptorPackSize == packedSize + i) { - descriptorWasFound = true; - item.FileCRC = Get32(buffer + i + 4); + item.Crc = Get32(buf + i + 4); item.PackSize = descriptorPackSize; - item.UnPackSize = Get32(buffer + i + 12); - IncreaseRealPosition(Int64(Int32(0 - (numBytesInBuffer - i - NFileHeader::kDataDescriptorSize)))); - break; + item.Size = Get32(buf + i + 12); + return IncreaseRealPosition(Int64(Int32(0 - (numBytesInBuffer - i - kDataDescriptorSize)))); } } - if (descriptorWasFound) - break; - packedSize += i; - int j; - for (j = 0; i < numBytesInBuffer; i++, j++) - buffer[j] = buffer[i]; - numBytesInBuffer = j; } + packedSize += i; + unsigned j; + for (j = 0; i < numBytesInBuffer; i++, j++) + buf[j] = buf[i]; + numBytesInBuffer = j; } - else - IncreaseRealPosition(item.PackSize); - return S_OK; } HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item) @@ -433,7 +706,7 @@ HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item) unpackSize = ReadUInt32(); } - if (crc != item.FileCRC || item.PackSize != packSize || item.UnPackSize != unpackSize) + if (crc != item.Crc || item.PackSize != packSize || item.Size != unpackSize) return S_FALSE; } } @@ -444,106 +717,161 @@ HRESULT CInArchive::ReadLocalItemAfterCdItemFull(CItemEx &item) HRESULT CInArchive::ReadCdItem(CItemEx &item) { item.FromCentral = true; - const int kBufSize = 42; - Byte p[kBufSize]; - SafeReadBytes(p, kBufSize); + Byte p[kCentralHeaderSize - 4]; + SafeReadBytes(p, kCentralHeaderSize - 4); + item.MadeByVersion.Version = p[0]; item.MadeByVersion.HostOS = p[1]; item.ExtractVersion.Version = p[2]; item.ExtractVersion.HostOS = p[3]; item.Flags = Get16(p + 4); - item.CompressionMethod = Get16(p + 6); + item.Method = Get16(p + 6); item.Time = Get32(p + 8); - item.FileCRC = Get32(p + 12); + item.Crc = Get32(p + 12); item.PackSize = Get32(p + 16); - item.UnPackSize = Get32(p + 20); - UInt16 headerNameSize = Get16(p + 24); - UInt16 headerExtraSize = Get16(p + 26); - UInt16 headerCommentSize = Get16(p + 28); - UInt32 headerDiskNumberStart = Get16(p + 30); - item.InternalAttributes = Get16(p + 32); - item.ExternalAttributes = Get32(p + 34); - item.LocalHeaderPosition = Get32(p + 38); - ReadFileName(headerNameSize, item.Name); + item.Size = Get32(p + 20); + unsigned nameSize = Get16(p + 24); + UInt16 extraSize = Get16(p + 26); + UInt16 commentSize = Get16(p + 28); + UInt32 diskNumberStart = Get16(p + 30); + item.InternalAttrib = Get16(p + 32); + item.ExternalAttrib = Get32(p + 34); + item.LocalHeaderPos = Get32(p + 38); + ReadFileName(nameSize, item.Name); - if (headerExtraSize > 0) + if (extraSize > 0) { - ReadExtra(headerExtraSize, item.CentralExtra, item.UnPackSize, item.PackSize, - item.LocalHeaderPosition, headerDiskNumberStart); + ReadExtra(extraSize, item.CentralExtra, item.Size, item.PackSize, + item.LocalHeaderPos, diskNumberStart); } - if (headerDiskNumberStart != 0) - throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported); + if (diskNumberStart != 0) + return E_NOTIMPL; // May be these strings must be deleted /* if (item.IsDir()) - item.UnPackSize = 0; + item.Size = 0; */ - ReadBuffer(item.Comment, headerCommentSize); + ReadBuffer(item.Comment, commentSize); return S_OK; } +void CCdInfo::ParseEcd(const Byte *p) +{ + NumEntries = Get16(p + 10); + Size = Get32(p + 12); + Offset = Get32(p + 16); +} + +void CCdInfo::ParseEcd64(const Byte *p) +{ + NumEntries = Get64(p + 24); + Size = Get64(p + 40); + Offset = Get64(p + 48); +} + HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo) { + if (offset >= ((UInt64)1 << 63)) + return S_FALSE; RINOK(Seek(offset)); - const UInt32 kEcd64Size = 56; - Byte buf[kEcd64Size]; - if (!ReadBytesAndTestSize(buf, kEcd64Size)) + Byte buf[kEcd64_FullSize]; + + RINOK(ReadStream_FALSE(Stream, buf, kEcd64_FullSize)); + + if (Get32(buf) != NSignature::kEcd64) return S_FALSE; - if (Get32(buf) != NSignature::kZip64EndOfCentralDir) + UInt64 mainSize = Get64(buf + 4); + if (mainSize < kEcd64_MainSize || mainSize > ((UInt64)1 << 32)) return S_FALSE; - // cdInfo.NumEntries = Get64(buf + 24); - cdInfo.Size = Get64(buf + 40); - cdInfo.Offset = Get64(buf + 48); + cdInfo.ParseEcd64(buf); return S_OK; } HRESULT CInArchive::FindCd(CCdInfo &cdInfo) { UInt64 endPosition; - RINOK(m_Stream->Seek(0, STREAM_SEEK_END, &endPosition)); - const UInt32 kBufSizeMax = (1 << 16) + kEcdSize + kZip64EcdLocatorSize; - CByteBuffer byteBuffer; - byteBuffer.SetCapacity(kBufSizeMax); - Byte *buf = byteBuffer; + RINOK(Stream->Seek(0, STREAM_SEEK_END, &endPosition)); + + const UInt32 kBufSizeMax = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize; UInt32 bufSize = (endPosition < kBufSizeMax) ? (UInt32)endPosition : kBufSizeMax; if (bufSize < kEcdSize) return S_FALSE; + CByteArr byteBuffer(bufSize); + UInt64 startPosition = endPosition - bufSize; - RINOK(m_Stream->Seek(startPosition, STREAM_SEEK_SET, &m_Position)); + RINOK(Stream->Seek(startPosition, STREAM_SEEK_SET, &m_Position)); if (m_Position != startPosition) return S_FALSE; - if (!ReadBytesAndTestSize(buf, bufSize)) - return S_FALSE; - for (int i = (int)(bufSize - kEcdSize); i >= 0; i--) + + RINOK(ReadStream_FALSE(Stream, byteBuffer, bufSize)); + + const Byte *buf = byteBuffer; + for (UInt32 i = bufSize - kEcdSize;; i--) { - if (Get32(buf + i) == NSignature::kEndOfCentralDir) + if (buf[i] != 0x50) { - if (i >= kZip64EcdLocatorSize) + if (i == 0) return S_FALSE; + i--; + if (buf[i] != 0x50) { - const Byte *locator = buf + i - kZip64EcdLocatorSize; - if (Get32(locator) == NSignature::kZip64EndOfCentralDirLocator) + if (i == 0) return S_FALSE; + continue; + } + } + if (Get32(buf + i) == NSignature::kEcd) + { + if (i >= kEcd64_FullSize + kEcd64Locator_Size) + { + const Byte *locator = buf + i - kEcd64Locator_Size; + if (Get32(locator) == NSignature::kEcd64Locator && + Get32(locator + 4) == 0) // number of the disk with the start of the zip64 ECD { + // Most of the zip64 use fixed size Zip64 ECD + UInt64 ecd64Offset = Get64(locator + 8); - if (TryEcd64(ecd64Offset, cdInfo) == S_OK) - return S_OK; - if (TryEcd64(ArcInfo.StartPosition + ecd64Offset, cdInfo) == S_OK) + UInt64 absEcd64 = endPosition - bufSize + i - (kEcd64Locator_Size + kEcd64_FullSize); + { + const Byte *ecd64 = locator - kEcd64_FullSize; + if (Get32(ecd64) == NSignature::kEcd64 && + Get64(ecd64 + 4) == kEcd64_MainSize) + { + cdInfo.ParseEcd64(ecd64); + ArcInfo.Base = absEcd64 - ecd64Offset; + return S_OK; + } + } + + // some zip64 use variable size Zip64 ECD. + // we try to find it + if (absEcd64 != ecd64Offset) + { + if (TryEcd64(ecd64Offset, cdInfo) == S_OK) + { + ArcInfo.Base = 0; + return S_OK; + } + } + if (ArcInfo.MarkerPos != 0 && + ArcInfo.MarkerPos + ecd64Offset != absEcd64) { - ArcInfo.Base = ArcInfo.StartPosition; - return S_OK; + if (TryEcd64(ArcInfo.MarkerPos + ecd64Offset, cdInfo) == S_OK) + { + ArcInfo.Base = ArcInfo.MarkerPos; + return S_OK; + } } } } - if (Get32(buf + i + 4) == 0) + if (Get32(buf + i + 4) == 0) // ThisDiskNumber, StartCentralDirectoryDiskNumber; { - // cdInfo.NumEntries = GetUInt16(buf + i + 10); - cdInfo.Size = Get32(buf + i + 12); - cdInfo.Offset = Get32(buf + i + 16); - UInt64 curPos = endPosition - bufSize + i; + cdInfo.ParseEcd(buf + i); + UInt64 absEcdPos = endPosition - bufSize + i; UInt64 cdEnd = cdInfo.Size + cdInfo.Offset; - if (curPos != cdEnd) + ArcInfo.Base = 0; + if (absEcdPos != cdEnd) { /* if (cdInfo.Offset <= 16 && cdInfo.Size != 0) @@ -553,290 +881,301 @@ HRESULT CInArchive::FindCd(CCdInfo &cdInfo) } else */ - ArcInfo.Base = curPos - cdEnd; + ArcInfo.Base = absEcdPos - cdEnd; } return S_OK; } } + if (i == 0) + return S_FALSE; } - return S_FALSE; } + HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress) { items.Clear(); - RINOK(m_Stream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position)); + RINOK(Stream->Seek(cdOffset, STREAM_SEEK_SET, &m_Position)); if (m_Position != cdOffset) return S_FALSE; - if (!_inBuffer.Create(1 << 15)) - return E_OUTOFMEMORY; - _inBuffer.SetStream(m_Stream); _inBuffer.Init(); _inBufMode = true; - while(m_Position - cdOffset < cdSize) + while (m_Position - cdOffset < cdSize) { if (ReadUInt32() != NSignature::kCentralFileHeader) return S_FALSE; CItemEx cdItem; RINOK(ReadCdItem(cdItem)); items.Add(cdItem); - if (progress && items.Size() % 1000 == 0) - RINOK(progress->SetCompleted(items.Size())); + if (progress && items.Size() % 1 == 0) + RINOK(progress->SetCompletedCD(items.Size())); } return (m_Position - cdOffset == cdSize) ? S_OK : S_FALSE; } HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress) { - ArcInfo.Base = 0; CCdInfo cdInfo; RINOK(FindCd(cdInfo)); HRESULT res = S_FALSE; cdSize = cdInfo.Size; cdOffset = cdInfo.Offset; + if (progress) + progress->SetTotalCD(cdInfo.NumEntries); res = TryReadCd(items, ArcInfo.Base + cdOffset, cdSize, progress); if (res == S_FALSE && ArcInfo.Base == 0) { - res = TryReadCd(items, cdInfo.Offset + ArcInfo.StartPosition, cdSize, progress); + res = TryReadCd(items, ArcInfo.MarkerPos + cdOffset, cdSize, progress); if (res == S_OK) - ArcInfo.Base = ArcInfo.StartPosition; + ArcInfo.Base = ArcInfo.MarkerPos; } - if (!ReadUInt32(m_Signature)) - return S_FALSE; return res; } -HRESULT CInArchive::ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems) +static HRESULT FindItem(const CObjectVector<CItemEx> &items, UInt64 offset) { - items.Clear(); - numCdItems = 0; - while (m_Signature == NSignature::kLocalFileHeader) + unsigned left = 0, right = items.Size(); + for (;;) { - // FSeek points to next byte after signature - // NFileHeader::CLocalBlock localHeader; - CItemEx item; - item.LocalHeaderPosition = m_Position - m_StreamStartPosition - 4; // points to signature; - RINOK(ReadLocalItem(item)); - item.FromLocal = true; - ReadLocalItemDescriptor(item); - items.Add(item); - if (progress && items.Size() % 100 == 0) - RINOK(progress->SetCompleted(items.Size())); - if (!ReadUInt32(m_Signature)) - break; + if (left >= right) + return -1; + unsigned index = (left + right) / 2; + UInt64 position = items[index].LocalHeaderPos; + if (offset == position) + return index; + if (offset < position) + right = index; + else + left = index + 1; } - cdOffset = m_Position - 4; - int i; - for (i = 0; i < items.Size(); i++, numCdItems++) - { - if (progress && i % 1000 == 0) - RINOK(progress->SetCompleted(items.Size())); - if (m_Signature == NSignature::kEndOfCentralDir) - break; - - if (m_Signature != NSignature::kCentralFileHeader) - return S_FALSE; +} - CItemEx cdItem; - RINOK(ReadCdItem(cdItem)); +bool IsStrangeItem(const CItem &item) +{ + return item.Name.Len() > (1 << 14) || item.Method > (1 << 8); +} - if (i == 0) +HRESULT CInArchive::ReadLocals( + CObjectVector<CItemEx> &items, CProgressVirt *progress) +{ + items.Clear(); + while (m_Signature == NSignature::kLocalFileHeader) + { + CItemEx item; + item.LocalHeaderPos = m_Position - 4 - ArcInfo.MarkerPos; + // we write ralative LocalHeaderPos here. Later we can correct it to real Base. + try { - int j; - for (j = 0; j < items.Size(); j++) + ReadLocalItem(item); + item.FromLocal = true; + if (item.HasDescriptor()) + ReadLocalItemDescriptor(item); + else { - CItemEx &item = items[j]; - if (item.Name == cdItem.Name) - { - ArcInfo.Base = item.LocalHeaderPosition - cdItem.LocalHeaderPosition; - break; - } + RINOK(IncreaseRealPosition(item.PackSize)); } - if (j == items.Size()) - return S_FALSE; + items.Add(item); + m_Signature = ReadUInt32(); } - - int index; - int left = 0, right = items.Size(); - for (;;) + catch (CUnexpectEnd &) { - if (left >= right) + if (items.IsEmpty() || items.Size() == 1 && IsStrangeItem(items[0])) return S_FALSE; - index = (left + right) / 2; - UInt64 position = items[index].LocalHeaderPosition - ArcInfo.Base; - if (cdItem.LocalHeaderPosition == position) - break; - if (cdItem.LocalHeaderPosition < position) - right = index; - else - left = index + 1; + throw; } - CItemEx &item = items[index]; - // item.LocalHeaderPosition = cdItem.LocalHeaderPosition; - item.MadeByVersion = cdItem.MadeByVersion; - item.CentralExtra = cdItem.CentralExtra; - - if ( - // item.ExtractVersion != cdItem.ExtractVersion || - !FlagsAreSame(item, cdItem) || - item.FileCRC != cdItem.FileCRC) - return S_FALSE; + if (progress && items.Size() % 1 == 0) + RINOK(progress->SetCompletedLocal(items.Size(), item.LocalHeaderPos)); + } - if (item.Name.Length() != cdItem.Name.Length() || - item.PackSize != cdItem.PackSize || - item.UnPackSize != cdItem.UnPackSize - ) - return S_FALSE; - item.Name = cdItem.Name; - item.InternalAttributes = cdItem.InternalAttributes; - item.ExternalAttributes = cdItem.ExternalAttributes; - item.Comment = cdItem.Comment; - item.FromCentral = cdItem.FromCentral; - if (!ReadUInt32(m_Signature)) + if (items.Size() == 1 && m_Signature != NSignature::kCentralFileHeader) + if (IsStrangeItem(items[0])) return S_FALSE; - } - for (i = 0; i < items.Size(); i++) - items[i].LocalHeaderPosition -= ArcInfo.Base; return S_OK; } -struct CEcd -{ - UInt16 thisDiskNumber; - UInt16 startCDDiskNumber; - UInt16 numEntriesInCDOnThisDisk; - UInt16 numEntriesInCD; - UInt32 cdSize; - UInt32 cdStartOffset; - UInt16 commentSize; - void Parse(const Byte *p); -}; - -void CEcd::Parse(const Byte *p) -{ - thisDiskNumber = Get16(p); - startCDDiskNumber = Get16(p + 2); - numEntriesInCDOnThisDisk = Get16(p + 4); - numEntriesInCD = Get16(p + 6); - cdSize = Get32(p + 8); - cdStartOffset = Get32(p + 12); - commentSize = Get16(p + 16); -} - -struct CEcd64 -{ - UInt16 versionMade; - UInt16 versionNeedExtract; - UInt32 thisDiskNumber; - UInt32 startCDDiskNumber; - UInt64 numEntriesInCDOnThisDisk; - UInt64 numEntriesInCD; - UInt64 cdSize; - UInt64 cdStartOffset; - void Parse(const Byte *p); - CEcd64() { memset(this, 0, sizeof(*this)); } -}; - -void CEcd64::Parse(const Byte *p) -{ - versionMade = Get16(p); - versionNeedExtract = Get16(p + 2); - thisDiskNumber = Get32(p + 4); - startCDDiskNumber = Get32(p + 8); - numEntriesInCDOnThisDisk = Get64(p + 12); - numEntriesInCD = Get64(p + 20); - cdSize = Get64(p + 28); - cdStartOffset = Get64(p + 36); -} #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; -HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress) +HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items, CProgressVirt *progress) { - IsOkHeaders = true; - // m_Signature must be kLocalFileHeaderSignature or - // kEndOfCentralDirSignature + items.Clear(); + + // m_Signature must be kLocalFileHeader or kEcd // m_Position points to next byte after signature + RINOK(Stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); - IsZip64 = false; - items.Clear(); + if (!_inBuffer.Create(1 << 15)) + return E_OUTOFMEMORY; + _inBuffer.SetStream(Stream); - UInt64 cdSize, cdStartOffset; - HRESULT res; - try + bool needReadCd = true; + bool localsWereRead = false; + if (m_Signature == NSignature::kEcd) { - res = ReadCd(items, cdStartOffset, cdSize, progress); + // 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); + CEcd ecd; + ecd.Parse(buf); + // if (ecd.cdSize != 0) + // Do we need also to support the case where empty zip archive with PK00 uses cdOffset = 4 ?? + if (!ecd.IsEmptyArc()) + 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)); } - catch(CInArchiveException &) + + UInt64 cdSize = 0, cdRelatOffset = 0, cdAbsOffset = 0; + HRESULT res = S_OK; + + if (needReadCd) { - res = S_FALSE; + CItemEx firstItem; + // try + { + try + { + if (!ReadLocalItem(firstItem)) + return S_FALSE; + } + catch(CUnexpectEnd &) + { + return S_FALSE; + } + + IsArc = true; + res = ReadCd(items, cdRelatOffset, cdSize, progress); + if (res == S_OK) + m_Signature = ReadUInt32(); + } + // catch() { res = S_FALSE; } + if (res != S_FALSE && res != S_OK) + return res; + + if (res == S_OK && items.Size() == 0) + res = S_FALSE; + + if (res == S_OK) + { + // we can't read local items here to keep _inBufMode state + firstItem.LocalHeaderPos = ArcInfo.MarkerPos2 - ArcInfo.Base; + int index = FindItem(items, firstItem.LocalHeaderPos); + if (index == -1) + res = S_FALSE; + else if (!AreItemsEqual(firstItem, items[index])) + res = S_FALSE; + ArcInfo.CdWasRead = true; + ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos; + } } - if (res != S_FALSE && res != S_OK) - return res; - /* - if (res != S_OK) - return res; - res = S_FALSE; - */ + CObjectVector<CItemEx> cdItems; - int numCdItems = items.Size(); + bool needSetBase = false; + unsigned numCdItems = items.Size(); + if (res == S_FALSE) { + // CD doesn't match firstItem so we clear items and read Locals. + items.Clear(); + localsWereRead = true; _inBufMode = false; - ArcInfo.Base = 0; - RINOK(m_Stream->Seek(ArcInfo.StartPosition, STREAM_SEEK_SET, &m_Position)); - if (m_Position != ArcInfo.StartPosition) - return S_FALSE; - if (!ReadUInt32(m_Signature)) - return S_FALSE; - RINOK(ReadLocalsAndCd(items, progress, cdStartOffset, numCdItems)); - cdSize = (m_Position - 4) - cdStartOffset; - cdStartOffset -= ArcInfo.Base; + ArcInfo.Base = ArcInfo.MarkerPos; + RINOK(Stream->Seek(ArcInfo.MarkerPos2, STREAM_SEEK_SET, &m_Position)); + m_Signature = ReadUInt32(); + + RINOK(ReadLocals(items, progress)); + + if (m_Signature != NSignature::kCentralFileHeader) + { + m_Position -= 4; + NoCentralDir = true; + HeadersError = true; + return S_OK; + } + _inBufMode = true; + _inBuffer.Init(); + cdAbsOffset = m_Position - 4; + for (;;) + { + CItemEx cdItem; + RINOK(ReadCdItem(cdItem)); + cdItems.Add(cdItem); + if (progress && cdItems.Size() % 1 == 0) + RINOK(progress->SetCompletedCD(items.Size())); + m_Signature = ReadUInt32(); + if (m_Signature != NSignature::kCentralFileHeader) + break; + } + + cdSize = (m_Position - 4) - cdAbsOffset; + needSetBase = true; + numCdItems = cdItems.Size(); + + if (!cdItems.IsEmpty()) + { + ArcInfo.CdWasRead = true; + ArcInfo.FirstItemRelatOffset = cdItems[0].LocalHeaderPos; + } } CEcd64 ecd64; bool isZip64 = false; - UInt64 zip64EcdStartOffset = m_Position - 4 - ArcInfo.Base; - if (m_Signature == NSignature::kZip64EndOfCentralDir) + UInt64 ecd64AbsOffset = m_Position - 4; + if (m_Signature == NSignature::kEcd64) { IsZip64 = isZip64 = true; UInt64 recordSize = ReadUInt64(); - const int kBufSize = kZip64EcdSize; + const unsigned kBufSize = kEcd64_MainSize; Byte buf[kBufSize]; SafeReadBytes(buf, kBufSize); ecd64.Parse(buf); - Skip(recordSize - kZip64EcdSize); - if (!ReadUInt32(m_Signature)) - return S_FALSE; + Skip64(recordSize - kEcd64_MainSize); + m_Signature = ReadUInt32(); + if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) - throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported); + return E_NOTIMPL; + + if (needSetBase) + { + ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset; + cdRelatOffset = ecd64.cdStartOffset; + needSetBase = false; + } + if (ecd64.numEntriesInCDOnThisDisk != numCdItems || ecd64.numEntriesInCD != numCdItems || ecd64.cdSize != cdSize || - (ecd64.cdStartOffset != cdStartOffset && + (ecd64.cdStartOffset != cdRelatOffset && (!items.IsEmpty()))) return S_FALSE; } - if (m_Signature == NSignature::kZip64EndOfCentralDirLocator) + if (m_Signature == NSignature::kEcd64Locator) { + if (!isZip64) + return S_FALSE; /* UInt32 startEndCDDiskNumber = */ ReadUInt32(); - UInt64 endCDStartOffset = ReadUInt64(); + UInt64 ecd64RelatOffset = ReadUInt64(); /* UInt32 numberOfDisks = */ ReadUInt32(); - if (zip64EcdStartOffset != endCDStartOffset) - return S_FALSE; - if (!ReadUInt32(m_Signature)) + if (ecd64AbsOffset != ArcInfo.Base + ecd64RelatOffset) return S_FALSE; + m_Signature = ReadUInt32(); } - if (m_Signature != NSignature::kEndOfCentralDir) + if (m_Signature != NSignature::kEcd) return S_FALSE; - const int kBufSize = kEcdSize - 4; + const unsigned kBufSize = kEcdSize - 4; Byte buf[kBufSize]; SafeReadBytes(buf, kBufSize); CEcd ecd; @@ -849,47 +1188,119 @@ HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *pr COPY_ECD_ITEM_32(cdSize); COPY_ECD_ITEM_32(cdStartOffset); - ReadBuffer(ArcInfo.Comment, ecd.commentSize); + if (needSetBase) + { + ArcInfo.Base = cdAbsOffset - ecd64.cdStartOffset; + cdRelatOffset = ecd64.cdStartOffset; + needSetBase = false; + } + + if (localsWereRead && (UInt64)ArcInfo.Base != ArcInfo.MarkerPos) + { + UInt64 delta = ArcInfo.MarkerPos - ArcInfo.Base; + for (unsigned i = 0; i < items.Size(); i++) + items[i].LocalHeaderPos += delta; + } + + + // ---------- merge Central Directory Items ---------- + + if (!cdItems.IsEmpty()) + { + for (unsigned i = 0; i < cdItems.Size(); i++) + { + const CItemEx &cdItem = cdItems[i]; + int index = FindItem(items, cdItem.LocalHeaderPos); + if (index == -1) + { + items.Add(cdItem); + continue; + } + CItemEx &item = items[index]; + if (item.Name != cdItem.Name + // || item.Name.Len() != cdItem.Name.Len() + || item.PackSize != cdItem.PackSize + || item.Size != cdItem.Size + // item.ExtractVersion != cdItem.ExtractVersion + || !FlagsAreSame(item, cdItem) + || item.Crc != cdItem.Crc) + continue; + + // item.LocalHeaderPos = cdItem.LocalHeaderPos; + // item.Name = cdItem.Name; + item.MadeByVersion = cdItem.MadeByVersion; + item.CentralExtra = cdItem.CentralExtra; + item.InternalAttrib = cdItem.InternalAttrib; + item.ExternalAttrib = cdItem.ExternalAttrib; + item.Comment = cdItem.Comment; + item.FromCentral = cdItem.FromCentral; + } + } if (ecd64.thisDiskNumber != 0 || ecd64.startCDDiskNumber != 0) - throw CInArchiveException(CInArchiveException::kMultiVolumeArchiveAreNotSupported); - if (numCdItems != items.Size()) - IsOkHeaders = false; - if ((UInt16)ecd64.numEntriesInCDOnThisDisk != ((UInt16)numCdItems) || + return E_NOTIMPL; + + if (isZip64) + { + if (ecd64.numEntriesInCDOnThisDisk != items.Size()) + HeadersError = true; + } + else + { + // old 7-zip could store 32-bit number of CD items to 16-bit field. + if ((UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)numCdItems || + (UInt16)ecd64.numEntriesInCDOnThisDisk != (UInt16)items.Size()) + HeadersError = true; + } + + ReadBuffer(ArcInfo.Comment, ecd.commentSize); + _inBufMode = false; + _inBuffer.Free(); + + if ( (UInt16)ecd64.numEntriesInCD != ((UInt16)numCdItems) || (UInt32)ecd64.cdSize != (UInt32)cdSize || - ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdStartOffset && + ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdRelatOffset && (!items.IsEmpty()))) return S_FALSE; - _inBufMode = false; - _inBuffer.Free(); - ArcInfo.FinishPosition = m_Position; + // printf("\nOpen OK"); return S_OK; } +HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress) +{ + HRESULT res; + try + { + res = ReadHeaders2(items, progress); + } + catch (const CInBufferException &e) { res = e.ErrorCode; } + catch (const CUnexpectEnd &) + { + if (items.IsEmpty()) + return S_FALSE; + UnexpectedEnd = true; + res = S_OK; + } + catch (...) + { + _inBufMode = false; + throw; + } + ArcInfo.FinishPos = m_Position; + _inBufMode = false; + return res; +} + ISequentialInStream* CInArchive::CreateLimitedStream(UInt64 position, UInt64 size) { CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr<ISequentialInStream> stream(streamSpec); - SeekInArchive(ArcInfo.Base + position); - streamSpec->SetStream(m_Stream); + Stream->Seek(ArcInfo.Base + position, STREAM_SEEK_SET, NULL); + streamSpec->SetStream(Stream); streamSpec->Init(size); return stream.Detach(); } -IInStream* CInArchive::CreateStream() -{ - CMyComPtr<IInStream> stream = m_Stream; - return stream.Detach(); -} - -bool CInArchive::SeekInArchive(UInt64 position) -{ - UInt64 newPosition; - if (m_Stream->Seek(position, STREAM_SEEK_SET, &newPosition) != S_OK) - return false; - return (newPosition == position); -} - }} diff --git a/CPP/7zip/Archive/Zip/ZipIn.h b/CPP/7zip/Archive/Zip/ZipIn.h index 0565339a..f6b349b1 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipIn.h +++ b/CPP/7zip/Archive/Zip/ZipIn.h @@ -3,121 +3,187 @@ #ifndef __ZIP_IN_H #define __ZIP_IN_H -#include "Common/MyCom.h" +#include "../../../Common/MyCom.h" #include "../../IStream.h" #include "../../Common/InBuffer.h" #include "ZipHeader.h" -#include "ZipItemEx.h" +#include "ZipItem.h" + +API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size); namespace NArchive { namespace NZip { -class CInArchiveException +class CItemEx: public CItem { public: - enum ECauseType - { - kUnexpectedEndOfArchive = 0, - kArchiceHeaderCRCError, - kFileHeaderCRCError, - kIncorrectArchive, - kDataDescroptorsAreNotSupported, - kMultiVolumeArchiveAreNotSupported, - kReadStreamError, - kSeekStreamError - } - Cause; - CInArchiveException(ECauseType cause): Cause(cause) {} + UInt32 LocalFullHeaderSize; // including Name and Extra + + UInt64 GetLocalFullSize() const + { return LocalFullHeaderSize + PackSize + (HasDescriptor() ? kDataDescriptorSize : 0); } + UInt64 GetDataPosition() const + { return LocalHeaderPos + LocalFullHeaderSize; }; }; -class CInArchiveInfo +struct CInArchiveInfo { -public: - UInt64 Base; - UInt64 StartPosition; - UInt64 FinishPosition; + Int64 Base; /* Base offset of start of archive in stream. + Offsets in headers must be calculated from that Base. + Base is equal to MarkerPos for normal ZIPs. + Base can point to PE stub for some ZIP SFXs. + if CentralDir was read, + Base can be negative, if start of data is not available, + if CentralDirs was not read, + Base = ArcInfo.MarkerPos; */ + + /* The following *Pos variables contain absolute offsets in Stream */ + UInt64 MarkerPos; /* Pos of first signature, it can point to PK00 signature + = MarkerPos2 in most archives + = MarkerPos2 - 4 if there is PK00 signature */ + UInt64 MarkerPos2; // Pos of first local item signature in stream + UInt64 FinishPos; // Finish pos of archive data + UInt64 FileEndPos; // Finish pos of stream + + UInt64 FirstItemRelatOffset; /* Relative offset of first local (read from cd) (relative to Base). + = 0 in most archives + = size of stub for some SFXs */ + bool CdWasRead; + CByteBuffer Comment; - CInArchiveInfo(): Base(0), StartPosition(0) {} - UInt64 GetPhySize() const { return FinishPosition - StartPosition; } + CInArchiveInfo(): Base(0), MarkerPos(0), MarkerPos2(0), FinishPos(0), FileEndPos(0), + FirstItemRelatOffset(0), CdWasRead(false) {} + + UInt64 GetPhySize() const { return FinishPos - Base; } + UInt64 GetEmbeddedStubSize() const + { + if (CdWasRead) + return FirstItemRelatOffset; + return MarkerPos2 - Base; + } + bool ThereIsTail() const { return FileEndPos > FinishPos; } + void Clear() { Base = 0; - StartPosition = 0; - Comment.SetCapacity(0); + MarkerPos = 0; + MarkerPos2 = 0; + FinishPos = 0; + FileEndPos = 0; + + FirstItemRelatOffset = 0; + CdWasRead = false; + + Comment.Free(); } }; -class CProgressVirt +struct CProgressVirt { -public: - STDMETHOD(SetTotal)(UInt64 numFiles) PURE; - STDMETHOD(SetCompleted)(UInt64 numFiles) PURE; + virtual HRESULT SetCompletedLocal(UInt64 numFiles, UInt64 numBytes) = 0; + virtual HRESULT SetTotalCD(UInt64 numFiles) = 0; + virtual HRESULT SetCompletedCD(UInt64 numFiles) = 0; }; struct CCdInfo { - // UInt64 NumEntries; + UInt64 NumEntries; UInt64 Size; UInt64 Offset; + + void ParseEcd(const Byte *p); + void ParseEcd64(const Byte *p); }; class CInArchive { - CMyComPtr<IInStream> m_Stream; + CInBuffer _inBuffer; + bool _inBufMode; UInt32 m_Signature; - UInt64 m_StreamStartPosition; UInt64 m_Position; - - bool _inBufMode; - CInBuffer _inBuffer; HRESULT Seek(UInt64 offset); - HRESULT FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit); - void ReadFileName(UInt32 nameSize, AString &dest); - + HRESULT IncreaseRealPosition(UInt64 addValue); + HRESULT ReadBytes(void *data, UInt32 size, UInt32 *processedSize); - bool ReadBytesAndTestSize(void *data, UInt32 size); - void SafeReadBytes(void *data, UInt32 size); - void ReadBuffer(CByteBuffer &buffer, UInt32 size); + void SafeReadBytes(void *data, unsigned size); + void ReadBuffer(CByteBuffer &buffer, unsigned size); Byte ReadByte(); UInt16 ReadUInt16(); UInt32 ReadUInt32(); UInt64 ReadUInt64(); - bool ReadUInt32(UInt32 &signature); - - void Skip(UInt64 num); - void IncreaseRealPosition(UInt64 addValue); - - void ReadExtra(UInt32 extraSize, CExtraBlock &extraBlock, + 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); - HRESULT ReadLocalItem(CItemEx &item); + bool ReadLocalItem(CItemEx &item); HRESULT ReadLocalItemDescriptor(CItemEx &item); HRESULT ReadCdItem(CItemEx &item); HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo); HRESULT FindCd(CCdInfo &cdInfo); HRESULT TryReadCd(CObjectVector<CItemEx> &items, UInt64 cdOffset, UInt64 cdSize, CProgressVirt *progress); HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt64 &cdOffset, UInt64 &cdSize, CProgressVirt *progress); - HRESULT ReadLocalsAndCd(CObjectVector<CItemEx> &items, CProgressVirt *progress, UInt64 &cdOffset, int &numCdItems); + HRESULT ReadLocals(CObjectVector<CItemEx> &localItems, CProgressVirt *progress); + + HRESULT ReadHeaders2(CObjectVector<CItemEx> &items, CProgressVirt *progress); public: CInArchiveInfo ArcInfo; + + bool IsArc; bool IsZip64; - bool IsOkHeaders; - + bool HeadersError; + bool HeadersWarning; + bool ExtraMinorError; + bool UnexpectedEnd; + bool NoCentralDir; + + CMyComPtr<IInStream> Stream; + + void Close(); + HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); HRESULT ReadHeaders(CObjectVector<CItemEx> &items, CProgressVirt *progress); + + bool IsOpen() const { return Stream != NULL; } + bool AreThereErrors() const { return HeadersError || UnexpectedEnd; } + + bool IsLocalOffsetOK(const CItemEx &item) const + { + if (item.FromLocal) + return true; + return /* ArcInfo.Base >= 0 || */ ArcInfo.Base + (Int64)item.LocalHeaderPos >= 0; + } + HRESULT ReadLocalItemAfterCdItem(CItemEx &item); HRESULT ReadLocalItemAfterCdItemFull(CItemEx &item); - HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); - void Close(); - bool SeekInArchive(UInt64 position); + ISequentialInStream *CreateLimitedStream(UInt64 position, UInt64 size); - IInStream* CreateStream(); - bool IsOpen() const { return m_Stream != NULL; } + UInt64 GetOffsetInStream(UInt64 offsetFromArc) const { return ArcInfo.Base + offsetFromArc; } + + bool CanUpdate() const + { + if (AreThereErrors()) + return false; + if (ArcInfo.Base < 0) + return false; + if ((Int64)ArcInfo.MarkerPos2 < ArcInfo.Base) + return false; + + // 7-zip probably can update archives with embedded stubs. + // we just disable that feature for more safety. + if (ArcInfo.GetEmbeddedStubSize() != 0) + return false; + + if (ArcInfo.ThereIsTail()) + return false; + return true; + } }; }} diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp index ad89f558..ae88944d 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipItem.cpp +++ b/CPP/7zip/Archive/Zip/ZipItem.cpp @@ -10,21 +10,13 @@ namespace NArchive { namespace NZip { -bool operator==(const CVersion &v1, const CVersion &v2) -{ - return (v1.Version == v2.Version) && (v1.HostOS == v2.HostOS); -} +using namespace NFileHeader; -bool operator!=(const CVersion &v1, const CVersion &v2) -{ - return !(v1 == v2); -} - -bool CExtraSubBlock::ExtractNtfsTime(int index, FILETIME &ft) const +bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const { ft.dwHighDateTime = ft.dwLowDateTime = 0; - UInt32 size = (UInt32)Data.GetCapacity(); - if (ID != NFileHeader::NExtraID::kNTFS || size < 32) + UInt32 size = (UInt32)Data.Size(); + if (ID != NExtraID::kNTFS || size < 32) return false; const Byte *p = (const Byte *)Data; p += 4; // for reserved @@ -32,13 +24,13 @@ bool CExtraSubBlock::ExtractNtfsTime(int index, FILETIME &ft) const while (size > 4) { UInt16 tag = GetUi16(p); - UInt32 attrSize = GetUi16(p + 2); + unsigned attrSize = GetUi16(p + 2); p += 4; size -= 4; if (attrSize > size) attrSize = size; - if (tag == NFileHeader::NNtfsExtra::kTagTime && attrSize >= 24) + if (tag == NNtfsExtra::kTagTime && attrSize >= 24) { p += 8 * index; ft.dwLowDateTime = GetUi32(p); @@ -51,25 +43,25 @@ bool CExtraSubBlock::ExtractNtfsTime(int index, FILETIME &ft) const return false; } -bool CExtraSubBlock::ExtractUnixTime(bool isCentral, int index, UInt32 &res) const +bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const { res = 0; - UInt32 size = (UInt32)Data.GetCapacity(); - if (ID != NFileHeader::NExtraID::kUnixTime || size < 5) + UInt32 size = (UInt32)Data.Size(); + if (ID != NExtraID::kUnixTime || size < 5) return false; const Byte *p = (const Byte *)Data; Byte flags = *p++; size--; if (isCentral) { - if (index != NFileHeader::NUnixTime::kMTime || - (flags & (1 << NFileHeader::NUnixTime::kMTime)) == 0 || + if (index != NUnixTime::kMTime || + (flags & (1 << NUnixTime::kMTime)) == 0 || size < 4) return false; res = GetUi32(p); return true; } - for (int i = 0; i < 3; i++) + for (unsigned i = 0; i < 3; i++) if ((flags & (1 << i)) != 0) { if (size < 4) @@ -96,30 +88,33 @@ bool CItem::IsDir() const return true; if (!FromCentral) return false; - WORD highAttributes = WORD((ExternalAttributes >> 16 ) & 0xFFFF); - switch (MadeByVersion.HostOS) + + UInt16 highAttrib = (UInt16)((ExternalAttrib >> 16 ) & 0xFFFF); + + Byte hostOS = GetHostOS(); + switch (hostOS) { - case NFileHeader::NHostOS::kAMIGA: - switch (highAttributes & NFileHeader::NAmigaAttribute::kIFMT) + case NHostOS::kAMIGA: + switch (highAttrib & NAmigaAttrib::kIFMT) { - case NFileHeader::NAmigaAttribute::kIFDIR: return true; - case NFileHeader::NAmigaAttribute::kIFREG: return false; + case NAmigaAttrib::kIFDIR: return true; + case NAmigaAttrib::kIFREG: return false; default: return false; // change it throw kUnknownAttributes; } - case NFileHeader::NHostOS::kFAT: - case NFileHeader::NHostOS::kNTFS: - case NFileHeader::NHostOS::kHPFS: - case NFileHeader::NHostOS::kVFAT: - return ((ExternalAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); - case NFileHeader::NHostOS::kAtari: - case NFileHeader::NHostOS::kMac: - case NFileHeader::NHostOS::kVMS: - case NFileHeader::NHostOS::kVM_CMS: - case NFileHeader::NHostOS::kAcorn: - case NFileHeader::NHostOS::kMVS: + case NHostOS::kFAT: + case NHostOS::kNTFS: + case NHostOS::kHPFS: + case NHostOS::kVFAT: + return ((ExternalAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0); + case NHostOS::kAtari: + case NHostOS::kMac: + case NHostOS::kVMS: + case NHostOS::kVM_CMS: + case NHostOS::kAcorn: + case NHostOS::kMVS: return false; // change it throw kUnknownAttributes; - case NFileHeader::NHostOS::kUnix: - return (highAttributes & NFileHeader::NUnixAttribute::kIFDIR) != 0; + case NHostOS::kUnix: + return (highAttrib & NUnixAttrib::kIFDIR) != 0; default: return false; } @@ -127,13 +122,13 @@ bool CItem::IsDir() const UInt32 CItem::GetWinAttrib() const { - DWORD winAttrib = 0; - switch (MadeByVersion.HostOS) + UInt32 winAttrib = 0; + switch (GetHostOS()) { - case NFileHeader::NHostOS::kFAT: - case NFileHeader::NHostOS::kNTFS: + case NHostOS::kFAT: + case NHostOS::kNTFS: if (FromCentral) - winAttrib = ExternalAttributes; + winAttrib = ExternalAttrib; break; } if (IsDir()) // test it; @@ -144,35 +139,15 @@ UInt32 CItem::GetWinAttrib() const bool CItem::GetPosixAttrib(UInt32 &attrib) const { // some archivers can store PosixAttrib in high 16 bits even with HostOS=FAT. - if (FromCentral && MadeByVersion.HostOS == NFileHeader::NHostOS::kUnix) + if (FromCentral && GetHostOS() == NHostOS::kUnix) { - attrib = ExternalAttributes >> 16; + attrib = ExternalAttrib >> 16; return (attrib != 0); } attrib = 0; if (IsDir()) - attrib = NFileHeader::NUnixAttribute::kIFDIR; + attrib = NUnixAttrib::kIFDIR; return false; } -void CLocalItem::SetFlagBits(int startBitNumber, int numBits, int value) -{ - UInt16 mask = (UInt16)(((1 << numBits) - 1) << startBitNumber); - Flags &= ~mask; - Flags |= value << startBitNumber; -} - -void CLocalItem::SetBitMask(int bitMask, bool enable) -{ - if(enable) - Flags |= bitMask; - else - Flags &= ~bitMask; -} - -void CLocalItem::SetEncrypted(bool encrypted) - { SetBitMask(NFileHeader::NFlags::kEncrypted, encrypted); } -void CLocalItem::SetUtf8(bool isUtf8) - { SetBitMask(NFileHeader::NFlags::kUtf8, isUtf8); } - }} diff --git a/CPP/7zip/Archive/Zip/ZipItem.h b/CPP/7zip/Archive/Zip/ZipItem.h index 5efd433a..d50c3ae9 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipItem.h +++ b/CPP/7zip/Archive/Zip/ZipItem.h @@ -3,10 +3,12 @@ #ifndef __ARCHIVE_ZIP_ITEM_H #define __ARCHIVE_ZIP_ITEM_H -#include "Common/MyString.h" -#include "Common/Buffer.h" -#include "Common/UTFConvert.h" -#include "Common/StringConvert.h" +#include "../../../../C/CpuArch.h" + +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" #include "ZipHeader.h" @@ -19,25 +21,25 @@ struct CVersion Byte HostOS; }; -bool operator==(const CVersion &v1, const CVersion &v2); -bool operator!=(const CVersion &v1, const CVersion &v2); - struct CExtraSubBlock { UInt16 ID; CByteBuffer Data; - bool ExtractNtfsTime(int index, FILETIME &ft) const; - bool ExtractUnixTime(bool isCentral, int index, UInt32 &res) const; + + bool ExtractNtfsTime(unsigned index, FILETIME &ft) const; + bool ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const; }; -struct CWzAesExtraField +const unsigned k_WzAesExtra_Size = 7; + +struct CWzAesExtra { - UInt16 VendorVersion; // 0x0001 - AE-1, 0x0002 - AE-2, - // UInt16 VendorId; // "AE" - Byte Strength; // 1 - 128-bit , 2 - 192-bit , 3 - 256-bit + UInt16 VendorVersion; // 1: AE-1, 2: AE-2, + // UInt16 VendorId; // 'A' 'E' + Byte Strength; // 1: 128-bit, 2: 192-bit, 3: 256-bit UInt16 Method; - CWzAesExtraField(): VendorVersion(2), Strength(3), Method(0) {} + CWzAesExtra(): VendorVersion(2), Strength(3), Method(0) {} bool NeedCrc() const { return (VendorVersion == 1); } @@ -45,19 +47,21 @@ struct CWzAesExtraField { if (sb.ID != NFileHeader::NExtraID::kWzAES) return false; - if (sb.Data.GetCapacity() < 7) + if (sb.Data.Size() < k_WzAesExtra_Size) return false; const Byte *p = (const Byte *)sb.Data; - VendorVersion = (((UInt16)p[1]) << 8) | p[0]; + VendorVersion = GetUi16(p); if (p[2] != 'A' || p[3] != 'E') return false; Strength = p[4]; - Method = (((UInt16)p[6]) << 16) | p[5]; + // 9.31: The BUG was fixed: + Method = GetUi16(p + 5); return true; } + void SetSubBlock(CExtraSubBlock &sb) const { - sb.Data.SetCapacity(7); + sb.Data.Alloc(k_WzAesExtra_Size); sb.ID = NFileHeader::NExtraID::kWzAES; Byte *p = (Byte *)sb.Data; p[0] = (Byte)VendorVersion; @@ -70,7 +74,7 @@ struct CWzAesExtraField } }; -namespace NStrongCryptoFlags +namespace NStrongCrypto_AlgId { const UInt16 kDES = 0x6601; const UInt16 kRC2old = 0x6602; @@ -85,7 +89,7 @@ namespace NStrongCryptoFlags const UInt16 kRC4 = 0x6801; } -struct CStrongCryptoField +struct CStrongCryptoExtra { UInt16 Format; UInt16 AlgId; @@ -97,12 +101,12 @@ struct CStrongCryptoField if (sb.ID != NFileHeader::NExtraID::kStrongEncrypt) return false; const Byte *p = (const Byte *)sb.Data; - if (sb.Data.GetCapacity() < 8) + if (sb.Data.Size() < 8) return false; - Format = (((UInt16)p[1]) << 8) | p[0]; - AlgId = (((UInt16)p[3]) << 8) | p[2]; - BitLen = (((UInt16)p[5]) << 8) | p[4]; - Flags = (((UInt16)p[7]) << 8) | p[6]; + Format = GetUi16(p + 0); + AlgId = GetUi16(p + 2); + BitLen = GetUi16(p + 4); + Flags = GetUi16(p + 6); return (Format == 2); } }; @@ -110,39 +114,50 @@ struct CStrongCryptoField struct CExtraBlock { CObjectVector<CExtraSubBlock> SubBlocks; + void Clear() { SubBlocks.Clear(); } + size_t GetSize() const { size_t res = 0; - for (int i = 0; i < SubBlocks.Size(); i++) - res += SubBlocks[i].Data.GetCapacity() + 2 + 2; + FOR_VECTOR (i, SubBlocks) + res += SubBlocks[i].Data.Size() + 2 + 2; return res; } - bool GetWzAesField(CWzAesExtraField &aesField) const + + bool GetWzAes(CWzAesExtra &e) const { - for (int i = 0; i < SubBlocks.Size(); i++) - if (aesField.ParseFromSubBlock(SubBlocks[i])) + FOR_VECTOR (i, SubBlocks) + if (e.ParseFromSubBlock(SubBlocks[i])) return true; return false; } - bool GetStrongCryptoField(CStrongCryptoField &f) const + bool HasWzAes() const + { + CWzAesExtra e; + return GetWzAes(e); + } + + bool GetStrongCrypto(CStrongCryptoExtra &e) const { - for (int i = 0; i < SubBlocks.Size(); i++) - if (f.ParseFromSubBlock(SubBlocks[i])) + FOR_VECTOR (i, SubBlocks) + if (e.ParseFromSubBlock(SubBlocks[i])) return true; return false; } - bool HasWzAesField() const + /* + bool HasStrongCrypto() const { - CWzAesExtraField aesField; - return GetWzAesField(aesField); + CStrongCryptoExtra e; + return GetStrongCrypto(e); } + */ - bool GetNtfsTime(int index, FILETIME &ft) const + bool GetNtfsTime(unsigned index, FILETIME &ft) const { - for (int i = 0; i < SubBlocks.Size(); i++) + FOR_VECTOR (i, SubBlocks) { const CExtraSubBlock &sb = SubBlocks[i]; if (sb.ID == NFileHeader::NExtraID::kNTFS) @@ -151,9 +166,9 @@ struct CExtraBlock return false; } - bool GetUnixTime(bool isCentral, int index, UInt32 &res) const + bool GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const { - for (int i = 0; i < SubBlocks.Size(); i++) + FOR_VECTOR (i, SubBlocks) { const CExtraSubBlock &sb = SubBlocks[i]; if (sb.ID == NFileHeader::NExtraID::kUnixTime) @@ -162,14 +177,6 @@ struct CExtraBlock return false; } - /* - bool HasStrongCryptoField() const - { - CStrongCryptoField f; - return GetStrongCryptoField(f); - } - */ - void RemoveUnknownSubBlocks() { for (int i = SubBlocks.Size() - 1; i >= 0; i--) @@ -182,95 +189,134 @@ struct CExtraBlock class CLocalItem { public: - CVersion ExtractVersion; UInt16 Flags; - UInt16 CompressionMethod; - UInt32 Time; - UInt32 FileCRC; + UInt16 Method; + CVersion ExtractVersion; + + UInt64 Size; UInt64 PackSize; - UInt64 UnPackSize; + UInt32 Time; + UInt32 Crc; AString Name; CExtraBlock LocalExtra; 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() || CompressionMethod == NFileHeader::NCompressionMethod::kWzAES); }; - + 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; } bool IsDir() const; - bool IgnoreItem() const { return false; } - - bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; } - UString GetUnicodeString(const AString &s) const + /* + void GetUnicodeString(const AString &s, UString &res) const { - UString res; - if (IsUtf8()) - if (!ConvertUTF8ToUnicode(s, res)) - res.Empty(); - if (res.IsEmpty()) - res = MultiByteToUnicodeString(s, GetCodePage()); - return res; + bool isUtf8 = IsUtf8(); + if (isUtf8) + if (ConvertUTF8ToUnicode(s, res)) + return; + MultiByteToUnicodeString2(res, s, GetCodePage()); } - + */ + private: - void SetFlagBits(int startBitNumber, int numBits, int value); - void SetBitMask(int bitMask, bool enable); + + void SetFlag(unsigned bitMask, bool enable) + { + if (enable) + Flags |= bitMask; + else + Flags &= ~bitMask; + } + public: + void ClearFlags() { Flags = 0; } - void SetEncrypted(bool encrypted); - void SetUtf8(bool isUtf8); + void SetEncrypted(bool encrypted) { SetFlag(NFileHeader::NFlags::kEncrypted, encrypted); } + void SetUtf8(bool isUtf8) { SetFlag(NFileHeader::NFlags::kUtf8, isUtf8); } - WORD GetCodePage() const { return CP_OEMCP; } + UINT GetCodePage() const { return CP_OEMCP; } }; + class CItem: public CLocalItem { public: CVersion MadeByVersion; - UInt16 InternalAttributes; - UInt32 ExternalAttributes; + UInt16 InternalAttrib; + UInt32 ExternalAttrib; - UInt64 LocalHeaderPosition; + UInt64 LocalHeaderPos; - FILETIME NtfsMTime; - FILETIME NtfsATime; - FILETIME NtfsCTime; - CExtraBlock CentralExtra; CByteBuffer Comment; bool FromLocal; bool FromCentral; - bool NtfsTimeIsDefined; + // CItem can be used as CLocalItem. So we must clear unused fields + CItem(): + InternalAttrib(0), + ExternalAttrib(0), + FromLocal(false), + FromCentral(false) + { + MadeByVersion.Version = 0; + MadeByVersion.HostOS = 0; + } + bool IsDir() const; UInt32 GetWinAttrib() const; bool GetPosixAttrib(UInt32 &attrib) const; + Byte GetHostOS() const { return FromCentral ? MadeByVersion.HostOS : ExtractVersion.HostOS; } + + void GetUnicodeString(const AString &s, UString &res, bool useSpecifiedCodePage, UINT codePage) const + { + bool isUtf8 = IsUtf8(); + + #ifdef _WIN32 + if (!isUtf8) + { + if (useSpecifiedCodePage) + isUtf8 = (codePage == CP_UTF8); + else if (GetHostOS() == NFileHeader::NHostOS::kUnix) + { + /* Some ZIP archives in Unix use UTF-8 encoding without Utf8 flag in header. + We try to get name as UTF-8. + Do we need to do it in POSIX version also? */ + isUtf8 = true; + } + } + #endif + + if (isUtf8) + if (ConvertUTF8ToUnicode(s, res)) + return; + MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage()); + } + bool IsThereCrc() const { - if (CompressionMethod == NFileHeader::NCompressionMethod::kWzAES) + if (Method == NFileHeader::NCompressionMethod::kWzAES) { - CWzAesExtraField aesField; - if (CentralExtra.GetWzAesField(aesField)) + CWzAesExtra aesField; + if (CentralExtra.GetWzAes(aesField)) return aesField.NeedCrc(); } - return (FileCRC != 0 || !IsDir()); + return (Crc != 0 || !IsDir()); } - WORD GetCodePage() const + UINT GetCodePage() const { - return (WORD)((MadeByVersion.HostOS == NFileHeader::NHostOS::kFAT - || MadeByVersion.HostOS == NFileHeader::NHostOS::kNTFS - ) ? CP_OEMCP : CP_ACP); + Byte hostOS = GetHostOS(); + return (UINT)(( + hostOS == NFileHeader::NHostOS::kFAT || + hostOS == NFileHeader::NHostOS::kNTFS) ? CP_OEMCP : CP_ACP); } - CItem() : FromLocal(false), FromCentral(false), NtfsTimeIsDefined(false) {} }; }} diff --git a/CPP/7zip/Archive/Zip/ZipItemEx.h b/CPP/7zip/Archive/Zip/ZipItemEx.h deleted file mode 100755 index ab62cdbb..00000000 --- a/CPP/7zip/Archive/Zip/ZipItemEx.h +++ /dev/null @@ -1,34 +0,0 @@ -// Archive/ZipItemEx.h - -#ifndef __ARCHIVE_ZIP_ITEMEX_H -#define __ARCHIVE_ZIP_ITEMEX_H - -#include "ZipHeader.h" -#include "ZipItem.h" - -namespace NArchive { -namespace NZip { - -class CItemEx: public CItem -{ -public: - UInt32 FileHeaderWithNameSize; - UInt16 LocalExtraSize; - - UInt64 GetLocalFullSize() const - { return FileHeaderWithNameSize + LocalExtraSize + PackSize + - (HasDescriptor() ? NFileHeader::kDataDescriptorSize : 0); }; - /* - UInt64 GetLocalFullSize(bool isZip64) const - { return FileHeaderWithNameSize + LocalExtraSize + PackSize + - (HasDescriptor() ? (isZip64 ? NFileHeader::kDataDescriptor64Size : NFileHeader::kDataDescriptorSize) : 0); }; - */ - UInt64 GetLocalExtraPosition() const - { return LocalHeaderPosition + FileHeaderWithNameSize; }; - UInt64 GetDataPosition() const - { return GetLocalExtraPosition() + LocalExtraSize; }; -}; - -}} - -#endif diff --git a/CPP/7zip/Archive/Zip/ZipOut.cpp b/CPP/7zip/Archive/Zip/ZipOut.cpp index aa82143e..2a1ba2c4 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipOut.cpp @@ -9,80 +9,93 @@ namespace NArchive { namespace NZip { -void COutArchive::Create(IOutStream *outStream) +HRESULT COutArchive::Create(IOutStream *outStream) { + m_CurPos = 0; if (!m_OutBuffer.Create(1 << 16)) - throw CSystemException(E_OUTOFMEMORY); + return E_OUTOFMEMORY; m_Stream = outStream; m_OutBuffer.SetStream(outStream); m_OutBuffer.Init(); - m_BasePosition = 0; + + return m_Stream->Seek(0, STREAM_SEEK_CUR, &m_Base); +} + +void COutArchive::MoveCurPos(UInt64 distanceToMove) +{ + m_CurPos += distanceToMove; // test overflow } -void COutArchive::MoveBasePosition(UInt64 distanceToMove) +void COutArchive::SeekToRelatPos(UInt64 offset) { - m_BasePosition += distanceToMove; // test overflow + HRESULT res = m_Stream->Seek(m_Base + offset, STREAM_SEEK_SET, NULL); + if (res != S_OK) + throw CSystemException(res); } -void COutArchive::PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption) +void COutArchive::PrepareWriteCompressedDataZip64(unsigned fileNameLen, bool isZip64, bool aesEncryption) { m_IsZip64 = isZip64; m_ExtraSize = isZip64 ? (4 + 8 + 8) : 0; if (aesEncryption) - m_ExtraSize += 4 + 7; - m_LocalFileHeaderSize = 4 + NFileHeader::kLocalBlockSize + fileNameLength + m_ExtraSize; + m_ExtraSize += 4 + k_WzAesExtra_Size; + m_LocalFileHeaderSize = kLocalHeaderSize + fileNameLen + m_ExtraSize; } -void COutArchive::PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption) +void COutArchive::PrepareWriteCompressedData(unsigned fileNameLen, UInt64 unPackSize, bool aesEncryption) { - // We test it to 0xF8000000 to support case when compressed size - // can be larger than uncompressed size. - PrepareWriteCompressedDataZip64(fileNameLength, unPackSize >= 0xF8000000, 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); } -void COutArchive::PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption) +#define DOES_NEED_ZIP64(v) (v >= (UInt32)0xFFFFFFFF) + +void COutArchive::PrepareWriteCompressedData2(unsigned fileNameLen, UInt64 unPackSize, UInt64 packSize, bool aesEncryption) { - bool isUnPack64 = unPackSize >= 0xFFFFFFFF; - bool isPack64 = packSize >= 0xFFFFFFFF; - bool isZip64 = isPack64 || isUnPack64; - PrepareWriteCompressedDataZip64(fileNameLength, isZip64, aesEncryption); + bool isZip64 = + DOES_NEED_ZIP64(unPackSize) || + DOES_NEED_ZIP64(packSize); + PrepareWriteCompressedDataZip64(fileNameLen, isZip64, aesEncryption); } void COutArchive::WriteBytes(const void *buffer, UInt32 size) { m_OutBuffer.WriteBytes(buffer, size); - m_BasePosition += size; + m_CurPos += size; } -void COutArchive::WriteByte(Byte b) +void COutArchive::Write8(Byte b) { - WriteBytes(&b, 1); + m_OutBuffer.WriteByte(b); + m_CurPos++; } -void COutArchive::WriteUInt16(UInt16 value) +void COutArchive::Write16(UInt16 val) { for (int i = 0; i < 2; i++) { - WriteByte((Byte)value); - value >>= 8; + Write8((Byte)val); + val >>= 8; } } -void COutArchive::WriteUInt32(UInt32 value) +void COutArchive::Write32(UInt32 val) { for (int i = 0; i < 4; i++) { - WriteByte((Byte)value); - value >>= 8; + Write8((Byte)val); + val >>= 8; } } -void COutArchive::WriteUInt64(UInt64 value) +void COutArchive::Write64(UInt64 val) { for (int i = 0; i < 8; i++) { - WriteByte((Byte)value); - value >>= 8; + Write8((Byte)val); + val >>= 8; } } @@ -90,178 +103,181 @@ void COutArchive::WriteExtra(const CExtraBlock &extra) { if (extra.SubBlocks.Size() != 0) { - for (int i = 0; i < extra.SubBlocks.Size(); i++) + FOR_VECTOR (i, extra.SubBlocks) { const CExtraSubBlock &subBlock = extra.SubBlocks[i]; - WriteUInt16(subBlock.ID); - WriteUInt16((UInt16)subBlock.Data.GetCapacity()); - WriteBytes(subBlock.Data, (UInt32)subBlock.Data.GetCapacity()); + Write16(subBlock.ID); + Write16((UInt16)subBlock.Data.Size()); + WriteBytes(subBlock.Data, (UInt32)subBlock.Data.Size()); } } } -void COutArchive::SeekTo(UInt64 offset) +void COutArchive::WriteCommonItemInfo(const CLocalItem &item, bool isZip64) { - HRESULT res = m_Stream->Seek(offset, STREAM_SEEK_SET, NULL); - if (res != S_OK) - throw CSystemException(res); + { + Byte ver = item.ExtractVersion.Version; + if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64) + ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64; + Write8(ver); + } + Write8(item.ExtractVersion.HostOS); + 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) { - SeekTo(m_BasePosition); + SeekToCurPos(); - bool isZip64 = m_IsZip64 || item.PackSize >= 0xFFFFFFFF || item.UnPackSize >= 0xFFFFFFFF; + bool isZip64 = m_IsZip64 || + DOES_NEED_ZIP64(item.PackSize) || + DOES_NEED_ZIP64(item.Size); - WriteUInt32(NSignature::kLocalFileHeader); - { - Byte ver = item.ExtractVersion.Version; - if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64) - ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64; - WriteByte(ver); - } - WriteByte(item.ExtractVersion.HostOS); - WriteUInt16(item.Flags); - WriteUInt16(item.CompressionMethod); - WriteUInt32(item.Time); - WriteUInt32(item.FileCRC); - WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.PackSize); - WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize); - WriteUInt16((UInt16)item.Name.Length()); + Write32(NSignature::kLocalFileHeader); + WriteCommonItemInfo(item, isZip64); + + WRITE_32_VAL_SPEC(item.PackSize, isZip64); + WRITE_32_VAL_SPEC(item.Size, isZip64); + + Write16((UInt16)item.Name.Len()); { - UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 16): 0) + item.LocalExtra.GetSize()); - if (localExtraSize > m_ExtraSize) + UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 8 + 8): 0) + item.LocalExtra.GetSize()); + if (localExtraSize != m_ExtraSize) throw CSystemException(E_FAIL); } - WriteUInt16((UInt16)m_ExtraSize); // test it; - WriteBytes((const char *)item.Name, item.Name.Length()); + Write16((UInt16)m_ExtraSize); + WriteBytes((const char *)item.Name, item.Name.Len()); - UInt32 extraPos = 0; if (isZip64) { - extraPos += 4 + 16; - WriteUInt16(NFileHeader::NExtraID::kZip64); - WriteUInt16(16); - WriteUInt64(item.UnPackSize); - WriteUInt64(item.PackSize); + Write16(NFileHeader::NExtraID::kZip64); + Write16(8 + 8); + Write64(item.Size); + Write64(item.PackSize); } WriteExtra(item.LocalExtra); - extraPos += (UInt32)item.LocalExtra.GetSize(); - for (; extraPos < m_ExtraSize; extraPos++) - WriteByte(0); + + // Why don't we write NTFS timestamps to local header? + // Probably we want to reduce size of archive? m_OutBuffer.FlushWithCheck(); - MoveBasePosition(item.PackSize); - SeekTo(m_BasePosition); + MoveCurPos(item.PackSize); } -void COutArchive::WriteCentralHeader(const CItem &item) +void COutArchive::WriteCentralHeader(const CItemOut &item) { - bool isUnPack64 = item.UnPackSize >= 0xFFFFFFFF; - bool isPack64 = item.PackSize >= 0xFFFFFFFF; - bool isPosition64 = item.LocalHeaderPosition >= 0xFFFFFFFF; - bool isZip64 = isPack64 || isUnPack64 || isPosition64; + bool isUnPack64 = DOES_NEED_ZIP64(item.Size); + bool isPack64 = DOES_NEED_ZIP64(item.PackSize); + bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos); + bool isZip64 = isPack64 || isUnPack64 || isPosition64; - WriteUInt32(NSignature::kCentralFileHeader); - WriteByte(item.MadeByVersion.Version); - WriteByte(item.MadeByVersion.HostOS); - { - Byte ver = item.ExtractVersion.Version; - if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64) - ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64; - WriteByte(ver); - } - WriteByte(item.ExtractVersion.HostOS); - WriteUInt16(item.Flags); - WriteUInt16(item.CompressionMethod); - WriteUInt32(item.Time); - WriteUInt32(item.FileCRC); - WriteUInt32(isPack64 ? 0xFFFFFFFF: (UInt32)item.PackSize); - WriteUInt32(isUnPack64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize); - WriteUInt16((UInt16)item.Name.Length()); - UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0)); + Write32(NSignature::kCentralFileHeader); + Write8(item.MadeByVersion.Version); + Write8(item.MadeByVersion.HostOS); + + WriteCommonItemInfo(item, isZip64); + + WRITE_32_VAL_SPEC(item.PackSize, isPack64); + WRITE_32_VAL_SPEC(item.Size, isUnPack64); + + Write16((UInt16)item.Name.Len()); + + UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0)); const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8); - UInt16 centralExtraSize = (UInt16)(isZip64 ? (4 + zip64ExtraSize) : 0) + (item.NtfsTimeIsDefined ? (4 + kNtfsExtraSize) : 0); - centralExtraSize = (UInt16)(centralExtraSize + item.CentralExtra.GetSize()); - WriteUInt16(centralExtraSize); // test it; - WriteUInt16((UInt16)item.Comment.GetCapacity()); - WriteUInt16(0); // DiskNumberStart; - WriteUInt16(item.InternalAttributes); - WriteUInt32(item.ExternalAttributes); - WriteUInt32(isPosition64 ? 0xFFFFFFFF: (UInt32)item.LocalHeaderPosition); - WriteBytes((const char *)item.Name, item.Name.Length()); + const UInt16 centralExtraSize = (UInt16)( + (isZip64 ? 4 + zip64ExtraSize : 0) + + (item.NtfsTimeIsDefined ? 4 + kNtfsExtraSize : 0) + + item.CentralExtra.GetSize()); + + Write16(centralExtraSize); // test it; + Write16((UInt16)item.Comment.Size()); + Write16(0); // DiskNumberStart; + Write16(item.InternalAttrib); + Write32(item.ExternalAttrib); + WRITE_32_VAL_SPEC(item.LocalHeaderPos, isPosition64); + WriteBytes((const char *)item.Name, item.Name.Len()); + if (isZip64) { - WriteUInt16(NFileHeader::NExtraID::kZip64); - WriteUInt16(zip64ExtraSize); - if(isUnPack64) - WriteUInt64(item.UnPackSize); - if(isPack64) - WriteUInt64(item.PackSize); - if(isPosition64) - WriteUInt64(item.LocalHeaderPosition); + Write16(NFileHeader::NExtraID::kZip64); + Write16(zip64ExtraSize); + if (isUnPack64) + Write64(item.Size); + if (isPack64) + Write64(item.PackSize); + if (isPosition64) + Write64(item.LocalHeaderPos); } + if (item.NtfsTimeIsDefined) { - WriteUInt16(NFileHeader::NExtraID::kNTFS); - WriteUInt16(kNtfsExtraSize); - WriteUInt32(0); // reserved - WriteUInt16(NFileHeader::NNtfsExtra::kTagTime); - WriteUInt16(8 * 3); - WriteUInt32(item.NtfsMTime.dwLowDateTime); - WriteUInt32(item.NtfsMTime.dwHighDateTime); - WriteUInt32(item.NtfsATime.dwLowDateTime); - WriteUInt32(item.NtfsATime.dwHighDateTime); - WriteUInt32(item.NtfsCTime.dwLowDateTime); - WriteUInt32(item.NtfsCTime.dwHighDateTime); + Write16(NFileHeader::NExtraID::kNTFS); + Write16(kNtfsExtraSize); + Write32(0); // reserved + Write16(NFileHeader::NNtfsExtra::kTagTime); + Write16(8 * 3); + WriteNtfsTime(item.Ntfs_MTime); + WriteNtfsTime(item.Ntfs_ATime); + WriteNtfsTime(item.Ntfs_CTime); } + WriteExtra(item.CentralExtra); - if (item.Comment.GetCapacity() > 0) - WriteBytes(item.Comment, (UInt32)item.Comment.GetCapacity()); + if (item.Comment.Size() > 0) + WriteBytes(item.Comment, (UInt32)item.Comment.Size()); } -void COutArchive::WriteCentralDir(const CObjectVector<CItem> &items, const CByteBuffer *comment) +void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment) { - SeekTo(m_BasePosition); + SeekToCurPos(); - UInt64 cdOffset = GetCurrentPosition(); - for(int i = 0; i < items.Size(); i++) + UInt64 cdOffset = GetCurPos(); + FOR_VECTOR (i, items) WriteCentralHeader(items[i]); - UInt64 cd64EndOffset = GetCurrentPosition(); + UInt64 cd64EndOffset = GetCurPos(); UInt64 cdSize = cd64EndOffset - cdOffset; - bool cdOffset64 = cdOffset >= 0xFFFFFFFF; - bool cdSize64 = cdSize >= 0xFFFFFFFF; + bool cdOffset64 = DOES_NEED_ZIP64(cdOffset); + bool cdSize64 = DOES_NEED_ZIP64(cdSize); bool items64 = items.Size() >= 0xFFFF; bool isZip64 = (cdOffset64 || cdSize64 || items64); + + // isZip64 = true; // to test Zip64 if (isZip64) { - WriteUInt32(NSignature::kZip64EndOfCentralDir); - WriteUInt64(kZip64EcdSize); // ThisDiskNumber = 0; - WriteUInt16(45); // version - WriteUInt16(45); // version - WriteUInt32(0); // ThisDiskNumber = 0; - WriteUInt32(0); // StartCentralDirectoryDiskNumber;; - WriteUInt64((UInt64)items.Size()); - WriteUInt64((UInt64)items.Size()); - WriteUInt64((UInt64)cdSize); - WriteUInt64((UInt64)cdOffset); - - WriteUInt32(NSignature::kZip64EndOfCentralDirLocator); - WriteUInt32(0); // number of the disk with the start of the zip64 end of central directory - WriteUInt64(cd64EndOffset); - WriteUInt32(1); // total number of disks + Write32(NSignature::kEcd64); + Write64(kEcd64_MainSize); + Write16(45); // made by version + Write16(45); // extract version + Write32(0); // ThisDiskNumber = 0; + Write32(0); // StartCentralDirectoryDiskNumber;; + Write64((UInt64)items.Size()); + Write64((UInt64)items.Size()); + Write64((UInt64)cdSize); + Write64((UInt64)cdOffset); + + Write32(NSignature::kEcd64Locator); + Write32(0); // number of the disk with the start of the zip64 end of central directory + Write64(cd64EndOffset); + Write32(1); // total number of disks } - WriteUInt32(NSignature::kEndOfCentralDir); - WriteUInt16(0); // ThisDiskNumber = 0; - WriteUInt16(0); // StartCentralDirectoryDiskNumber; - WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size())); - WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size())); - WriteUInt32(cdSize64 ? 0xFFFFFFFF: (UInt32)cdSize); - WriteUInt32(cdOffset64 ? 0xFFFFFFFF: (UInt32)cdOffset); - UInt32 commentSize = (UInt32)(comment ? comment->GetCapacity() : 0); - WriteUInt16((UInt16)commentSize); + + Write32(NSignature::kEcd); + Write16(0); // ThisDiskNumber = 0; + Write16(0); // StartCentralDirectoryDiskNumber; + Write16((UInt16)(items64 ? 0xFFFF: items.Size())); + Write16((UInt16)(items64 ? 0xFFFF: items.Size())); + + WRITE_32_VAL_SPEC(cdSize, cdSize64); + WRITE_32_VAL_SPEC(cdOffset, cdOffset64); + + UInt32 commentSize = (UInt32)(comment ? comment->Size() : 0); + Write16((UInt16)commentSize); if (commentSize > 0) WriteBytes((const Byte *)*comment, commentSize); m_OutBuffer.FlushWithCheck(); @@ -271,14 +287,21 @@ void COutArchive::CreateStreamForCompressing(IOutStream **outStream) { COffsetOutStream *streamSpec = new COffsetOutStream; CMyComPtr<IOutStream> tempStream(streamSpec); - streamSpec->Init(m_Stream, m_BasePosition + m_LocalFileHeaderSize); + 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); +} void COutArchive::CreateStreamForCopying(ISequentialOutStream **outStream) { diff --git a/CPP/7zip/Archive/Zip/ZipOut.h b/CPP/7zip/Archive/Zip/ZipOut.h index 2f6349e5..eaaa0320 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipOut.h +++ b/CPP/7zip/Archive/Zip/ZipOut.h @@ -3,7 +3,7 @@ #ifndef __ZIP_OUT_H #define __ZIP_OUT_H -#include "Common/MyCom.h" +#include "../../../Common/MyCom.h" #include "../../IStream.h" #include "../../Common/OutBuffer.h" @@ -14,41 +14,73 @@ namespace NArchive { namespace NZip { // can throw CSystemException and COutBufferException - + +class CItemOut: public CItem +{ +public: + FILETIME Ntfs_MTime; + FILETIME Ntfs_ATime; + FILETIME Ntfs_CTime; + bool NtfsTimeIsDefined; + + // It's possible that NtfsTime is not defined, but there is NtfsTime in Extra. + + CItemOut(): NtfsTimeIsDefined(false) {} +}; + class COutArchive { CMyComPtr<IOutStream> m_Stream; COutBuffer m_OutBuffer; - UInt64 m_BasePosition; + UInt64 m_Base; // Base of arc (offset in output Stream) + UInt64 m_CurPos; // Curent position in archive (relative from m_Base) + UInt32 m_LocalFileHeaderSize; UInt32 m_ExtraSize; bool m_IsZip64; + void SeekToRelatPos(UInt64 offset); + void WriteBytes(const void *buffer, UInt32 size); - void WriteByte(Byte b); - void WriteUInt16(UInt16 value); - void WriteUInt32(UInt32 value); - void WriteUInt64(UInt64 value); + void Write8(Byte b); + void Write16(UInt16 val); + void Write32(UInt32 val); + void Write64(UInt64 val); + void WriteNtfsTime(const FILETIME &ft) + { + Write32(ft.dwLowDateTime); + Write32(ft.dwHighDateTime); + } - void WriteExtraHeader(const CItem &item); - void WriteCentralHeader(const CItem &item); void WriteExtra(const CExtraBlock &extra); - void SeekTo(UInt64 offset); + void WriteCommonItemInfo(const CLocalItem &item, bool isZip64); + void WriteCentralHeader(const CItemOut &item); + + void PrepareWriteCompressedDataZip64(unsigned fileNameLen, bool isZip64, bool aesEncryption); + public: - void Create(IOutStream *outStream); - void MoveBasePosition(UInt64 distanceToMove); - UInt64 GetCurrentPosition() const { return m_BasePosition; }; - void PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption); - void PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption); - void PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption); + 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 WriteCentralDir(const CObjectVector<CItem> &items, const CByteBuffer *comment); + void WriteLocalHeader_And_SeekToNextFile(const CLocalItem &item) + { + WriteLocalHeader(item); + SeekToCurPos(); + } + + void WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment); void CreateStreamForCompressing(IOutStream **outStream); void CreateStreamForCopying(ISequentialOutStream **outStream); - void SeekToPackedDataPosition(); }; }} diff --git a/CPP/7zip/Archive/Zip/ZipRegister.cpp b/CPP/7zip/Archive/Zip/ZipRegister.cpp index 3e7aade8..545e76c6 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipRegister.cpp +++ b/CPP/7zip/Archive/Zip/ZipRegister.cpp @@ -5,14 +5,27 @@ #include "../../Common/RegisterArc.h" #include "ZipHandler.h" -static IInArchive *CreateArc() { return new NArchive::NZip::CHandler; } -#ifndef EXTRACT_ONLY -static IOutArchive *CreateArcOut() { return new NArchive::NZip::CHandler; } -#else -#define CreateArcOut 0 -#endif + +namespace NArchive { +namespace NZip { + +IMP_CreateArcIn +IMP_CreateArcOut static CArcInfo g_ArcInfo = - { L"zip", L"zip jar xpi odt ods docx xlsx", 0, 1, { 0x50, 0x4B, 0x03, 0x04 }, 4, false, CreateArc, CreateArcOut }; + { "zip", "zip zipx jar xpi odt ods docx xlsx epub", 0, 1, + 3 + 4 + 4 + 6, + { + 4, 0x50, 0x4B, 0x03, 0x04, + 4, 0x50, 0x4B, 0x05, 0x06, + 6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B, + }, + 0, + NArcInfoFlags::kFindSignature | + NArcInfoFlags::kMultiSignature | + NArcInfoFlags::kUseGlobalOffset, + REF_CreateArc_Pair, IsArc_Zip }; REGISTER_ARC(Zip) + +}} diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index a91364be..2978e387 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -4,12 +4,12 @@ #include "../../../../C/Alloc.h" -#include "Common/AutoPtr.h" -#include "Common/Defs.h" -#include "Common/StringConvert.h" +#include "../../../Common/AutoPtr.h" +#include "../../../Common/Defs.h" +#include "../../../Common/StringConvert.h" -#include "Windows/Defs.h" -#include "Windows/Thread.h" +#include "../../../Windows/Defs.h" +#include "../../../Windows/Thread.h" #include "../../Common/CreateCoder.h" #include "../../Common/LimitedStreams.h" @@ -44,12 +44,12 @@ static const Byte kExtractHostOS = kHostOS; static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStored; -static HRESULT CopyBlockToArchive(ISequentialInStream *inStream, +static HRESULT CopyBlockToArchive(ISequentialInStream *inStream, UInt64 size, COutArchive &outArchive, ICompressProgressInfo *progress) { CMyComPtr<ISequentialOutStream> outStream; outArchive.CreateStreamForCopying(&outStream); - return NCompress::CopyStream(inStream, outStream, progress); + return NCompress::CopyStream_ExactSize(inStream, outStream, size, progress); } static HRESULT WriteRange(IInStream *inStream, COutArchive &outArchive, @@ -57,13 +57,7 @@ static HRESULT WriteRange(IInStream *inStream, COutArchive &outArchive, { UInt64 position; RINOK(inStream->Seek(range.Position, STREAM_SEEK_SET, &position)); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec); - streamSpec->SetStream(inStream); - streamSpec->Init(range.Size); - - RINOK(CopyBlockToArchive(inStreamLimited, outArchive, progress)); + RINOK(CopyBlockToArchive(inStream, range.Size, outArchive, progress)); return progress->SetRatioInfo(&range.Size, &range.Size); } @@ -71,42 +65,42 @@ static void SetFileHeader( COutArchive &archive, const CCompressionMethodMode &options, const CUpdateItem &ui, - CItem &item) + CItemOut &item) { - item.UnPackSize = ui.Size; + item.Size = ui.Size; bool isDir; item.ClearFlags(); - if (ui.NewProperties) + if (ui.NewProps) { isDir = ui.IsDir; item.Name = ui.Name; item.SetUtf8(ui.IsUtf8); - item.ExternalAttributes = ui.Attributes; + item.ExternalAttrib = ui.Attrib; item.Time = ui.Time; - item.NtfsMTime = ui.NtfsMTime; - item.NtfsATime = ui.NtfsATime; - item.NtfsCTime = ui.NtfsCTime; + item.Ntfs_MTime = ui.Ntfs_MTime; + item.Ntfs_ATime = ui.Ntfs_ATime; + item.Ntfs_CTime = ui.Ntfs_CTime; item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined; } else isDir = item.IsDir(); - item.LocalHeaderPosition = archive.GetCurrentPosition(); + item.LocalHeaderPos = archive.GetCurPos(); item.MadeByVersion.HostOS = kMadeByHostOS; item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion; item.ExtractVersion.HostOS = kExtractHostOS; - item.InternalAttributes = 0; // test it + item.InternalAttrib = 0; // test it item.SetEncrypted(!isDir && options.PasswordIsDefined); if (isDir) { item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir; - item.CompressionMethod = kMethodForDirectory; + item.Method = kMethodForDirectory; item.PackSize = 0; - item.FileCRC = 0; // test it + item.Crc = 0; // test it } } @@ -114,9 +108,9 @@ static void SetItemInfoFromCompressingResult(const CCompressingResult &compressi bool isAesMode, Byte aesKeyMode, CItem &item) { item.ExtractVersion.Version = compressingResult.ExtractVersion; - item.CompressionMethod = compressingResult.Method; - item.FileCRC = compressingResult.CRC; - item.UnPackSize = compressingResult.UnpackSize; + item.Method = compressingResult.Method; + item.Crc = compressingResult.CRC; + item.Size = compressingResult.UnpackSize; item.PackSize = compressingResult.PackSize; item.LocalExtra.Clear(); @@ -124,11 +118,11 @@ static void SetItemInfoFromCompressingResult(const CCompressingResult &compressi if (isAesMode) { - CWzAesExtraField wzAesField; + CWzAesExtra wzAesField; wzAesField.Strength = aesKeyMode; wzAesField.Method = compressingResult.Method; - item.CompressionMethod = NFileHeader::NCompressionMethod::kWzAES; - item.FileCRC = 0; + item.Method = NFileHeader::NCompressionMethod::kWzAES; + item.Crc = 0; CExtraSubBlock sb; wzAesField.SetSubBlock(sb); item.LocalExtra.SubBlocks.Add(sb); @@ -142,10 +136,7 @@ static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo); struct CThreadInfo { - #ifdef EXTERNAL_CODECS - CMyComPtr<ICompressCodecsInfo> _codecsInfo; - const CObjectVector<CCodecInfoEx> *_externalCodecs; - #endif + DECL_EXTERNAL_CODECS_LOC_VARS2; NWindows::CThread Thread; NWindows::NSynchronization::CAutoResetEvent CompressEvent; @@ -202,9 +193,7 @@ void CThreadInfo::WaitAndCode() if (ExitThread) return; Result = Coder.Compress( - #ifdef EXTERNAL_CODECS - _codecsInfo, _externalCodecs, - #endif + EXTERNAL_CODECS_LOC_VARS InStream, OutStream, Progress, CompressingResult); if (Result == S_OK && Progress) Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize); @@ -224,7 +213,7 @@ public: CObjectVector<CThreadInfo> Threads; ~CThreads() { - for (int i = 0; i < Threads.Size(); i++) + FOR_VECTOR (i, Threads) Threads[i].StopWaitClose(); } }; @@ -245,7 +234,7 @@ public: CMemRefs(CMemBlockManagerMt *manager): Manager(manager) {} ; ~CMemRefs() { - for (int i = 0; i < Refs.Size(); i++) + FOR_VECTOR (i, Refs) Refs[i].FreeOpt(Manager); } }; @@ -335,69 +324,74 @@ STDMETHODIMP CMtProgressMixer::SetRatioInfo(const UInt64 *inSize, const UInt64 * #endif -static HRESULT UpdateItemOldData(COutArchive &archive, - IInStream *inStream, - const CUpdateItem &ui, CItemEx &item, +static HRESULT UpdateItemOldData( + COutArchive &archive, + CInArchive *inArchive, + const CItemEx &itemEx, + const CUpdateItem &ui, + CItemOut &item, /* bool izZip64, */ ICompressProgressInfo *progress, UInt64 &complexity) { - if (ui.NewProperties) + if (ui.NewProps) { if (item.HasDescriptor()) return E_NOTIMPL; // use old name size. // CUpdateRange range(item.GetLocalExtraPosition(), item.LocalExtraSize + item.PackSize); - CUpdateRange range(item.GetDataPosition(), item.PackSize); + CUpdateRange range(inArchive->GetOffsetInStream(itemEx.GetDataPosition()), itemEx.PackSize); - // item.ExternalAttributes = ui.Attributes; - // Test it + // we keep ExternalAttrib and some another properties from old archive + // item.ExternalAttrib = ui.Attrib; + item.Name = ui.Name; item.SetUtf8(ui.IsUtf8); item.Time = ui.Time; - item.NtfsMTime = ui.NtfsMTime; - item.NtfsATime = ui.NtfsATime; - item.NtfsCTime = ui.NtfsCTime; + item.Ntfs_MTime = ui.Ntfs_MTime; + item.Ntfs_ATime = ui.Ntfs_ATime; + item.Ntfs_CTime = ui.Ntfs_CTime; item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined; item.CentralExtra.RemoveUnknownSubBlocks(); item.LocalExtra.RemoveUnknownSubBlocks(); - - archive.PrepareWriteCompressedData2((UInt16)item.Name.Length(), item.UnPackSize, item.PackSize, item.LocalExtra.HasWzAesField()); - item.LocalHeaderPosition = archive.GetCurrentPosition(); - archive.SeekToPackedDataPosition(); - RINOK(WriteRange(inStream, archive, range, progress)); - complexity += range.Size; + item.LocalHeaderPos = archive.GetCurPos(); + + archive.PrepareWriteCompressedData2(item.Name.Len(), item.Size, item.PackSize, item.LocalExtra.HasWzAes()); archive.WriteLocalHeader(item); + RINOK(WriteRange(inArchive->Stream, archive, range, progress)); + complexity += range.Size; } else { - CUpdateRange range(item.LocalHeaderPosition, item.GetLocalFullSize()); + CUpdateRange range(inArchive->GetOffsetInStream(itemEx.LocalHeaderPos), itemEx.GetLocalFullSize()); // set new header position - item.LocalHeaderPosition = archive.GetCurrentPosition(); + item.LocalHeaderPos = archive.GetCurPos(); - RINOK(WriteRange(inStream, archive, range, progress)); + RINOK(WriteRange(inArchive->Stream, archive, range, progress)); complexity += range.Size; - archive.MoveBasePosition(range.Size); + archive.MoveCurPos(range.Size); } return S_OK; } static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options, - const CUpdateItem &ui, CItemEx &item) + const CUpdateItem &ui, CItemOut &item) { SetFileHeader(archive, *options, ui, item); - archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsRealAesMode()); - archive.WriteLocalHeader(item); + archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, + // options->IsRealAesMode() + false // fixed 9.31 + ); + archive.WriteLocalHeader_And_SeekToNextFile(item); } static HRESULT Update2St( DECL_EXTERNAL_CODECS_LOC_VARS COutArchive &archive, CInArchive *inArchive, - IInStream *inStream, const CObjectVector<CItemEx> &inputItems, const CObjectVector<CUpdateItem> &updateItems, const CCompressionMethodMode *options, @@ -410,26 +404,29 @@ static HRESULT Update2St( CAddCommon compressor(*options); - CObjectVector<CItem> items; + CObjectVector<CItemOut> items; UInt64 unpackSizeTotal = 0, packSizeTotal = 0; - for (int itemIndex = 0; itemIndex < updateItems.Size(); itemIndex++) + FOR_VECTOR (itemIndex, updateItems) { lps->InSize = unpackSizeTotal; lps->OutSize = packSizeTotal; RINOK(lps->SetCur()); const CUpdateItem &ui = updateItems[itemIndex]; - CItemEx item; - if (!ui.NewProperties || !ui.NewData) + CItemEx itemEx; + CItemOut item; + + if (!ui.NewProps || !ui.NewData) { - item = inputItems[ui.IndexInArchive]; - if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK) + itemEx = inputItems[ui.IndexInArc]; + if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK) return E_NOTIMPL; + (CItem &)item = itemEx; } if (ui.NewData) { - bool isDir = ((ui.NewProperties) ? ui.IsDir : item.IsDir()); + bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); if (isDir) { WriteDirHeader(archive, options, ui, item); @@ -445,10 +442,12 @@ static HRESULT Update2St( continue; } RINOK(res); + if (!fileInStream) + return E_INVALIDARG; // file Size can be 64-bit !!! SetFileHeader(archive, *options, ui, item); - archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsRealAesMode()); + archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode()); CCompressingResult compressingResult; CMyComPtr<IOutStream> outStream; archive.CreateStreamForCompressing(&outStream); @@ -456,9 +455,9 @@ static HRESULT Update2St( EXTERNAL_CODECS_LOC_VARS fileInStream, outStream, progress, compressingResult)); SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); - archive.WriteLocalHeader(item); + archive.WriteLocalHeader_And_SeekToNextFile(item); RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); - unpackSizeTotal += item.UnPackSize; + unpackSizeTotal += item.Size; packSizeTotal += item.PackSize; } } @@ -466,12 +465,12 @@ static HRESULT Update2St( { UInt64 complexity = 0; lps->SendRatio = false; - RINOK(UpdateItemOldData(archive, inStream, ui, item, progress, complexity)); + RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, complexity)); lps->SendRatio = true; lps->ProgressOffset += complexity; } items.Add(item); - lps->ProgressOffset += NFileHeader::kLocalBlockSize; + lps->ProgressOffset += kLocalHeaderSize; } lps->InSize = unpackSizeTotal; lps->OutSize = packSizeTotal; @@ -484,7 +483,6 @@ static HRESULT Update2( DECL_EXTERNAL_CODECS_LOC_VARS COutArchive &archive, CInArchive *inArchive, - IInStream *inStream, const CObjectVector<CItemEx> &inputItems, const CObjectVector<CUpdateItem> &updateItems, const CCompressionMethodMode *options, @@ -495,7 +493,7 @@ static HRESULT Update2( UInt64 numFilesToCompress = 0; UInt64 numBytesToCompress = 0; - int i; + unsigned i; for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; @@ -511,18 +509,18 @@ static HRESULT Update2( } else { - CItemEx inputItem = inputItems[ui.IndexInArchive]; + CItemEx inputItem = inputItems[ui.IndexInArc]; if (inArchive->ReadLocalItemAfterCdItemFull(inputItem) != S_OK) return E_NOTIMPL; complexity += inputItem.GetLocalFullSize(); // complexity += inputItem.GetCentralExtraPlusCommentSize(); } - complexity += NFileHeader::kLocalBlockSize; - complexity += NFileHeader::kCentralBlockSize; + complexity += kLocalHeaderSize; + complexity += kCentralHeaderSize; } if (comment) - complexity += comment->GetCapacity(); + complexity += comment->Size(); complexity++; // end of central updateCallback->SetTotal(complexity); @@ -540,6 +538,9 @@ static HRESULT Update2( UInt32 numThreads = options->NumThreads; if (numThreads > kNumMaxThreads) numThreads = kNumMaxThreads; + if (numThreads < 1) + numThreads = 1; + const size_t kMemPerThread = (1 << 25); const size_t kBlockSize = 1 << 16; @@ -549,16 +550,18 @@ static HRESULT Update2( if (numFilesToCompress <= 1) mtMode = false; + Byte method = options->MethodSequence.Front(); if (!mtMode) { - if (numThreads < 2) - if (options2.MethodInfo.FindProp(NCoderPropID::kNumThreads) < 0 && - options2.NumThreadsWasChanged) - options2.MethodInfo.AddNumThreadsProp(1); + if (options2.MethodInfo.FindProp(NCoderPropID::kNumThreads) < 0) + { + // fixed for 9.31. bzip2 default is just one thread. + if (options2.NumThreadsWasChanged || method == NFileHeader::NCompressionMethod::kBZip2) + options2.MethodInfo.AddNumThreadsProp(numThreads); + } } else { - Byte method = options->MethodSequence.Front(); if (method == NFileHeader::NCompressionMethod::kStored && !options->PasswordIsDefined) numThreads = 1; if (method == NFileHeader::NCompressionMethod::kBZip2) @@ -594,13 +597,13 @@ static HRESULT Update2( #endif return Update2St( EXTERNAL_CODECS_LOC_VARS - archive, inArchive, inStream, + archive, inArchive, inputItems, updateItems, &options2, comment, updateCallback); #ifndef _7ZIP_ST - CObjectVector<CItem> items; + CObjectVector<CItemOut> items; CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer; CMyComPtr<ICompressProgressInfo> progress = mtProgressMixerSpec; @@ -629,8 +632,7 @@ static HRESULT Update2( { CThreadInfo &threadInfo = threads.Threads[i]; #ifdef EXTERNAL_CODECS - threadInfo._codecsInfo = codecsInfo; - threadInfo._externalCodecs = externalCodecs; + threadInfo.__externalCodecs = __externalCodecs; #endif RINOK(threadInfo.CreateEvents()); threadInfo.OutStreamSpec = new COutMemStream(&memManager); @@ -643,9 +645,9 @@ static HRESULT Update2( RINOK(threadInfo.CreateThread()); } } - int mtItemIndex = 0; + unsigned mtItemIndex = 0; - int itemIndex = 0; + unsigned itemIndex = 0; int lastRealStreamItemIndex = -1; while (itemIndex < updateItems.Size()) @@ -655,17 +657,19 @@ static HRESULT Update2( const CUpdateItem &ui = updateItems[mtItemIndex++]; if (!ui.NewData) continue; - CItemEx item; - if (ui.NewProperties) + CItemEx itemEx; + CItemOut item; + if (ui.NewProps) { if (ui.IsDir) continue; } else { - item = inputItems[ui.IndexInArchive]; - if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK) + itemEx = inputItems[ui.IndexInArc]; + if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK) return E_NOTIMPL; + (CItem &)item = itemEx; if (item.IsDir()) continue; } @@ -676,13 +680,15 @@ static HRESULT Update2( if (res == S_FALSE) { complexity += ui.Size; - complexity += NFileHeader::kLocalBlockSize; + complexity += kLocalHeaderSize; mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); refs.Refs[mtItemIndex - 1].Skip = true; continue; } RINOK(res); + if (!fileInStream) + return E_INVALIDARG; RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } @@ -719,29 +725,31 @@ static HRESULT Update2( const CUpdateItem &ui = updateItems[itemIndex]; - CItemEx item; - if (!ui.NewProperties || !ui.NewData) + CItemEx itemEx; + CItemOut item; + if (!ui.NewProps || !ui.NewData) { - item = inputItems[ui.IndexInArchive]; - if (inArchive->ReadLocalItemAfterCdItemFull(item) != S_OK) + itemEx = inputItems[ui.IndexInArc]; + if (inArchive->ReadLocalItemAfterCdItemFull(itemEx) != S_OK) return E_NOTIMPL; + (CItem &)item = itemEx; } if (ui.NewData) { - bool isDir = ((ui.NewProperties) ? ui.IsDir : item.IsDir()); + bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); if (isDir) { WriteDirHeader(archive, options, ui, item); } else { - if (lastRealStreamItemIndex < itemIndex) + if (lastRealStreamItemIndex < (int)itemIndex) { lastRealStreamItemIndex = itemIndex; SetFileHeader(archive, *options, ui, item); // file Size can be 64-bit !!! - archive.PrepareWriteCompressedData((UInt16)item.Name.Length(), ui.Size, options->IsRealAesMode()); + archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode()); } CMemBlocks2 &memRef = refs.Refs[itemIndex]; @@ -750,10 +758,13 @@ static HRESULT Update2( CMyComPtr<IOutStream> outStream; archive.CreateStreamForCompressing(&outStream); memRef.WriteToStream(memManager.GetBlockSize(), outStream); + SetFileHeader(archive, *options, ui, item); + // the BUG was fixed in 9.26: + // SetItemInfoFromCompressingResult must be after SetFileHeader + // to write correct Size. SetItemInfoFromCompressingResult(memRef.CompressingResult, options->IsRealAesMode(), options->AesKeyMode, item); - SetFileHeader(archive, *options, ui, item); - archive.WriteLocalHeader(item); + archive.WriteLocalHeader_And_SeekToNextFile(item); // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); memRef.FreeOpt(&memManager); } @@ -783,10 +794,10 @@ static HRESULT Update2( { RINOK(threadInfo.OutStreamSpec->WriteToRealStream()); threadInfo.OutStreamSpec->ReleaseOutStream(); + SetFileHeader(archive, *options, ui, item); SetItemInfoFromCompressingResult(threadInfo.CompressingResult, options->IsRealAesMode(), options->AesKeyMode, item); - SetFileHeader(archive, *options, ui, item); - archive.WriteLocalHeader(item); + archive.WriteLocalHeader_And_SeekToNextFile(item); } else { @@ -801,10 +812,10 @@ static HRESULT Update2( } else { - RINOK(UpdateItemOldData(archive, inStream, ui, item, progress, complexity)); + RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, complexity)); } items.Add(item); - complexity += NFileHeader::kLocalBlockSize; + complexity += kLocalHeaderSize; mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); itemIndex++; } @@ -993,15 +1004,18 @@ STDMETHODIMP CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *proce STDMETHODIMP CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { - switch(seekOrigin) + switch (seekOrigin) { - case STREAM_SEEK_SET: _virtPos = offset; break; - case STREAM_SEEK_CUR: _virtPos += offset; break; - case STREAM_SEEK_END: _virtPos = _virtSize + offset; break; + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += _virtSize; break; default: return STG_E_INVALIDFUNCTION; } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = offset; if (newPosition) - *newPosition = _virtPos; + *newPosition = offset; return S_OK; } @@ -1029,16 +1043,33 @@ HRESULT Update( const CObjectVector<CItemEx> &inputItems, const CObjectVector<CUpdateItem> &updateItems, ISequentialOutStream *seqOutStream, - CInArchive *inArchive, + CInArchive *inArchive, bool removeSfx, CCompressionMethodMode *compressionMethodMode, IArchiveUpdateCallback *updateCallback) { + if (inArchive) + { + if (!inArchive->CanUpdate()) + return E_NOTIMPL; + } + + CMyComPtr<IOutStream> outStream; { CMyComPtr<IOutStream> outStreamReal; seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal); if (!outStreamReal) return E_NOTIMPL; + + if (inArchive) + { + if (inArchive->ArcInfo.Base > 0 && !removeSfx) + { + RINOK(inArchive->Stream->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(NCompress::CopyStream_ExactSize(inArchive->Stream, outStreamReal, inArchive->ArcInfo.Base, NULL)); + } + } + CCacheOutStream *cacheStream = new CCacheOutStream(); outStream = cacheStream; if (!cacheStream->Allocate()) @@ -1046,32 +1077,23 @@ HRESULT Update( RINOK(cacheStream->Init(outStreamReal)); } - if (inArchive) - { - if (inArchive->ArcInfo.Base != 0 || - inArchive->ArcInfo.StartPosition != 0 || - !inArchive->IsOkHeaders) - return E_NOTIMPL; - } - COutArchive outArchive; - outArchive.Create(outStream); - /* - if (inArchive && inArchive->ArcInfo.StartPosition > 0) + RINOK(outArchive.Create(outStream)); + + if (inArchive) { - CMyComPtr<ISequentialInStream> inStream; - inStream.Attach(inArchive->CreateLimitedStream(0, inArchive->ArcInfo.StartPosition)); - RINOK(CopyBlockToArchive(inStream, outArchive, NULL)); - outArchive.MoveBasePosition(inArchive->ArcInfo.StartPosition); + if ((Int64)inArchive->ArcInfo.MarkerPos2 > inArchive->ArcInfo.Base) + { + RINOK(inArchive->Stream->Seek(inArchive->ArcInfo.Base, STREAM_SEEK_SET, NULL)); + UInt64 embStubSize = inArchive->ArcInfo.MarkerPos2 - inArchive->ArcInfo.Base; + RINOK(NCompress::CopyStream_ExactSize(inArchive->Stream, outStream, embStubSize, NULL)); + outArchive.MoveCurPos(embStubSize); + } } - */ - CMyComPtr<IInStream> inStream; - if (inArchive) - inStream.Attach(inArchive->CreateStream()); return Update2( EXTERNAL_CODECS_LOC_VARS - outArchive, inArchive, inStream, + outArchive, inArchive, inputItems, updateItems, compressionMethodMode, inArchive ? &inArchive->ArcInfo.Comment : NULL, diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.h b/CPP/7zip/Archive/Zip/ZipUpdate.h index eee16738..747c07bc 100755..100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.h +++ b/CPP/7zip/Archive/Zip/ZipUpdate.h @@ -1,4 +1,4 @@ -// Zip/Update.h +// ZipUpdate.h #ifndef __ZIP_UPDATE_H #define __ZIP_UPDATE_H @@ -18,28 +18,29 @@ struct CUpdateRange { UInt64 Position; UInt64 Size; - CUpdateRange() {}; + + // CUpdateRange() {}; CUpdateRange(UInt64 position, UInt64 size): Position(position), Size(size) {}; }; struct CUpdateItem { bool NewData; - bool NewProperties; + bool NewProps; bool IsDir; bool NtfsTimeIsDefined; bool IsUtf8; - int IndexInArchive; + int IndexInArc; int IndexInClient; - UInt32 Attributes; + UInt32 Attrib; UInt32 Time; UInt64 Size; AString Name; // bool Commented; // CUpdateRange CommentRange; - FILETIME NtfsMTime; - FILETIME NtfsATime; - FILETIME NtfsCTime; + FILETIME Ntfs_MTime; + FILETIME Ntfs_ATime; + FILETIME Ntfs_CTime; CUpdateItem(): NtfsTimeIsDefined(false), IsUtf8(false), Size(0) {} }; @@ -49,7 +50,7 @@ HRESULT Update( const CObjectVector<CItemEx> &inputItems, const CObjectVector<CUpdateItem> &updateItems, ISequentialOutStream *seqOutStream, - CInArchive *inArchive, + CInArchive *inArchive, bool removeSfx, CCompressionMethodMode *compressionMethodMode, IArchiveUpdateCallback *updateCallback); diff --git a/CPP/7zip/Archive/makefile b/CPP/7zip/Archive/makefile index 7512ad56..7512ad56 100755..100644 --- a/CPP/7zip/Archive/makefile +++ b/CPP/7zip/Archive/makefile |