diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2015-06-15 03:00:00 +0300 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:54 +0300 |
commit | 54490d51d5c6b0d794dcbad2d634d4c95fc25b6c (patch) | |
tree | c3c413656432c0ef87b2841c80e42b55ad17d4e8 /CPP/7zip/Archive | |
parent | 0713a3ab803e57401f18432148b4139e5fe6e5dd (diff) |
15.0515.05
Diffstat (limited to 'CPP/7zip/Archive')
131 files changed, 8137 insertions, 4426 deletions
diff --git a/CPP/7zip/Archive/7z/7z.dsp b/CPP/7zip/Archive/7z/7z.dsp index 53913f77..7fd1ccdc 100644 --- a/CPP/7zip/Archive/7z/7z.dsp +++ b/CPP/7zip/Archive/7z/7z.dsp @@ -350,14 +350,6 @@ SOURCE=..\Common\CoderMixer2.h # End Source File # Begin Source File -SOURCE=..\Common\CoderMixer2MT.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\CoderMixer2MT.h -# End Source File -# Begin Source File - SOURCE=..\Common\CrossThreadProgress.cpp # End Source File # Begin Source File diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.h b/CPP/7zip/Archive/7z/7zCompressionMode.h index 5cde97c3..8105ff04 100644 --- a/CPP/7zip/Archive/7z/7zCompressionMode.h +++ b/CPP/7zip/Archive/7z/7zCompressionMode.h @@ -9,37 +9,62 @@ namespace NArchive { namespace N7z { -struct CMethodFull: public CProps +struct CMethodFull: public CMethodProps { CMethodId Id; - UInt32 NumInStreams; - UInt32 NumOutStreams; + UInt32 NumStreams; - bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); } + bool IsSimpleCoder() const { return NumStreams == 1; } }; -struct CBind +struct CBond2 { - UInt32 InCoder; - UInt32 InStream; UInt32 OutCoder; UInt32 OutStream; + UInt32 InCoder; }; struct CCompressionMethodMode { + /* + if (Bonds.Empty()), then default bonds must be created + if (Filter_was_Inserted) + { + Methods[0] is filter method + Bonds don't contain bonds for filter (these bonds must be created) + } + */ + CObjectVector<CMethodFull> Methods; - CRecordVector<CBind> Binds; + CRecordVector<CBond2> Bonds; + + bool IsThereBond_to_Coder(unsigned coderIndex) const + { + FOR_VECTOR(i, Bonds) + if (Bonds[i].InCoder == coderIndex) + return true; + return false; + } + + bool DefaultMethod_was_Inserted; + bool Filter_was_Inserted; + #ifndef _7ZIP_ST UInt32 NumThreads; + bool MultiThreadMixer; #endif + bool PasswordIsDefined; UString Password; bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); } - CCompressionMethodMode(): PasswordIsDefined(false) + CCompressionMethodMode(): + DefaultMethod_was_Inserted(false), + Filter_was_Inserted(false), + PasswordIsDefined(false) #ifndef _7ZIP_ST , NumThreads(1) + , MultiThreadMixer(true) #endif {} }; diff --git a/CPP/7zip/Archive/7z/7zDecode.cpp b/CPP/7zip/Archive/7z/7zDecode.cpp index 7f0e45d1..d1a810cb 100644 --- a/CPP/7zip/Archive/7z/7zDecode.cpp +++ b/CPP/7zip/Archive/7z/7zDecode.cpp @@ -3,7 +3,6 @@ #include "StdAfx.h" #include "../../Common/LimitedStreams.h" -#include "../../Common/LockedStream.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamObjects.h" @@ -12,50 +11,70 @@ namespace NArchive { namespace N7z { -static void ConvertFolderItemInfoToBindInfo(const CFolder &folder, - CBindInfoEx &bindInfo) +class CDecProgress: + public ICompressProgressInfo, + public CMyUnknownImp { - bindInfo.Clear(); - bindInfo.BindPairs.ClearAndSetSize(folder.BindPairs.Size()); + CMyComPtr<ICompressProgressInfo> _progress; +public: + CDecProgress(ICompressProgressInfo *progress): _progress(progress) {} + + MY_UNKNOWN_IMP1(ICompressProgressInfo) + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); +}; + +STDMETHODIMP CDecProgress::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 *outSize) +{ + return _progress->SetRatioInfo(NULL, outSize); +} + +static void Convert_FolderInfo_to_BindInfo(const CFolderEx &folder, CBindInfoEx &bi) +{ + bi.Clear(); + + bi.Bonds.ClearAndSetSize(folder.Bonds.Size()); unsigned i; - for (i = 0; i < folder.BindPairs.Size(); i++) + for (i = 0; i < folder.Bonds.Size(); i++) { - NCoderMixer::CBindPair &bindPair = bindInfo.BindPairs[i]; - bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex; - bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex; + NCoderMixer2::CBond &bond = bi.Bonds[i]; + const N7z::CBond &folderBond = folder.Bonds[i]; + bond.PackIndex = folderBond.PackIndex; + bond.UnpackIndex = folderBond.UnpackIndex; } - bindInfo.Coders.ClearAndSetSize(folder.Coders.Size()); - bindInfo.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size()); - - UInt32 outStreamIndex = 0; + bi.Coders.ClearAndSetSize(folder.Coders.Size()); + bi.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size()); for (i = 0; i < folder.Coders.Size(); i++) { - NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i]; const CCoderInfo &coderInfo = folder.Coders[i]; - coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams; - coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams; - bindInfo.CoderMethodIDs[i] = coderInfo.MethodID; - for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++) - if (folder.FindBindPairForOutStream(outStreamIndex) < 0) - bindInfo.OutStreams.Add(outStreamIndex); + bi.Coders[i].NumStreams = coderInfo.NumStreams; + bi.CoderMethodIDs[i] = coderInfo.MethodID; } - bindInfo.InStreams.ClearAndSetSize(folder.PackStreams.Size()); + + /* + if (!bi.SetUnpackCoder()) + throw 1112; + */ + bi.UnpackCoder = folder.UnpackCoder; + bi.PackStreams.ClearAndSetSize(folder.PackStreams.Size()); for (i = 0; i < folder.PackStreams.Size(); i++) - bindInfo.InStreams[i] = (UInt32)folder.PackStreams[i]; + bi.PackStreams[i] = folder.PackStreams[i]; } -static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1, - const NCoderMixer::CCoderStreamsInfo &a2) +static inline bool AreCodersEqual( + const NCoderMixer2::CCoderStreamsInfo &a1, + const NCoderMixer2::CCoderStreamsInfo &a2) { - return (a1.NumInStreams == a2.NumInStreams) && - (a1.NumOutStreams == a2.NumOutStreams); + return (a1.NumStreams == a2.NumStreams); } -static bool AreBindPairsEqual(const NCoderMixer::CBindPair &a1, const NCoderMixer::CBindPair &a2) +static inline bool AreBondsEqual( + const NCoderMixer2::CBond &a1, + const NCoderMixer2::CBond &a2) { - return (a1.InIndex == a2.InIndex) && - (a1.OutIndex == a2.OutIndex); + return + (a1.PackIndex == a2.PackIndex) && + (a1.UnpackIndex == a2.UnpackIndex); } static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2) @@ -66,186 +85,284 @@ static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2) for (i = 0; i < a1.Coders.Size(); i++) if (!AreCodersEqual(a1.Coders[i], a2.Coders[i])) return false; - if (a1.BindPairs.Size() != a2.BindPairs.Size()) + + if (a1.Bonds.Size() != a2.Bonds.Size()) return false; - for (i = 0; i < a1.BindPairs.Size(); i++) - if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i])) + for (i = 0; i < a1.Bonds.Size(); i++) + if (!AreBondsEqual(a1.Bonds[i], a2.Bonds[i])) return false; + for (i = 0; i < a1.CoderMethodIDs.Size(); i++) if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i]) return false; - if (a1.InStreams.Size() != a2.InStreams.Size()) + + if (a1.PackStreams.Size() != a2.PackStreams.Size()) return false; - if (a1.OutStreams.Size() != a2.OutStreams.Size()) + for (i = 0; i < a1.PackStreams.Size(); i++) + if (a1.PackStreams[i] != a2.PackStreams[i]) + return false; + + /* + if (a1.UnpackCoder != a2.UnpackCoder) return false; + */ return true; } -CDecoder::CDecoder(bool multiThread) +CDecoder::CDecoder(bool useMixerMT): + _bindInfoPrev_Defined(false), + _useMixerMT(useMixerMT) +{} + + +struct CLockedInStream: + public IUnknown, + public CMyUnknownImp { - #ifndef _ST_MODE - multiThread = true; + CMyComPtr<IInStream> Stream; + UInt64 Pos; + + MY_UNKNOWN_IMP + + #ifdef USE_MIXER_MT + NWindows::NSynchronization::CCriticalSection CriticalSection; #endif - _multiThread = multiThread; - _bindInfoExPrevIsDefined = false; +}; + + +#ifdef USE_MIXER_MT + +class CLockedSequentialInStreamMT: + public ISequentialInStream, + public CMyUnknownImp +{ + CLockedInStream *_glob; + UInt64 _pos; + CMyComPtr<IUnknown> _globRef; +public: + void Init(CLockedInStream *lockedInStream, UInt64 startPos) + { + _globRef = lockedInStream; + _glob = lockedInStream; + _pos = startPos; + } + + MY_UNKNOWN_IMP1(ISequentialInStream) + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CLockedSequentialInStreamMT::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + NWindows::NSynchronization::CCriticalSectionLock lock(_glob->CriticalSection); + + if (_pos != _glob->Pos) + { + RINOK(_glob->Stream->Seek(_pos, STREAM_SEEK_SET, NULL)); + _glob->Pos = _pos; + } + + UInt32 realProcessedSize = 0; + HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize); + _pos += realProcessedSize; + _glob->Pos = _pos; + if (processedSize) + *processedSize = realProcessedSize; + return res; +} + +#endif + + +#ifdef USE_MIXER_ST + +class CLockedSequentialInStreamST: + public ISequentialInStream, + public CMyUnknownImp +{ + CLockedInStream *_glob; + UInt64 _pos; + CMyComPtr<IUnknown> _globRef; +public: + void Init(CLockedInStream *lockedInStream, UInt64 startPos) + { + _globRef = lockedInStream; + _glob = lockedInStream; + _pos = startPos; + } + + MY_UNKNOWN_IMP1(ISequentialInStream) + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CLockedSequentialInStreamST::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (_pos != _glob->Pos) + { + RINOK(_glob->Stream->Seek(_pos, STREAM_SEEK_SET, NULL)); + _glob->Pos = _pos; + } + + UInt32 realProcessedSize = 0; + HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize); + _pos += realProcessedSize; + _glob->Pos = _pos; + if (processedSize) + *processedSize = realProcessedSize; + return res; } +#endif + + + HRESULT CDecoder::Decode( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, UInt64 startPos, - const CFolders &folders, int folderIndex, - ISequentialOutStream *outStream, - ICompressProgressInfo *compressProgress + const CFolders &folders, unsigned folderIndex, + const UInt64 *unpackSize + + , ISequentialOutStream *outStream + , ICompressProgressInfo *compressProgress + , ISequentialInStream ** + + #ifdef USE_MIXER_ST + inStreamMainRes + #endif + _7Z_DECODER_CRYPRO_VARS_DECL + #if !defined(_7ZIP_ST) && !defined(_SFX) , bool mtMode, UInt32 numThreads #endif ) { const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]]; - CFolder folderInfo; - folders.ParseFolderInfo(folderIndex, folderInfo); + CFolderEx folderInfo; + folders.ParseFolderEx(folderIndex, folderInfo); - if (!folderInfo.CheckStructure(folders.GetNumFolderUnpackSizes(folderIndex))) + if (!folderInfo.IsDecodingSupported()) + return E_NOTIMPL; + + CBindInfoEx bindInfo; + Convert_FolderInfo_to_BindInfo(folderInfo, bindInfo); + if (!bindInfo.CalcMapsAndCheck()) return E_NOTIMPL; + UInt64 folderUnpackSize = folders.GetFolderUnpackSize(folderIndex); + bool fullUnpack = true; + if (unpackSize) + { + if (*unpackSize > folderUnpackSize) + return E_FAIL; + fullUnpack = (*unpackSize == folderUnpackSize); + } + /* 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 (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++) + if (!_bindInfoPrev_Defined || !AreBindInfoExEqual(bindInfo, _bindInfoPrev)) { - CLockedSequentialInStreamImp *lockedStreamImpSpec = new CLockedSequentialInStreamImp; - CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec; - lockedStreamImpSpec->Init(&lockedInStream, startPos + packPositions[j]); - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr<ISequentialInStream> inStream = streamSpec; - streamSpec->SetStream(lockedStreamImp); - streamSpec->Init(packPositions[j + 1] - packPositions[j]); - inStreams.Add(inStream); - } - - unsigned numCoders = folderInfo.Coders.Size(); - - CBindInfoEx bindInfo; - ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo); - bool createNewCoders; - if (!_bindInfoExPrevIsDefined) - createNewCoders = true; - else - createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev); - if (createNewCoders) - { - unsigned i; - _decoders.Clear(); - // _decoders2.Clear(); - - _mixerCoder.Release(); + _mixerRef.Release(); - if (_multiThread) + #ifdef USE_MIXER_MT + #ifdef USE_MIXER_ST + if (_useMixerMT) + #endif { - _mixerCoderMTSpec = new NCoderMixer::CCoderMixer2MT; - _mixerCoder = _mixerCoderMTSpec; - _mixerCoderCommon = _mixerCoderMTSpec; + _mixerMT = new NCoderMixer2::CMixerMT(false); + _mixerRef = _mixerMT; + _mixer = _mixerMT; } + #ifdef USE_MIXER_ST else + #endif + #endif { - #ifdef _ST_MODE - _mixerCoderSTSpec = new NCoderMixer::CCoderMixer2ST; - _mixerCoder = _mixerCoderSTSpec; - _mixerCoderCommon = _mixerCoderSTSpec; + #ifdef USE_MIXER_ST + _mixerST = new NCoderMixer2::CMixerST(false); + _mixerRef = _mixerST; + _mixer = _mixerST; #endif } - RINOK(_mixerCoderCommon->SetBindInfo(bindInfo)); - for (i = 0; i < numCoders; i++) + RINOK(_mixer->SetBindInfo(bindInfo)); + + FOR_VECTOR(i, folderInfo.Coders) { const CCoderInfo &coderInfo = folderInfo.Coders[i]; - - CMyComPtr<ICompressCoder> decoder; - CMyComPtr<ICompressCoder2> decoder2; + CCreatedCoder cod; RINOK(CreateCoder( EXTERNAL_CODECS_LOC_VARS - coderInfo.MethodID, decoder, decoder2, false)); - CMyComPtr<IUnknown> decoderUnknown; + coderInfo.MethodID, false, cod)); + if (coderInfo.IsSimpleCoder()) { - if (decoder == 0) + if (!cod.Coder) return E_NOTIMPL; - - decoderUnknown = (IUnknown *)decoder; - - if (_multiThread) - _mixerCoderMTSpec->AddCoder(decoder); - #ifdef _ST_MODE - else - _mixerCoderSTSpec->AddCoder(decoder, false); - #endif + // CMethodId m = coderInfo.MethodID; + // isFilter = (IsFilterMethod(m) || m == k_AES); } else { - if (decoder2 == 0) + if (!cod.Coder2 || cod.NumStreams != coderInfo.NumStreams) return E_NOTIMPL; - decoderUnknown = (IUnknown *)decoder2; - if (_multiThread) - _mixerCoderMTSpec->AddCoder2(decoder2); - #ifdef _ST_MODE - else - _mixerCoderSTSpec->AddCoder2(decoder2, false); - #endif } - _decoders.Add(decoderUnknown); + _mixer->AddCoder(cod); + + // now there is no codec that uses another external codec + /* #ifdef EXTERNAL_CODECS CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { + // we must use g_ExternalCodecs also RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); } #endif + */ } - _bindInfoExPrev = bindInfo; - _bindInfoExPrevIsDefined = true; + + _bindInfoPrev = bindInfo; + _bindInfoPrev_Defined = true; } - unsigned i; - _mixerCoderCommon->ReInit(); + + _mixer->ReInit(); UInt32 packStreamIndex = 0; UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex]; - UInt32 unpackStreamIndex = unpackStreamIndexStart; - UInt32 coderIndex = 0; - // UInt32 coder2Index = 0; - - for (i = 0; i < numCoders; i++) + + unsigned i; + + for (i = 0; i < folderInfo.Coders.Size(); i++) { const CCoderInfo &coderInfo = folderInfo.Coders[i]; - CMyComPtr<IUnknown> &decoder = _decoders[coderIndex]; - + IUnknown *decoder = _mixer->GetCoder(i).GetUnknown(); + { CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties; - decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); + decoder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties); if (setDecoderProperties) { const CByteBuffer &props = coderInfo.Props; size_t size = props.Size(); if (size > 0xFFFFFFFF) return E_NOTIMPL; - // if (size > 0) - { - RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size)); - } + HRESULT res = setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size); + if (res == E_INVALIDARG) + res = E_NOTIMPL; + RINOK(res); } } @@ -253,7 +370,7 @@ HRESULT CDecoder::Decode( if (mtMode) { CMyComPtr<ICompressSetCoderMt> setCoderMt; - decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); + decoder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt); if (setCoderMt) { RINOK(setCoderMt->SetNumberOfThreads(numThreads)); @@ -264,7 +381,7 @@ HRESULT CDecoder::Decode( #ifndef _NO_CRYPTO { CMyComPtr<ICryptoSetPassword> cryptoSetPassword; - decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); + decoder->QueryInterface(IID_ICryptoSetPassword, (void **)&cryptoSetPassword); if (cryptoSetPassword) { isEncrypted = true; @@ -273,9 +390,13 @@ HRESULT CDecoder::Decode( CMyComBSTR passwordBSTR; RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR)); passwordIsDefined = true; + password.Empty(); size_t len = 0; if (passwordBSTR) - len = MyStringLen((BSTR)passwordBSTR); + { + password = passwordBSTR; + len = password.Len(); + } CByteBuffer buffer(len * 2); for (size_t i = 0; i < len; i++) { @@ -288,56 +409,129 @@ HRESULT CDecoder::Decode( } #endif - coderIndex++; + { + CMyComPtr<ICompressSetFinishMode> setFinishMode; + decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); + if (setFinishMode) + { + RINOK(setFinishMode->SetFinishMode(BoolToInt(fullUnpack))); + } + } - UInt32 numInStreams = (UInt32)coderInfo.NumInStreams; - UInt32 numOutStreams = (UInt32)coderInfo.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[j] = &folders.CoderUnpackSizes[unpackStreamIndex]; + UInt32 numStreams = (UInt32)coderInfo.NumStreams; - for (j = 0; j < numInStreams; j++, packStreamIndex++) + CObjArray<UInt64> packSizes(numStreams); + CObjArray<const UInt64 *> packSizesPointers(numStreams); + + for (UInt32 j = 0; j < numStreams; j++, packStreamIndex++) { - int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex); - if (bindPairIndex >= 0) - packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + (UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]; + int bond = folderInfo.FindBond_for_PackStream(packStreamIndex); + + if (bond >= 0) + packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + folderInfo.Bonds[(unsigned)bond].UnpackIndex]; else { - int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex); + int index = folderInfo.Find_in_PackStreams(packStreamIndex); if (index < 0) - return S_FALSE; // check it - packSizes[j] = packPositions[index + 1] - packPositions[index]; + return E_NOTIMPL; + packSizes[j] = packPositions[(unsigned)index + 1] - packPositions[(unsigned)index]; packSizesPointers[j] = &packSizes[j]; } } + + const UInt64 *unpackSizesPointer = + (unpackSize && i == bindInfo.UnpackCoder) ? + unpackSize : + &folders.CoderUnpackSizes[unpackStreamIndexStart + i]; - _mixerCoderCommon->SetCoderInfo(i, packSizesPointers, unpackSizesPointers); + _mixer->SetCoderInfo(i, unpackSizesPointer, packSizesPointers); } - UInt32 mainCoder, temp; - bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp); - if (_multiThread) - _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder); - /* - else - _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);; - */ + if (outStream) + { + _mixer->SelectMainCoder(!fullUnpack); + } + + CObjectVector< CMyComPtr<ISequentialInStream> > inStreams; + + CLockedInStream *lockedInStreamSpec = new CLockedInStream; + CMyComPtr<IUnknown> lockedInStream = lockedInStreamSpec; + + bool needMtLock = false; + + if (folderInfo.PackStreams.Size() > 1) + { + // lockedInStream.Pos = (UInt64)(Int64)-1; + // RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &lockedInStream.Pos)); + RINOK(inStream->Seek(startPos + packPositions[0], STREAM_SEEK_SET, &lockedInStreamSpec->Pos)); + lockedInStreamSpec->Stream = inStream; + + #ifdef USE_MIXER_ST + if (_mixer->IsThere_ExternalCoder_in_PackTree(_mixer->MainCoderIndex)) + #endif + needMtLock = true; + } + + for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++) + { + CMyComPtr<ISequentialInStream> packStream; + UInt64 packPos = startPos + packPositions[j]; + + if (folderInfo.PackStreams.Size() == 1) + { + RINOK(inStream->Seek(packPos, STREAM_SEEK_SET, NULL)); + packStream = inStream; + } + else + { + #ifdef USE_MIXER_MT + #ifdef USE_MIXER_ST + if (_useMixerMT || needMtLock) + #endif + { + CLockedSequentialInStreamMT *lockedStreamImpSpec = new CLockedSequentialInStreamMT; + packStream = lockedStreamImpSpec; + lockedStreamImpSpec->Init(lockedInStreamSpec, packPos); + } + #ifdef USE_MIXER_ST + else + #endif + #endif + { + #ifdef USE_MIXER_ST + CLockedSequentialInStreamST *lockedStreamImpSpec = new CLockedSequentialInStreamST; + packStream = lockedStreamImpSpec; + lockedStreamImpSpec->Init(lockedInStreamSpec, packPos); + #endif + } + } + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + inStreams.AddNew() = streamSpec; + streamSpec->SetStream(packStream); + streamSpec->Init(packPositions[j + 1] - packPositions[j]); + } - if (numCoders == 0) - return 0; 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, NULL, num, - &outStreamPointer, NULL, 1, - compressProgress); + + if (outStream) + { + CMyComPtr<ICompressProgressInfo> progress2; + if (compressProgress && !_mixer->Is_PackSize_Correct_for_Coder(_mixer->MainCoderIndex)) + progress2 = new CDecProgress(compressProgress); + + ISequentialOutStream *outStreamPointer = outStream; + return _mixer->Code(inStreamPointers, &outStreamPointer, progress2 ? (ICompressProgressInfo *)progress2 : compressProgress); + } + + #ifdef USE_MIXER_ST + return _mixerST->GetMainUnpackStream(inStreamPointers, inStreamMainRes); + #else + return E_FAIL; + #endif } }} diff --git a/CPP/7zip/Archive/7z/7zDecode.h b/CPP/7zip/Archive/7z/7zDecode.h index 1361772c..5b729f6c 100644 --- a/CPP/7zip/Archive/7z/7zDecode.h +++ b/CPP/7zip/Archive/7z/7zDecode.h @@ -3,25 +3,17 @@ #ifndef __7Z_DECODE_H #define __7Z_DECODE_H -#include "../../IStream.h" -#include "../../IPassword.h" - #include "../Common/CoderMixer2.h" -#include "../Common/CoderMixer2MT.h" -#ifdef _ST_MODE -#include "../Common/CoderMixer2ST.h" -#endif - -#include "../../Common/CreateCoder.h" #include "7zIn.h" namespace NArchive { namespace N7z { -struct CBindInfoEx: public NCoderMixer::CBindInfo +struct CBindInfoEx: public NCoderMixer2::CBindInfo { CRecordVector<CMethodId> CoderMethodIDs; + void Clear() { CBindInfo::Clear(); @@ -31,29 +23,40 @@ struct CBindInfoEx: public NCoderMixer::CBindInfo class CDecoder { - bool _bindInfoExPrevIsDefined; - CBindInfoEx _bindInfoExPrev; + bool _bindInfoPrev_Defined; + CBindInfoEx _bindInfoPrev; + + bool _useMixerMT; - bool _multiThread; - #ifdef _ST_MODE - NCoderMixer::CCoderMixer2ST *_mixerCoderSTSpec; + #ifdef USE_MIXER_ST + NCoderMixer2::CMixerST *_mixerST; #endif - NCoderMixer::CCoderMixer2MT *_mixerCoderMTSpec; - NCoderMixer::CCoderMixer2 *_mixerCoderCommon; - CMyComPtr<ICompressCoder2> _mixerCoder; - CObjectVector<CMyComPtr<IUnknown> > _decoders; - // CObjectVector<CMyComPtr<ICompressCoder2> > _decoders2; + #ifdef USE_MIXER_MT + NCoderMixer2::CMixerMT *_mixerMT; + #endif + + NCoderMixer2::CMixer *_mixer; + CMyComPtr<IUnknown> _mixerRef; + public: - CDecoder(bool multiThread); + + CDecoder(bool useMixerMT); + HRESULT Decode( DECL_EXTERNAL_CODECS_LOC_VARS IInStream *inStream, UInt64 startPos, - const CFolders &folders, int folderIndex, - ISequentialOutStream *outStream, - ICompressProgressInfo *compressProgress + const CFolders &folders, unsigned folderIndex, + const UInt64 *unpackSize // if (!unpackSize), then full folder is required + // if (unpackSize), then only *unpackSize bytes from folder are required + + , ISequentialOutStream *outStream + , ICompressProgressInfo *compressProgress + , ISequentialInStream **inStreamMainRes + _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 36ff5177..ab251711 100644 --- a/CPP/7zip/Archive/7z/7zEncode.cpp +++ b/CPP/7zip/Archive/7z/7zEncode.cpp @@ -12,43 +12,80 @@ #include "7zEncode.h" #include "7zSpecStream.h" -static const UInt64 k_Delta = 0x03; -static const UInt64 k_BCJ = 0x03030103; -static const UInt64 k_BCJ2 = 0x0303011B; - namespace NArchive { namespace N7z { -static void ConvertBindInfoToFolderItemInfo(const NCoderMixer::CBindInfo &bindInfo, - const CRecordVector<CMethodId> decompressionMethods, - CFolder &folder) +void CEncoder::InitBindConv() +{ + unsigned numIn = _bindInfo.Coders.Size(); + + _SrcIn_to_DestOut.ClearAndSetSize(numIn); + _DestOut_to_SrcIn.ClearAndSetSize(numIn); + + unsigned numOut = _bindInfo.GetNum_Bonds_and_PackStreams(); + _SrcOut_to_DestIn.ClearAndSetSize(numOut); + // _DestIn_to_SrcOut.ClearAndSetSize(numOut); + + UInt32 destIn = 0; + UInt32 destOut = 0; + + for (unsigned i = _bindInfo.Coders.Size(); i != 0;) + { + i--; + + const NCoderMixer2::CCoderStreamsInfo &coder = _bindInfo.Coders[i]; + + numIn--; + numOut -= coder.NumStreams; + + _SrcIn_to_DestOut[numIn] = destOut; + _DestOut_to_SrcIn[destOut] = numIn; + + destOut++; + + for (UInt32 j = 0; j < coder.NumStreams; j++, destIn++) + { + UInt32 index = numOut + j; + _SrcOut_to_DestIn[index] = destIn; + // _DestIn_to_SrcOut[destIn] = index; + } + } +} + +void CEncoder::SetFolder(CFolder &folder) { - // bindInfo.CoderMethodIDs.Clear(); - // folder.OutStreams.Clear(); - folder.BindPairs.SetSize(bindInfo.BindPairs.Size()); + folder.Bonds.SetSize(_bindInfo.Bonds.Size()); + unsigned i; - for (i = 0; i < bindInfo.BindPairs.Size(); i++) + + for (i = 0; i < _bindInfo.Bonds.Size(); i++) { - CBindPair &bp = folder.BindPairs[i]; - const NCoderMixer::CBindPair &mixerBp = bindInfo.BindPairs[i]; - bp.InIndex = mixerBp.InIndex; - bp.OutIndex = mixerBp.OutIndex; + CBond &fb = folder.Bonds[i]; + const NCoderMixer2::CBond &mixerBond = _bindInfo.Bonds[_bindInfo.Bonds.Size() - 1 - i]; + fb.PackIndex = _SrcOut_to_DestIn[mixerBond.PackIndex]; + fb.UnpackIndex = _SrcIn_to_DestOut[mixerBond.UnpackIndex]; } - folder.Coders.SetSize(bindInfo.Coders.Size()); - for (i = 0; i < bindInfo.Coders.Size(); i++) + + folder.Coders.SetSize(_bindInfo.Coders.Size()); + + for (i = 0; i < _bindInfo.Coders.Size(); i++) { CCoderInfo &coderInfo = folder.Coders[i]; - const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i]; - coderInfo.NumInStreams = coderStreamsInfo.NumInStreams; - coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams; - coderInfo.MethodID = decompressionMethods[i]; - // coderInfo.Props can be nonFree; + const NCoderMixer2::CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[_bindInfo.Coders.Size() - 1 - i]; + + coderInfo.NumStreams = coderStreamsInfo.NumStreams; + coderInfo.MethodID = _decompressionMethods[i]; + // we don't free coderInfo.Props here. So coderInfo.Props can be non-empty. } - folder.PackStreams.SetSize(bindInfo.InStreams.Size()); - for (i = 0; i < bindInfo.InStreams.Size(); i++) - folder.PackStreams[i] = bindInfo.InStreams[i]; + + folder.PackStreams.SetSize(_bindInfo.PackStreams.Size()); + + for (i = 0; i < _bindInfo.PackStreams.Size(); i++) + folder.PackStreams[i] = _SrcOut_to_DestIn[_bindInfo.PackStreams[i]]; } + + static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder) { CMyComPtr<ICompressSetCoderProperties> setCoderProperties; @@ -58,30 +95,75 @@ static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, return props.AreThereNonOptionalProps() ? E_INVALIDARG : S_OK; } + + +void CMtEncMultiProgress::Init(ICompressProgressInfo *progress) +{ + _progress = progress; + OutSize = 0; +} + +STDMETHODIMP CMtEncMultiProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */) +{ + UInt64 outSize2; + { + #ifndef _7ZIP_ST + NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); + #endif + outSize2 = OutSize; + } + + if (_progress) + return _progress->SetRatioInfo(inSize, &outSize2); + + return S_OK; +} + + + HRESULT CEncoder::CreateMixerCoder( DECL_EXTERNAL_CODECS_LOC_VARS const UInt64 *inSizeForReduce) { - _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT; - _mixerCoder = _mixerCoderSpec; - RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo)); + #ifdef USE_MIXER_MT + #ifdef USE_MIXER_ST + if (_options.MultiThreadMixer) + #endif + { + _mixerMT = new NCoderMixer2::CMixerMT(true); + _mixerRef = _mixerMT; + _mixer = _mixerMT; + } + #ifdef USE_MIXER_ST + else + #endif + #endif + { + #ifdef USE_MIXER_ST + _mixerST = new NCoderMixer2::CMixerST(true); + _mixerRef = _mixerST; + _mixer = _mixerST; + #endif + } + + RINOK(_mixer->SetBindInfo(_bindInfo)); + FOR_VECTOR (i, _options.Methods) { const CMethodFull &methodFull = _options.Methods[i]; - CCoderInfo &encodingInfo = _codersInfo.AddNew(); - encodingInfo.MethodID = methodFull.Id; - CMyComPtr<ICompressCoder> encoder; - CMyComPtr<ICompressCoder2> encoder2; - + CCreatedCoder cod; + RINOK(CreateCoder( EXTERNAL_CODECS_LOC_VARS - methodFull.Id, encoder, encoder2, true)); + methodFull.Id, true, cod)); - if (!encoder && !encoder2) + if (cod.NumStreams != methodFull.NumStreams) + return E_FAIL; + if (!cod.Coder && !cod.Coder2) return E_FAIL; - CMyComPtr<IUnknown> encoderCommon = encoder ? (IUnknown *)encoder : (IUnknown *)encoder2; + CMyComPtr<IUnknown> encoderCommon = cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2; #ifndef _7ZIP_ST { @@ -105,21 +187,25 @@ HRESULT CEncoder::CreateMixerCoder( } */ + // now there is no codec that uses another external codec + /* #ifdef EXTERNAL_CODECS CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { + // we must use g_ExternalCodecs also RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); } #endif + */ CMyComPtr<ICryptoSetPassword> cryptoSetPassword; encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); if (cryptoSetPassword) { - const UInt32 sizeInBytes = _options.Password.Len() * 2; + const unsigned sizeInBytes = _options.Password.Len() * 2; CByteBuffer buffer(sizeInBytes); for (unsigned i = 0; i < _options.Password.Len(); i++) { @@ -127,21 +213,79 @@ HRESULT CEncoder::CreateMixerCoder( ((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)sizeInBytes)); } - if (encoder) - _mixerCoderSpec->AddCoder(encoder); - else - _mixerCoderSpec->AddCoder2(encoder2); + _mixer->AddCoder(cod); } return S_OK; } + + +class CSequentialOutTempBufferImp2: + public ISequentialOutStream, + public CMyUnknownImp +{ + CInOutTempBuffer *_buf; +public: + CMtEncMultiProgress *_mtProgresSpec; + + CSequentialOutTempBufferImp2(): _buf(0), _mtProgresSpec(NULL) {} + void Init(CInOutTempBuffer *buffer) { _buf = buffer; } + MY_UNKNOWN_IMP1(ISequentialOutStream) + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CSequentialOutTempBufferImp2::Write(const void *data, UInt32 size, UInt32 *processed) +{ + if (!_buf->Write(data, size)) + { + if (processed) + *processed = 0; + return E_FAIL; + } + if (processed) + *processed = size; + if (_mtProgresSpec) + _mtProgresSpec->AddOutSize(size); + return S_OK; +} + + +class CSequentialOutMtNotify: + public ISequentialOutStream, + public CMyUnknownImp +{ +public: + CMyComPtr<ISequentialOutStream> _stream; + CMtEncMultiProgress *_mtProgresSpec; + + CSequentialOutMtNotify(): _mtProgresSpec(NULL) {} + MY_UNKNOWN_IMP1(ISequentialOutStream) + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CSequentialOutMtNotify::Write(const void *data, UInt32 size, UInt32 *processed) +{ + UInt32 realProcessed = 0; + HRESULT res = _stream->Write(data, size, &realProcessed); + if (processed) + *processed = realProcessed; + if (_mtProgresSpec) + _mtProgresSpec->AddOutSize(size); + return res; +} + + + HRESULT CEncoder::Encode( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, - const UInt64 *inStreamSize, const UInt64 *inSizeForReduce, + // const UInt64 *inStreamSize, + const UInt64 *inSizeForReduce, CFolder &folderItem, CRecordVector<UInt64> &coderUnpackSizes, UInt64 &unpackSize, @@ -151,27 +295,37 @@ HRESULT CEncoder::Encode( { RINOK(EncoderConstr()); - if (!_mixerCoderSpec) + if (!_mixerRef) { RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce)); } - _mixerCoderSpec->ReInit(); - // _mixerCoderSpec->SetCoderInfo(0, NULL, NULL, progress); + + _mixer->ReInit(); + + CMtEncMultiProgress *mtProgressSpec = NULL; + CMyComPtr<ICompressProgressInfo> mtProgress; + + CSequentialOutMtNotify *mtOutStreamNotifySpec = NULL; + CMyComPtr<ISequentialOutStream> mtOutStreamNotify; CObjectVector<CInOutTempBuffer> inOutTempBuffers; - CObjectVector<CSequentialOutTempBufferImp *> tempBufferSpecs; + CObjectVector<CSequentialOutTempBufferImp2 *> tempBufferSpecs; CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers; + unsigned numMethods = _bindInfo.Coders.Size(); + unsigned i; - for (i = 1; i < _bindInfo.OutStreams.Size(); i++) + + for (i = 1; i < _bindInfo.PackStreams.Size(); i++) { CInOutTempBuffer &iotb = inOutTempBuffers.AddNew(); iotb.Create(); iotb.InitWriting(); } - for (i = 1; i < _bindInfo.OutStreams.Size(); i++) + + for (i = 1; i < _bindInfo.PackStreams.Size(); i++) { - CSequentialOutTempBufferImp *tempBufferSpec = new CSequentialOutTempBufferImp; + CSequentialOutTempBufferImp2 *tempBufferSpec = new CSequentialOutTempBufferImp2; CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec; tempBufferSpec->Init(&inOutTempBuffers[i - 1]); tempBuffers.Add(tempBuffer); @@ -179,94 +333,111 @@ HRESULT CEncoder::Encode( } for (i = 0; i < numMethods; i++) - _mixerCoderSpec->SetCoderInfo(i, NULL, NULL); + _mixer->SetCoderInfo(i, NULL, NULL); - if (_bindInfo.InStreams.IsEmpty()) - return E_FAIL; - UInt32 mainCoderIndex, mainStreamIndex; - _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex); - + + /* inStreamSize can be used by BCJ2 to set optimal range of conversion. + But current BCJ2 encoder uses also another way to check exact size of current file. + So inStreamSize is not required. */ + + /* if (inStreamSize) - { - CRecordVector<const UInt64 *> sizePointers; - for (UInt32 i = 0; i < _bindInfo.Coders[mainCoderIndex].NumInStreams; i++) - if (i == mainStreamIndex) - sizePointers.Add(inStreamSize); - else - sizePointers.Add(NULL); - _mixerCoderSpec->SetCoderInfo(mainCoderIndex, &sizePointers.Front(), NULL); - } + _mixer->SetCoderInfo(_bindInfo.UnpackCoder, inStreamSize, NULL); + */ - // UInt64 outStreamStartPos; - // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos)); - CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2; CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec; + CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL; CMyComPtr<ISequentialOutStream> outStreamSizeCount; inStreamSizeCountSpec->Init(inStream); - CRecordVector<ISequentialInStream *> inStreamPointers; + ISequentialInStream *inStreamPointer = inStreamSizeCount; CRecordVector<ISequentialOutStream *> outStreamPointers; - inStreamPointers.Add(inStreamSizeCount); - if (_bindInfo.OutStreams.Size() != 0) - { - outStreamSizeCountSpec = new CSequentialOutStreamSizeCount; - outStreamSizeCount = outStreamSizeCountSpec; - outStreamSizeCountSpec->SetStream(outStream); - outStreamSizeCountSpec->Init(); - outStreamPointers.Add(outStreamSizeCount); - } + SetFolder(folderItem); - for (i = 1; i < _bindInfo.OutStreams.Size(); i++) - outStreamPointers.Add(tempBuffers[i - 1]); - - for (i = 0; i < _codersInfo.Size(); i++) + for (i = 0; i < numMethods; i++) { - CCoderInfo &encodingInfo = _codersInfo[i]; - + IUnknown *coder = _mixer->GetCoder(i).GetUnknown(); + CMyComPtr<ICryptoResetInitVector> resetInitVector; - _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector); + coder->QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector); if (resetInitVector) { resetInitVector->ResetInitVector(); } CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties; - _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties); + coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties); + + CByteBuffer &props = folderItem.Coders[numMethods - 1 - i].Props; + if (writeCoderProperties) { CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream; - CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); + CMyComPtr<ISequentialOutStream> dynOutStream(outStreamSpec); outStreamSpec->Init(); - writeCoderProperties->WriteCoderProperties(outStream); - outStreamSpec->CopyToBuffer(encodingInfo.Props); + writeCoderProperties->WriteCoderProperties(dynOutStream); + outStreamSpec->CopyToBuffer(props); } + else + props.Free(); } - UInt32 progressIndex = mainCoderIndex; + _mixer->SelectMainCoder(false); + UInt32 mainCoder = _mixer->MainCoderIndex; - for (i = 0; i + 1 < _codersInfo.Size(); i++) + bool useMtProgress = false; + if (!_mixer->Is_PackSize_Correct_for_Coder(mainCoder)) { - UInt64 m = _codersInfo[i].MethodID; - if (m == k_Delta || m == k_BCJ || m == k_BCJ2) - progressIndex = i + 1; + #ifdef _7ZIP_ST + if (!_mixer->IsThere_ExternalCoder_in_PackTree(mainCoder)) + #endif + useMtProgress = true; } - _mixerCoderSpec->SetProgressCoderIndex(progressIndex); + if (useMtProgress) + { + mtProgressSpec = new CMtEncMultiProgress; + mtProgress = mtProgressSpec; + mtProgressSpec->Init(compressProgress); + + mtOutStreamNotifySpec = new CSequentialOutMtNotify; + mtOutStreamNotify = mtOutStreamNotifySpec; + mtOutStreamNotifySpec->_stream = outStream; + mtOutStreamNotifySpec->_mtProgresSpec = mtProgressSpec; + + FOR_VECTOR(i, tempBufferSpecs) + { + tempBufferSpecs[i]->_mtProgresSpec = mtProgressSpec; + } + } - RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1, - &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress)); - ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, folderItem); + if (_bindInfo.PackStreams.Size() != 0) + { + outStreamSizeCountSpec = new CSequentialOutStreamSizeCount; + outStreamSizeCount = outStreamSizeCountSpec; + outStreamSizeCountSpec->SetStream(mtOutStreamNotify ? (ISequentialOutStream *)mtOutStreamNotify : outStream); + outStreamSizeCountSpec->Init(); + outStreamPointers.Add(outStreamSizeCount); + } + + for (i = 1; i < _bindInfo.PackStreams.Size(); i++) + outStreamPointers.Add(tempBuffers[i - 1]); + + RINOK(_mixer->Code( + &inStreamPointer, + &outStreamPointers.Front(), + mtProgress ? (ICompressProgressInfo *)mtProgress : compressProgress)); - if (_bindInfo.OutStreams.Size() != 0) + if (_bindInfo.PackStreams.Size() != 0) packSizes.Add(outStreamSizeCountSpec->GetSize()); - for (i = 1; i < _bindInfo.OutStreams.Size(); i++) + for (i = 1; i < _bindInfo.PackStreams.Size(); i++) { CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1]; RINOK(inOutTempBuffer.WriteToStream(outStream)); @@ -274,37 +445,45 @@ HRESULT CEncoder::Encode( } unpackSize = 0; - for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++) + + for (i = 0; i < _bindInfo.Coders.Size(); i++) { - int binder = _bindInfo.FindBinderForInStream( - _bindReverseConverter->DestOutToSrcInMap[i]); + int bond = _bindInfo.FindBond_for_UnpackStream(_DestOut_to_SrcIn[i]); UInt64 streamSize; - if (binder < 0) + if (bond < 0) { streamSize = inStreamSizeCountSpec->GetSize(); unpackSize = streamSize; } else - streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder); + streamSize = _mixer->GetBondStreamSize(bond); coderUnpackSizes.Add(streamSize); } - for (i = 0; i < numMethods; i++) - folderItem.Coders[numMethods - 1 - i].Props = _codersInfo[i].Props; + return S_OK; } CEncoder::CEncoder(const CCompressionMethodMode &options): - _bindReverseConverter(0), - _constructed(false) + _constructed(false) { if (options.IsEmpty()) throw 1; _options = options; - _mixerCoderSpec = NULL; + + #ifdef USE_MIXER_ST + _mixerST = NULL; + #endif + + #ifdef USE_MIXER_MT + _mixerMT = NULL; + #endif + + _mixer = NULL; } + HRESULT CEncoder::EncoderConstr() { if (_constructed) @@ -314,112 +493,125 @@ HRESULT CEncoder::EncoderConstr() // it has only password method; if (!_options.PasswordIsDefined) throw 1; - if (!_options.Binds.IsEmpty()) + if (!_options.Bonds.IsEmpty()) throw 1; - NCoderMixer::CCoderStreamsInfo coderStreamsInfo; + CMethodFull method; - - method.NumInStreams = 1; - method.NumOutStreams = 1; - coderStreamsInfo.NumInStreams = 1; - coderStreamsInfo.NumOutStreams = 1; method.Id = k_AES; - + method.NumStreams = 1; _options.Methods.Add(method); + + NCoderMixer2::CCoderStreamsInfo coderStreamsInfo; + coderStreamsInfo.NumStreams = 1; _bindInfo.Coders.Add(coderStreamsInfo); - _bindInfo.InStreams.Add(0); - _bindInfo.OutStreams.Add(0); + _bindInfo.PackStreams.Add(0); + _bindInfo.UnpackCoder = 0; } else { - UInt32 numInStreams = 0, numOutStreams = 0; + UInt32 numOutStreams = 0; unsigned i; + for (i = 0; i < _options.Methods.Size(); i++) { const CMethodFull &methodFull = _options.Methods[i]; - NCoderMixer::CCoderStreamsInfo coderStreamsInfo; - coderStreamsInfo.NumInStreams = methodFull.NumOutStreams; - coderStreamsInfo.NumOutStreams = methodFull.NumInStreams; - if (_options.Binds.IsEmpty()) + NCoderMixer2::CCoderStreamsInfo cod; + + cod.NumStreams = methodFull.NumStreams; + + if (_options.Bonds.IsEmpty()) { - if (i < _options.Methods.Size() - 1) + // if there are no bonds in options, we create bonds via first streams of coders + if (i != _options.Methods.Size() - 1) { - NCoderMixer::CBindPair bindPair; - bindPair.InIndex = numInStreams + coderStreamsInfo.NumInStreams; - bindPair.OutIndex = numOutStreams; - _bindInfo.BindPairs.Add(bindPair); + NCoderMixer2::CBond bond; + bond.PackIndex = numOutStreams; + bond.UnpackIndex = i + 1; // it's next coder + _bindInfo.Bonds.Add(bond); } - else if (coderStreamsInfo.NumOutStreams != 0) - _bindInfo.OutStreams.Insert(0, numOutStreams); - for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++) - _bindInfo.OutStreams.Add(numOutStreams + j); + else if (cod.NumStreams != 0) + _bindInfo.PackStreams.Insert(0, numOutStreams); + + for (UInt32 j = 1; j < cod.NumStreams; j++) + _bindInfo.PackStreams.Add(numOutStreams + j); } - numInStreams += coderStreamsInfo.NumInStreams; - numOutStreams += coderStreamsInfo.NumOutStreams; + numOutStreams += cod.NumStreams; - _bindInfo.Coders.Add(coderStreamsInfo); + _bindInfo.Coders.Add(cod); } - if (!_options.Binds.IsEmpty()) + if (!_options.Bonds.IsEmpty()) { - for (i = 0; i < _options.Binds.Size(); i++) + for (i = 0; i < _options.Bonds.Size(); i++) { - NCoderMixer::CBindPair bindPair; - const CBind &bind = _options.Binds[i]; - bindPair.InIndex = _bindInfo.GetCoderInStreamIndex(bind.InCoder) + bind.InStream; - bindPair.OutIndex = _bindInfo.GetCoderOutStreamIndex(bind.OutCoder) + bind.OutStream; - _bindInfo.BindPairs.Add(bindPair); + NCoderMixer2::CBond mixerBond; + const CBond2 &bond = _options.Bonds[i]; + if (bond.InCoder >= _bindInfo.Coders.Size() + || bond.OutCoder >= _bindInfo.Coders.Size() + || bond.OutStream >= _bindInfo.Coders[bond.OutCoder].NumStreams) + return E_INVALIDARG; + mixerBond.PackIndex = _bindInfo.GetStream_for_Coder(bond.OutCoder) + bond.OutStream; + mixerBond.UnpackIndex = bond.InCoder; + _bindInfo.Bonds.Add(mixerBond); } - for (i = 0; i < (int)numOutStreams; i++) - if (_bindInfo.FindBinderForOutStream(i) == -1) - _bindInfo.OutStreams.Add(i); + + for (i = 0; i < numOutStreams; i++) + if (_bindInfo.FindBond_for_PackStream(i) == -1) + _bindInfo.PackStreams.Add(i); } - for (i = 0; i < (int)numInStreams; i++) - if (_bindInfo.FindBinderForInStream(i) == -1) - _bindInfo.InStreams.Add(i); + if (!_bindInfo.SetUnpackCoder()) + return E_INVALIDARG; - if (_bindInfo.InStreams.IsEmpty()) - throw 1; // this is error + if (!_bindInfo.CalcMapsAndCheck()) + return E_INVALIDARG; - // Make main stream first in list - int inIndex = _bindInfo.InStreams[0]; - for (;;) + if (_bindInfo.PackStreams.Size() != 1) { - UInt32 coderIndex, coderStreamIndex; - _bindInfo.FindInStream(inIndex, coderIndex, coderStreamIndex); - UInt32 outIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex); - int binder = _bindInfo.FindBinderForOutStream(outIndex); - if (binder >= 0) + /* main_PackStream is pack stream of main path of coders tree. + We find main_PackStream, and place to start of list of out streams. + It allows to use more optimal memory usage for temp buffers, + if main_PackStream is largest stream. */ + + UInt32 ci = _bindInfo.UnpackCoder; + + for (;;) { - inIndex = _bindInfo.BindPairs[binder].InIndex; - continue; - } - for (i = 0; i < _bindInfo.OutStreams.Size(); i++) - if (_bindInfo.OutStreams[i] == outIndex) - { - _bindInfo.OutStreams.Delete(i); - _bindInfo.OutStreams.Insert(0, outIndex); + if (_bindInfo.Coders[ci].NumStreams == 0) break; + + UInt32 outIndex = _bindInfo.Coder_to_Stream[ci]; + int bond = _bindInfo.FindBond_for_PackStream(outIndex); + if (bond >= 0) + { + ci = _bindInfo.Bonds[bond].UnpackIndex; + continue; } - break; + + int i = _bindInfo.FindStream_in_PackStreams(outIndex); + if (i >= 0) + _bindInfo.PackStreams.MoveToFront(i); + break; + } } if (_options.PasswordIsDefined) { - unsigned numCryptoStreams = _bindInfo.OutStreams.Size(); + unsigned numCryptoStreams = _bindInfo.PackStreams.Size(); + unsigned numInStreams = _bindInfo.Coders.Size(); + for (i = 0; i < numCryptoStreams; i++) { - NCoderMixer::CBindPair bindPair; - bindPair.InIndex = numInStreams + i; - bindPair.OutIndex = _bindInfo.OutStreams[i]; - _bindInfo.BindPairs.Add(bindPair); + NCoderMixer2::CBond bond; + bond.UnpackIndex = numInStreams + i; + bond.PackIndex = _bindInfo.PackStreams[i]; + _bindInfo.Bonds.Add(bond); } - _bindInfo.OutStreams.Clear(); + _bindInfo.PackStreams.Clear(); /* if (numCryptoStreams == 0) @@ -428,37 +620,37 @@ HRESULT CEncoder::EncoderConstr() for (i = 0; i < numCryptoStreams; i++) { - NCoderMixer::CCoderStreamsInfo coderStreamsInfo; CMethodFull method; - method.NumInStreams = 1; - method.NumOutStreams = 1; - coderStreamsInfo.NumInStreams = method.NumOutStreams; - coderStreamsInfo.NumOutStreams = method.NumInStreams; + method.NumStreams = 1; method.Id = k_AES; - _options.Methods.Add(method); - _bindInfo.Coders.Add(coderStreamsInfo); - _bindInfo.OutStreams.Add(numOutStreams + i); + + NCoderMixer2::CCoderStreamsInfo cod; + cod.NumStreams = 1; + _bindInfo.Coders.Add(cod); + + _bindInfo.PackStreams.Add(numOutStreams++); } } } - for (int i = _options.Methods.Size() - 1; i >= 0; i--) - { - const CMethodFull &methodFull = _options.Methods[i]; - _decompressionMethods.Add(methodFull.Id); - } + for (unsigned i = _options.Methods.Size(); i != 0;) + _decompressionMethods.Add(_options.Methods[--i].Id); - _bindReverseConverter = new NCoderMixer::CBindReverseConverter(_bindInfo); - _bindReverseConverter->CreateReverseBindInfo(_decompressBindInfo); + if (_bindInfo.Coders.Size() > 16) + return E_INVALIDARG; + if (_bindInfo.GetNum_Bonds_and_PackStreams() > 16) + return E_INVALIDARG; + + if (!_bindInfo.CalcMapsAndCheck()) + return E_INVALIDARG; + + InitBindConv(); _constructed = true; return S_OK; } -CEncoder::~CEncoder() -{ - delete _bindReverseConverter; -} +CEncoder::~CEncoder() {} }} diff --git a/CPP/7zip/Archive/7z/7zEncode.h b/CPP/7zip/Archive/7z/7zEncode.h index 8e20bdb5..f1a9b5ad 100644 --- a/CPP/7zip/Archive/7z/7zEncode.h +++ b/CPP/7zip/Archive/7z/7zEncode.h @@ -3,47 +3,82 @@ #ifndef __7Z_ENCODE_H #define __7Z_ENCODE_H -// #include "../../Common/StreamObjects.h" - #include "7zCompressionMode.h" #include "../Common/CoderMixer2.h" -#include "../Common/CoderMixer2MT.h" -#ifdef _ST_MODE -#include "../Common/CoderMixer2ST.h" -#endif -#include "7zItem.h" -#include "../../Common/CreateCoder.h" +#include "7zItem.h" namespace NArchive { namespace N7z { -class CEncoder +class CMtEncMultiProgress: + public ICompressProgressInfo, + public CMyUnknownImp { - NCoderMixer::CCoderMixer2MT *_mixerCoderSpec; - CMyComPtr<ICompressCoder2> _mixerCoder; + CMyComPtr<ICompressProgressInfo> _progress; + #ifndef _7ZIP_ST + NWindows::NSynchronization::CCriticalSection CriticalSection; + #endif + +public: + UInt64 OutSize; + + CMtEncMultiProgress(): OutSize(0) {} + + void Init(ICompressProgressInfo *progress); - CObjectVector<CCoderInfo> _codersInfo; + void AddOutSize(UInt64 addOutSize) + { + #ifndef _7ZIP_ST + NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); + #endif + OutSize += addOutSize; + } + + MY_UNKNOWN_IMP1(ICompressProgressInfo) + + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); +}; + +class CEncoder +{ + #ifdef USE_MIXER_ST + NCoderMixer2::CMixerST *_mixerST; + #endif + #ifdef USE_MIXER_MT + NCoderMixer2::CMixerMT *_mixerMT; + #endif + + NCoderMixer2::CMixer *_mixer; + CMyComPtr<IUnknown> _mixerRef; CCompressionMethodMode _options; - NCoderMixer::CBindInfo _bindInfo; - NCoderMixer::CBindInfo _decompressBindInfo; - NCoderMixer::CBindReverseConverter *_bindReverseConverter; + NCoderMixer2::CBindInfo _bindInfo; CRecordVector<CMethodId> _decompressionMethods; + CRecordVector<UInt32> _SrcIn_to_DestOut; + CRecordVector<UInt32> _SrcOut_to_DestIn; + // CRecordVector<UInt32> _DestIn_to_SrcOut; + CRecordVector<UInt32> _DestOut_to_SrcIn; + + void InitBindConv(); + void SetFolder(CFolder &folder); + HRESULT CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS const UInt64 *inSizeForReduce); bool _constructed; public: + CEncoder(const CCompressionMethodMode &options); ~CEncoder(); HRESULT EncoderConstr(); HRESULT Encode( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, - const UInt64 *inStreamSize, const UInt64 *inSizeForReduce, + // const UInt64 *inStreamSize, + const UInt64 *inSizeForReduce, CFolder &folderItem, CRecordVector<UInt64> &coderUnpackSizes, UInt64 &unpackSize, diff --git a/CPP/7zip/Archive/7z/7zExtract.cpp b/CPP/7zip/Archive/7z/7zExtract.cpp index 6d2c5b06..d21bafdb 100644 --- a/CPP/7zip/Archive/7z/7zExtract.cpp +++ b/CPP/7zip/Archive/7z/7zExtract.cpp @@ -2,205 +2,327 @@ #include "StdAfx.h" +#include "../../../../C/7zCrc.h" + #include "../../../Common/ComTry.h" #include "../../Common/ProgressUtils.h" #include "7zDecode.h" -// #include "7z1Decode.h" -#include "7zFolderOutStream.h" #include "7zHandler.h" +// EXTERN_g_ExternalCodecs + namespace NArchive { namespace N7z { -struct CExtractFolderInfo +class CFolderOutStream: + public ISequentialOutStream, + public CMyUnknownImp { - #ifdef _7Z_VOL - int VolumeIndex; - #endif - CNum FileIndex; - CNum FolderIndex; - CBoolVector ExtractStatuses; - UInt64 UnpackSize; - CExtractFolderInfo( - #ifdef _7Z_VOL - int volumeIndex, - #endif - CNum fileIndex, CNum folderIndex): - #ifdef _7Z_VOL - VolumeIndex(volumeIndex), - #endif - FileIndex(fileIndex), - FolderIndex(folderIndex), - UnpackSize(0) + CMyComPtr<ISequentialOutStream> _stream; +public: + bool TestMode; + bool CheckCrc; +private: + bool _fileIsOpen; + bool _calcCrc; + UInt32 _crc; + UInt64 _rem; + + const UInt32 *_indexes; + unsigned _numFiles; + unsigned _fileIndex; + + HRESULT OpenFile(bool isCorrupted = false); + HRESULT CloseFile_and_SetResult(Int32 res); + HRESULT CloseFile(); + HRESULT ProcessEmptyFiles(); + +public: + MY_UNKNOWN_IMP1(ISequentialOutStream) + + const CDbEx *_db; + CMyComPtr<IArchiveExtractCallback> ExtractCallback; + + bool ExtraWriteWasCut; + + CFolderOutStream(): + TestMode(false), + CheckCrc(true) + {} + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + + HRESULT Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles); + HRESULT FlushCorrupted(Int32 callbackOperationResult); + + bool WasWritingFinished() const { return _numFiles == 0; } +}; + + +HRESULT CFolderOutStream::Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles) +{ + _fileIndex = startIndex; + _indexes = indexes; + _numFiles = numFiles; + + _fileIsOpen = false; + ExtraWriteWasCut = false; + + return ProcessEmptyFiles(); +} + +HRESULT CFolderOutStream::OpenFile(bool isCorrupted) +{ + const CFileItem &fi = _db->Files[_fileIndex]; + UInt32 nextFileIndex = (_indexes ? *_indexes : _fileIndex); + Int32 askMode = (_fileIndex == nextFileIndex) ? + (TestMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract) : + NExtract::NAskMode::kSkip; + + if (isCorrupted + && askMode == NExtract::NAskMode::kExtract + && !_db->IsItemAnti(_fileIndex) + && !fi.IsDir) + askMode = NExtract::NAskMode::kTest; + + CMyComPtr<ISequentialOutStream> realOutStream; + RINOK(ExtractCallback->GetStream(_fileIndex, &realOutStream, askMode)); + + _stream = realOutStream; + _crc = CRC_INIT_VAL; + _calcCrc = (CheckCrc && fi.CrcDefined && !fi.IsDir); + + _fileIsOpen = true; + _rem = fi.Size; + + if (askMode == NExtract::NAskMode::kExtract + && !realOutStream + && !_db->IsItemAnti(_fileIndex) + && !fi.IsDir) + askMode = NExtract::NAskMode::kSkip; + return ExtractCallback->PrepareOperation(askMode); +} + +HRESULT CFolderOutStream::CloseFile_and_SetResult(Int32 res) +{ + _stream.Release(); + _fileIsOpen = false; + + if (!_indexes) + _numFiles--; + else if (*_indexes == _fileIndex) + { + _indexes++; + _numFiles--; + } + + _fileIndex++; + return ExtractCallback->SetOperationResult(res); +} + +HRESULT CFolderOutStream::CloseFile() +{ + const CFileItem &fi = _db->Files[_fileIndex]; + return CloseFile_and_SetResult((!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc)) ? + NExtract::NOperationResult::kOK : + NExtract::NOperationResult::kCRCError); +} + +HRESULT CFolderOutStream::ProcessEmptyFiles() +{ + while (_numFiles != 0 && _db->Files[_fileIndex].Size == 0) { - if (fileIndex != kNumNoIndex) + RINOK(OpenFile()); + RINOK(CloseFile()); + } + return S_OK; +} + +STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + + while (size != 0) + { + if (_fileIsOpen) { - ExtractStatuses.ClearAndSetSize(1); - ExtractStatuses[0] = true; + UInt32 cur = (size < _rem ? size : (UInt32)_rem); + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, cur, &cur); + if (_calcCrc) + _crc = CrcUpdate(_crc, data, cur); + if (processedSize) + *processedSize += cur; + data = (const Byte *)data + cur; + size -= cur; + _rem -= cur; + if (_rem == 0) + { + RINOK(CloseFile()); + RINOK(ProcessEmptyFiles()); + } + RINOK(result); + if (cur == 0) + break; + continue; } - }; -}; + + RINOK(ProcessEmptyFiles()); + if (_numFiles == 0) + { + // we support partial extracting + /* + if (processedSize) + *processedSize += size; + break; + */ + ExtraWriteWasCut = true; + // return S_FALSE; + return k_My_HRESULT_WritingWasCut; + } + RINOK(OpenFile()); + } + + return S_OK; +} + +HRESULT CFolderOutStream::FlushCorrupted(Int32 callbackOperationResult) +{ + while (_numFiles != 0) + { + if (_fileIsOpen) + { + RINOK(CloseFile_and_SetResult(callbackOperationResult)); + } + else + { + RINOK(OpenFile(true)); + } + } + return S_OK; +} STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec) { COM_TRY_BEGIN - bool testMode = (testModeSpec != 0); + CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec; + UInt64 importantTotalUnpacked = 0; + // numItems = (UInt32)(Int32)-1; + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) - numItems = - #ifdef _7Z_VOL - _refs.Size(); - #else - _db.Files.Size(); - #endif + numItems = _db.Files.Size(); - if(numItems == 0) + if (numItems == 0) return S_OK; - /* - if(_volumes.Size() != 1) - return E_FAIL; - const CVolume &volume = _volumes.Front(); - const CDbEx &_db = volume.Database; - IInStream *_inStream = volume.Stream; - */ - - CObjectVector<CExtractFolderInfo> extractFolderInfoVector; - for (UInt32 ii = 0; ii < numItems; ii++) { - // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex]; - UInt32 ref2Index = allFilesMode ? ii : indices[ii]; - // const CRef2 &ref2 = _refs[ref2Index]; - - // for (UInt32 ri = 0; ri < ref2.Refs.Size(); ri++) + CNum prevFolder = kNumNoIndex; + UInt32 nextFile = 0; + + UInt32 i; + + for (i = 0; i < numItems; i++) { - #ifdef _7Z_VOL - // const CRef &ref = ref2.Refs[ri]; - const CRef &ref = _refs[ref2Index]; - - int volumeIndex = ref.VolumeIndex; - const CVolume &volume = _volumes[volumeIndex]; - const CDbEx &db = volume.Database; - UInt32 fileIndex = ref.ItemIndex; - #else - const CDbEx &db = _db; - UInt32 fileIndex = ref2Index; - #endif - - CNum folderIndex = db.FileIndexToFolderIndexMap[fileIndex]; + UInt32 fileIndex = allFilesMode ? i : indices[i]; + CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; if (folderIndex == kNumNoIndex) - { - extractFolderInfoVector.Add(CExtractFolderInfo( - #ifdef _7Z_VOL - volumeIndex, - #endif - fileIndex, kNumNoIndex)); continue; - } - if (extractFolderInfoVector.IsEmpty() || - folderIndex != extractFolderInfoVector.Back().FolderIndex - #ifdef _7Z_VOL - || volumeIndex != extractFolderInfoVector.Back().VolumeIndex - #endif - ) - { - extractFolderInfoVector.Add(CExtractFolderInfo( - #ifdef _7Z_VOL - volumeIndex, - #endif - kNumNoIndex, folderIndex)); - UInt64 unpackSize = db.GetFolderUnpackSize(folderIndex); - importantTotalUnpacked += unpackSize; - extractFolderInfoVector.Back().UnpackSize = unpackSize; - } - - CExtractFolderInfo &efi = extractFolderInfoVector.Back(); - - // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex]; - CNum startIndex = db.FolderStartFileIndex[folderIndex]; - for (CNum index = efi.ExtractStatuses.Size(); - index <= fileIndex - startIndex; index++) - { - // UInt64 unpackSize = _db.Files[startIndex + index].UnpackSize; - // Count partial_folder_size - // efi.UnpackSize += unpackSize; - // importantTotalUnpacked += unpackSize; - efi.ExtractStatuses.Add(index == fileIndex - startIndex); - } + if (folderIndex != prevFolder || fileIndex < nextFile) + nextFile = _db.FolderStartFileIndex[folderIndex]; + for (CNum index = nextFile; index <= fileIndex; index++) + importantTotalUnpacked += _db.Files[index].Size; + nextFile = fileIndex + 1; + prevFolder = folderIndex; } } RINOK(extractCallback->SetTotal(importantTotalUnpacked)); + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + CDecoder decoder( - #ifdef _ST_MODE - false + #ifndef USE_MIXER_ST + false #else - true + _useMultiThreadMixer #endif ); - // CDecoder1 decoder; - UInt64 totalPacked = 0; - UInt64 totalUnpacked = 0; UInt64 curPacked, curUnpacked; - CLocalProgress *lps = new CLocalProgress; - CMyComPtr<ICompressProgressInfo> progress = lps; - lps->Init(extractCallback, false); + CMyComPtr<IArchiveExtractCallbackMessage> callbackMessage; + extractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage, &callbackMessage); + + CFolderOutStream *folderOutStream = new CFolderOutStream; + CMyComPtr<ISequentialOutStream> outStream(folderOutStream); - for (unsigned i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked) + folderOutStream->_db = &_db; + folderOutStream->ExtractCallback = extractCallback; + folderOutStream->TestMode = (testModeSpec != 0); + folderOutStream->CheckCrc = (_crcSize != 0); + + for (UInt32 i = 0;; lps->OutSize += curUnpacked, lps->InSize += curPacked) { - lps->OutSize = totalUnpacked; - lps->InSize = totalPacked; RINOK(lps->SetCur()); - if (i >= extractFolderInfoVector.Size()) + if (i >= numItems) break; - - const CExtractFolderInfo &efi = extractFolderInfoVector[i]; - curUnpacked = efi.UnpackSize; + + curUnpacked = 0; curPacked = 0; - CFolderOutStream *folderOutStream = new CFolderOutStream; - CMyComPtr<ISequentialOutStream> outStream(folderOutStream); + UInt32 fileIndex = allFilesMode ? i : indices[i]; + CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; - #ifdef _7Z_VOL - const CVolume &volume = _volumes[efi.VolumeIndex]; - const CDbEx &db = volume.Database; - #else - const CDbEx &db = _db; - #endif + UInt32 numSolidFiles = 1; - CNum startIndex; - if (efi.FileIndex != kNumNoIndex) - startIndex = efi.FileIndex; - else - startIndex = db.FolderStartFileIndex[efi.FolderIndex]; + if (folderIndex != kNumNoIndex) + { + curPacked = _db.GetFolderFullPackSize(folderIndex); + UInt32 nextFile = fileIndex + 1; + fileIndex = _db.FolderStartFileIndex[folderIndex]; + UInt32 k; + + for (k = i + 1; k < numItems; k++) + { + UInt32 fileIndex2 = allFilesMode ? k : indices[k]; + if (_db.FileIndexToFolderIndexMap[fileIndex2] != folderIndex + || fileIndex2 < nextFile) + break; + nextFile = fileIndex2 + 1; + } + + numSolidFiles = k - i; + + for (k = fileIndex; k < nextFile; k++) + curUnpacked += _db.Files[k].Size; + } + + HRESULT result = folderOutStream->Init(fileIndex, + allFilesMode ? NULL : indices + i, + numSolidFiles); - HRESULT result = folderOutStream->Init(&db, - #ifdef _7Z_VOL - volume.StartRef2Index, - #else - 0, - #endif - startIndex, - &efi.ExtractStatuses, extractCallback, testMode, _crcSize != 0); + i += numSolidFiles; RINOK(result); - if (efi.FileIndex != kNumNoIndex) + // to test solid block with zero unpacked size we disable that code + if (folderOutStream->WasWritingFinished()) continue; - CNum folderIndex = efi.FolderIndex; - curPacked = _db.GetFolderFullPackSize(folderIndex); - #ifndef _NO_CRYPTO CMyComPtr<ICryptoGetTextPassword> getTextPassword; if (extractCallback) @@ -212,50 +334,64 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, #ifndef _NO_CRYPTO bool isEncrypted = false; bool passwordIsDefined = false; + UString password; #endif + HRESULT result = decoder.Decode( EXTERNAL_CODECS_VARS - #ifdef _7Z_VOL - volume.Stream, - #else - _inStream, - #endif - db.ArcInfo.DataStartPosition, - db, folderIndex, + _inStream, + _db.ArcInfo.DataStartPosition, + _db, folderIndex, + &curUnpacked, + outStream, - progress + progress, + NULL // *inStreamMainRes + _7Z_DECODER_CRYPRO_VARS #if !defined(_7ZIP_ST) && !defined(_SFX) , true, _numThreads #endif ); - if (result == S_FALSE) + if (result == S_FALSE || result == E_NOTIMPL) { - RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); - continue; - } - if (result == E_NOTIMPL) - { - RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kUnsupportedMethod)); + bool wasFinished = folderOutStream->WasWritingFinished(); + + int resOp = (result == S_FALSE ? + NExtract::NOperationResult::kDataError : + NExtract::NOperationResult::kUnsupportedMethod); + + RINOK(folderOutStream->FlushCorrupted(resOp)); + + if (wasFinished) + { + // we don't show error, if it's after required files + if (/* !folderOutStream->ExtraWriteWasCut && */ callbackMessage) + { + RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, resOp)); + } + } continue; } + if (result != S_OK) return result; - if (folderOutStream->WasWritingFinished() != S_OK) - { - RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); - continue; - } + + RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); + continue; } catch(...) { RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); - continue; + // continue; + return E_FAIL; } } + return S_OK; + COM_TRY_END } diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/CPP/7zip/Archive/7z/7zFolderInStream.cpp index 3f420a51..14cdc436 100644 --- a/CPP/7zip/Archive/7z/7zFolderInStream.cpp +++ b/CPP/7zip/Archive/7z/7zFolderInStream.cpp @@ -7,96 +7,103 @@ namespace NArchive { namespace N7z { -CFolderInStream::CFolderInStream() -{ - _inStreamWithHashSpec = new CSequentialInStreamWithCRC; - _inStreamWithHash = _inStreamWithHashSpec; -} - void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback, - const UInt32 *fileIndices, UInt32 numFiles) + const UInt32 *indexes, unsigned numFiles) { _updateCallback = updateCallback; + _indexes = indexes; _numFiles = numFiles; - _fileIndex = 0; - _fileIndices = fileIndices; - Processed.Clear(); - CRCs.Clear(); - Sizes.Clear(); - _fileIsOpen = false; - _currentSizeIsDefined = false; + _index = 0; + + Processed.ClearAndReserve(numFiles); + CRCs.ClearAndReserve(numFiles); + Sizes.ClearAndReserve(numFiles); + + _pos = 0; + _crc = CRC_INIT_VAL; + _size_Defined = false; + _size = 0; + + _stream.Release(); } HRESULT CFolderInStream::OpenStream() { - _filePos = 0; - while (_fileIndex < _numFiles) + _pos = 0; + _crc = CRC_INIT_VAL; + _size_Defined = false; + _size = 0; + + while (_index < _numFiles) { CMyComPtr<ISequentialInStream> stream; - HRESULT result = _updateCallback->GetStream(_fileIndices[_fileIndex], &stream); - if (result != S_OK && result != S_FALSE) - return result; - _fileIndex++; - _inStreamWithHashSpec->SetStream(stream); - _inStreamWithHashSpec->Init(); + HRESULT result = _updateCallback->GetStream(_indexes[_index], &stream); + if (result != S_OK) + { + if (result != S_FALSE) + return result; + } + + _stream = stream; + if (stream) { - _fileIsOpen = true; CMyComPtr<IStreamGetSize> streamGetSize; stream.QueryInterface(IID_IStreamGetSize, &streamGetSize); if (streamGetSize) { - RINOK(streamGetSize->GetSize(&_currentSize)); - _currentSizeIsDefined = true; + if (streamGetSize->GetSize(&_size) == S_OK) + _size_Defined = true; } return S_OK; } + + _index++; RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); - Sizes.Add(0); - Processed.Add(result == S_OK); - AddDigest(); + AddFileInfo(result == S_OK); } return S_OK; } -void CFolderInStream::AddDigest() +void CFolderInStream::AddFileInfo(bool isProcessed) { - CRCs.Add(_inStreamWithHashSpec->GetCRC()); -} - -HRESULT CFolderInStream::CloseStream() -{ - RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); - _inStreamWithHashSpec->ReleaseStream(); - _fileIsOpen = false; - _currentSizeIsDefined = false; - Processed.Add(true); - Sizes.Add(_filePos); - AddDigest(); - return S_OK; + Processed.Add(isProcessed); + Sizes.Add(_pos); + CRCs.Add(CRC_GET_DIGEST(_crc)); } STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { - if (processedSize != 0) + if (processedSize) *processedSize = 0; - while (size > 0) + while (size != 0) { - if (_fileIsOpen) + if (_stream) { UInt32 processed2; - RINOK(_inStreamWithHash->Read(data, size, &processed2)); - if (processed2 == 0) + RINOK(_stream->Read(data, size, &processed2)); + if (processed2 != 0) { - RINOK(CloseStream()); - continue; + _crc = CrcUpdate(_crc, data, processed2); + _pos += processed2; + if (processedSize) + *processedSize = processed2; + return S_OK; } - if (processedSize != 0) - *processedSize = processed2; - _filePos += processed2; - break; + + _stream.Release(); + _index++; + AddFileInfo(true); + + _pos = 0; + _crc = CRC_INIT_VAL; + _size_Defined = false; + _size = 0; + + RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } - if (_fileIndex >= _numFiles) + + if (_index >= _numFiles) break; RINOK(OpenStream()); } @@ -106,17 +113,23 @@ STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSiz STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value) { *value = 0; - unsigned index2 = (unsigned)subStream; if (subStream > Sizes.Size()) - return E_FAIL; - if (index2 < Sizes.Size()) + return S_FALSE; // E_FAIL; + + unsigned index = (unsigned)subStream; + if (index < Sizes.Size()) { - *value = Sizes[index2]; + *value = Sizes[index]; return S_OK; } - if (!_currentSizeIsDefined) + + if (!_size_Defined) + { + *value = _pos; return S_FALSE; - *value = _currentSize; + } + + *value = (_pos > _size ? _pos : _size); return S_OK; } diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.h b/CPP/7zip/Archive/7z/7zFolderInStream.h index 4ed4b2dd..805db54e 100644 --- a/CPP/7zip/Archive/7z/7zFolderInStream.h +++ b/CPP/7zip/Archive/7z/7zFolderInStream.h @@ -3,11 +3,13 @@ #ifndef __7Z_FOLDER_IN_STREAM_H #define __7Z_FOLDER_IN_STREAM_H +#include "../../../../C/7zCrc.h" + +#include "../../../Common/MyCom.h" +#include "../../../Common/MyVector.h" + #include "../../ICoder.h" #include "../IArchive.h" -#include "../Common/InStreamWithCRC.h" - -#include "7zItem.h" namespace NArchive { namespace N7z { @@ -17,33 +19,34 @@ class CFolderInStream: public ICompressGetSubStreamSize, public CMyUnknownImp { - CSequentialInStreamWithCRC *_inStreamWithHashSpec; - CMyComPtr<ISequentialInStream> _inStreamWithHash; - CMyComPtr<IArchiveUpdateCallback> _updateCallback; + CMyComPtr<ISequentialInStream> _stream; + UInt64 _pos; + UInt32 _crc; + bool _size_Defined; + UInt64 _size; - bool _currentSizeIsDefined; - bool _fileIsOpen; - UInt64 _currentSize; - UInt64 _filePos; - const UInt32 *_fileIndices; - UInt32 _numFiles; - UInt32 _fileIndex; + const UInt32 *_indexes; + unsigned _numFiles; + unsigned _index; + + CMyComPtr<IArchiveUpdateCallback> _updateCallback; HRESULT OpenStream(); - HRESULT CloseStream(); - void AddDigest(); + void AddFileInfo(bool isProcessed); public: CRecordVector<bool> Processed; CRecordVector<UInt32> CRCs; CRecordVector<UInt64> Sizes; - MY_UNKNOWN_IMP1(ICompressGetSubStreamSize) + MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); - CFolderInStream(); - void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *fileIndices, UInt32 numFiles); + void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *indexes, unsigned numFiles); + + bool WasFinished() const { return _index == _numFiles; } + UInt64 GetFullSize() const { UInt64 size = 0; diff --git a/CPP/7zip/Archive/7z/7zFolderOutStream.cpp b/CPP/7zip/Archive/7z/7zFolderOutStream.cpp index 847f65bf..e63ee925 100644 --- a/CPP/7zip/Archive/7z/7zFolderOutStream.cpp +++ b/CPP/7zip/Archive/7z/7zFolderOutStream.cpp @@ -1,149 +1,3 @@ // 7zFolderOutStream.cpp #include "StdAfx.h" - -#include "7zFolderOutStream.h" - -namespace NArchive { -namespace N7z { - -CFolderOutStream::CFolderOutStream() -{ - _crcStreamSpec = new COutStreamWithCRC; - _crcStream = _crcStreamSpec; -} - -HRESULT CFolderOutStream::Init( - const CDbEx *db, - UInt32 ref2Offset, UInt32 startIndex, - const CBoolVector *extractStatuses, - IArchiveExtractCallback *extractCallback, - bool testMode, bool checkCrc) -{ - _db = db; - _ref2Offset = ref2Offset; - _startIndex = startIndex; - - _extractStatuses = extractStatuses; - _extractCallback = extractCallback; - _testMode = testMode; - _checkCrc = checkCrc; - - _currentIndex = 0; - _fileIsOpen = false; - return ProcessEmptyFiles(); -} - -HRESULT CFolderOutStream::OpenFile() -{ - Int32 askMode = ((*_extractStatuses)[_currentIndex]) ? (_testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract) : - NExtract::NAskMode::kSkip; - CMyComPtr<ISequentialOutStream> realOutStream; - UInt32 index = _startIndex + _currentIndex; - RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode)); - _crcStreamSpec->SetStream(realOutStream); - _crcStreamSpec->Init(_checkCrc); - _fileIsOpen = true; - const CFileItem &fi = _db->Files[index]; - _rem = fi.Size; - if (askMode == NExtract::NAskMode::kExtract && !realOutStream && - !_db->IsItemAnti(index) && !fi.IsDir) - askMode = NExtract::NAskMode::kSkip; - return _extractCallback->PrepareOperation(askMode); -} - -HRESULT CFolderOutStream::CloseFileAndSetResult(Int32 res) -{ - _crcStreamSpec->ReleaseStream(); - _fileIsOpen = false; - _currentIndex++; - return _extractCallback->SetOperationResult(res); -} - -HRESULT CFolderOutStream::CloseFileAndSetResult() -{ - const CFileItem &fi = _db->Files[_startIndex + _currentIndex]; - return CloseFileAndSetResult( - (fi.IsDir || !fi.CrcDefined || !_checkCrc || fi.Crc == _crcStreamSpec->GetCRC()) ? - NExtract::NOperationResult::kOK : - NExtract::NOperationResult::kCRCError); -} - -HRESULT CFolderOutStream::ProcessEmptyFiles() -{ - while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0) - { - RINOK(OpenFile()); - RINOK(CloseFileAndSetResult()); - } - return S_OK; -} - -STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) -{ - if (processedSize != NULL) - *processedSize = 0; - while (size != 0) - { - if (_fileIsOpen) - { - UInt32 cur = size < _rem ? size : (UInt32)_rem; - RINOK(_crcStream->Write(data, cur, &cur)); - if (cur == 0) - break; - data = (const Byte *)data + cur; - size -= cur; - _rem -= cur; - if (processedSize != NULL) - *processedSize += cur; - if (_rem == 0) - { - RINOK(CloseFileAndSetResult()); - RINOK(ProcessEmptyFiles()); - continue; - } - } - else - { - RINOK(ProcessEmptyFiles()); - if (_currentIndex == _extractStatuses->Size()) - { - // we support partial extracting - if (processedSize != NULL) - *processedSize += size; - break; - } - RINOK(OpenFile()); - } - } - return S_OK; -} - -STDMETHODIMP CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value) -{ - *value = 0; - if ((int)subStream >= _extractStatuses->Size()) - return S_FALSE; - *value = _db->Files[_startIndex + (int)subStream].Size; - return S_OK; -} - -HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult) -{ - while (_currentIndex < _extractStatuses->Size()) - { - if (_fileIsOpen) - { - RINOK(CloseFileAndSetResult(resultEOperationResult)); - } - else - { - RINOK(OpenFile()); - } - } - return S_OK; -} - -}} diff --git a/CPP/7zip/Archive/7z/7zFolderOutStream.h b/CPP/7zip/Archive/7z/7zFolderOutStream.h index cc2d7734..a32b22e0 100644 --- a/CPP/7zip/Archive/7z/7zFolderOutStream.h +++ b/CPP/7zip/Archive/7z/7zFolderOutStream.h @@ -3,56 +3,4 @@ #ifndef __7Z_FOLDER_OUT_STREAM_H #define __7Z_FOLDER_OUT_STREAM_H -#include "../../IStream.h" -#include "../IArchive.h" -#include "../Common/OutStreamWithCRC.h" - -#include "7zIn.h" - -namespace NArchive { -namespace N7z { - -class CFolderOutStream: - public ISequentialOutStream, - public ICompressGetSubStreamSize, - public CMyUnknownImp -{ - COutStreamWithCRC *_crcStreamSpec; - CMyComPtr<ISequentialOutStream> _crcStream; - const CDbEx *_db; - const CBoolVector *_extractStatuses; - CMyComPtr<IArchiveExtractCallback> _extractCallback; - UInt32 _ref2Offset; - UInt32 _startIndex; - unsigned _currentIndex; - bool _testMode; - bool _checkCrc; - bool _fileIsOpen; - UInt64 _rem; - - HRESULT OpenFile(); - HRESULT CloseFileAndSetResult(Int32 res); - HRESULT CloseFileAndSetResult(); - HRESULT ProcessEmptyFiles(); -public: - MY_UNKNOWN_IMP1(ICompressGetSubStreamSize) - - CFolderOutStream(); - - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); - - HRESULT Init( - const CDbEx *db, - UInt32 ref2Offset, UInt32 startIndex, - const CBoolVector *extractStatuses, - IArchiveExtractCallback *extractCallback, - bool testMode, bool checkCrc); - HRESULT FlushCorrupted(Int32 resultEOperationResult); - HRESULT WasWritingFinished() const - { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; } -}; - -}} - #endif diff --git a/CPP/7zip/Archive/7z/7zHandler.cpp b/CPP/7zip/Archive/7z/7zHandler.cpp index 2b86ed22..d397e818 100644 --- a/CPP/7zip/Archive/7z/7zHandler.cpp +++ b/CPP/7zip/Archive/7z/7zHandler.cpp @@ -150,22 +150,12 @@ static char *AddProp32(char *s, const char *name, UInt32 v) 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()) + AString name; + FindMethod(EXTERNAL_CODECS_VARS id, name); + if (name.IsEmpty()) ConvertMethodIdToString(s, id); else - for (unsigned i = 0; i < methodName.Len(); i++) - s += (char)methodName[i]; + s += name; } #endif @@ -186,8 +176,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) FOR_VECTOR (i, pm.IDs) { UInt64 id = pm.IDs[i]; - if (!s.IsEmpty()) - s += ' '; + s.Add_Space_if_NotEmpty(); char temp[16]; if (id == k_LZMA2) { @@ -376,6 +365,7 @@ HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const // numCoders == 0 ??? CNum numCoders = inByte.ReadNum(); bool needSpace = false; + for (; numCoders != 0; numCoders--, needSpace = true) { if (pos < 32) // max size of property @@ -500,17 +490,8 @@ HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const } else { - UString methodName; + AString 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()) @@ -522,10 +503,11 @@ HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const break; pos -= len; for (unsigned i = 0; i < len; i++) - temp[pos + i] = (char)methodName[i]; + temp[pos + i] = methodName[i]; } } } + if (numCoders != 0 && pos >= 4) { temp[--pos] = ' '; @@ -533,6 +515,7 @@ HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const temp[--pos] = '.'; temp[--pos] = '.'; } + return PropVarEm_Set_Str(prop, temp + pos); // } } @@ -555,7 +538,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val const CFileItem &item = _db.Files[index]; UInt32 index2 = index; - switch(propID) + switch (propID) { case kpidIsDir: PropVarEm_Set_Bool(value, item.IsDir); break; case kpidSize: @@ -608,7 +591,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val */ case kpidPath: return _db.GetPath_Prop(index, value); + #ifndef _SFX + case kpidMethod: return SetMethodToProp(_db.FileIndexToFolderIndexMap[index2], value); case kpidBlock: { @@ -617,30 +602,29 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val PropVarEm_Set_UInt32(value, (UInt32)folderIndex); } break; + /* case kpidPackedSize0: case kpidPackedSize1: case kpidPackedSize2: case kpidPackedSize3: case kpidPackedSize4: { - /* CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; if (folderIndex != kNumNoIndex) { - const CFolder &folderInfo = _db.Folders[folderIndex]; if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 && - folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0)) + _db.FoStartPackStreamIndex[folderIndex + 1] - + _db.FoStartPackStreamIndex[folderIndex] > (propID - kpidPackedSize0)) { - prop = _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0); + PropVarEm_Set_UInt64(value, _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0)); } - else - prop = (UInt64)0; } else - prop = (UInt64)0; - */ + PropVarEm_Set_UInt64(value, 0); } break; + */ + #endif } // prop.Detach(value); @@ -668,7 +652,13 @@ STDMETHODIMP CHandler::Open(IInStream *stream, openArchiveCallbackTemp.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); #endif - CInArchive archive; + CInArchive archive( + #ifdef __7Z_SET_PROPERTIES + _useMultiThreadMixer + #else + true + #endif + ); _db.IsArc = false; RINOK(archive.Open(stream, maxCheckStartPosition)); _db.IsArc = true; @@ -677,7 +667,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, EXTERNAL_CODECS_VARS _db #ifndef _NO_CRYPTO - , getTextPassword, _isEncrypted, _passwordIsDefined + , getTextPassword, _isEncrypted, _passwordIsDefined, _password #endif ); RINOK(result); @@ -688,8 +678,9 @@ STDMETHODIMP CHandler::Open(IInStream *stream, { Close(); // return E_INVALIDARG; + // return S_FALSE; // we must return out_of_memory here - return S_FALSE; + return E_OUTOFMEMORY; } // _inStream = stream; #ifndef _SFX @@ -707,6 +698,7 @@ STDMETHODIMP CHandler::Close() #ifndef _NO_CRYPTO _isEncrypted = false; _passwordIsDefined = false; + _password.Empty(); #endif return S_OK; COM_TRY_END @@ -715,11 +707,12 @@ STDMETHODIMP CHandler::Close() #ifdef __7Z_SET_PROPERTIES #ifdef EXTRACT_ONLY -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); _numThreads = numProcessors; + _useMultiThreadMixer = true; for (UInt32 i = 0; i < numProps; i++) { @@ -732,7 +725,8 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v int index = ParseStringToUInt32(name, number); if (index == 0) { - if (name.IsPrefixedBy(L"mt")) + if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer); + if (name.IsPrefixedBy_Ascii_NoCase("mt")) { RINOK(ParseMtProp(name.Ptr(2), value, numProcessors, _numThreads)); continue; diff --git a/CPP/7zip/Archive/7z/7zHandler.h b/CPP/7zip/Archive/7z/7zHandler.h index c33617c4..8a078e19 100644 --- a/CPP/7zip/Archive/7z/7zHandler.h +++ b/CPP/7zip/Archive/7z/7zHandler.h @@ -18,16 +18,6 @@ namespace NArchive { namespace N7z { -const UInt32 k_Copy = 0x0; -const UInt32 k_Delta = 3; -const UInt32 k_LZMA2 = 0x21; -const UInt32 k_LZMA = 0x030101; -const UInt32 k_PPMD = 0x030401; -const UInt32 k_BCJ = 0x03030103; -const UInt32 k_BCJ2 = 0x0303011B; -const UInt32 k_Deflate = 0x040108; -const UInt32 k_BZip2 = 0x040202; - #ifndef __7Z_SET_PROPERTIES #ifdef EXTRACT_ONLY @@ -64,7 +54,9 @@ public: CBoolPair Write_ATime; CBoolPair Write_MTime; - bool _volumeMode; + bool _useMultiThreadMixer; + + // bool _volumeMode; void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); } void InitSolidSize() { _numSolidBytes = (UInt64)(Int64)(-1); } @@ -117,7 +109,7 @@ public: INTERFACE_IArchiveGetRawProps(;) #ifdef __7Z_SET_PROPERTIES - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); #endif #ifndef EXTRACT_ONLY @@ -131,28 +123,29 @@ public: private: CMyComPtr<IInStream> _inStream; NArchive::N7z::CDbEx _db; + #ifndef _NO_CRYPTO bool _isEncrypted; bool _passwordIsDefined; + UString _password; #endif #ifdef EXTRACT_ONLY #ifdef __7Z_SET_PROPERTIES UInt32 _numThreads; + bool _useMultiThreadMixer; #endif UInt32 _crcSize; #else - CRecordVector<CBind> _binds; + CRecordVector<CBond2> _bonds; HRESULT PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m); HRESULT SetHeaderMethod(CCompressionMethodMode &headerMethod); - void AddDefaultMethod(); - HRESULT SetMainMethod(CCompressionMethodMode &method, - CObjectVector<COneMethodInfo> &methodsInfo + HRESULT SetMainMethod(CCompressionMethodMode &method #ifndef _7ZIP_ST , UInt32 numThreads #endif diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp index 5e113207..5cab6a82 100644 --- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp +++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp @@ -18,11 +18,11 @@ using namespace NWindows; namespace NArchive { namespace N7z { -static const wchar_t *k_LZMA_Name = L"LZMA"; -static const wchar_t *kDefaultMethodName = L"LZMA2"; -static const wchar_t *k_Copy_Name = L"Copy"; +static const char *k_LZMA_Name = "LZMA"; +static const char *kDefaultMethodName = "LZMA2"; +static const char *k_Copy_Name = "Copy"; -static const wchar_t *k_MatchFinder_ForHeaders = L"BT2"; +static const char *k_MatchFinder_ForHeaders = "BT2"; static const UInt32 k_NumFastBytes_ForHeaders = 273; static const UInt32 k_Level_ForHeaders = 5; static const UInt32 k_Dictionary_ForHeaders = @@ -42,7 +42,7 @@ HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodI { if (!FindMethod( EXTERNAL_CODECS_VARS - m.MethodName, dest.Id, dest.NumInStreams, dest.NumOutStreams)) + m.MethodName, dest.Id, dest.NumStreams)) return E_INVALIDARG; (CProps &)dest = (CProps &)m; return S_OK; @@ -54,48 +54,62 @@ HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod) return S_OK; COneMethodInfo m; m.MethodName = k_LZMA_Name; - m.AddPropString(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders); - m.AddProp32(NCoderPropID::kLevel, k_Level_ForHeaders); + m.AddProp_Ascii(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders); + m.AddProp_Level(k_Level_ForHeaders); m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders); m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders); - m.AddNumThreadsProp(1); + m.AddProp_NumThreads(1); - CMethodFull methodFull; - RINOK(PropsMethod_To_FullMethod(methodFull, m)); - headerMethod.Methods.Add(methodFull); - return S_OK; -} - -void CHandler::AddDefaultMethod() -{ - FOR_VECTOR (i, _methods) - { - UString &methodName = _methods[i].MethodName; - if (methodName.IsEmpty()) - methodName = kDefaultMethodName; - } - if (_methods.IsEmpty()) - { - COneMethodInfo m; - m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName); - _methods.Add(m); - } + CMethodFull &methodFull = headerMethod.Methods.AddNew(); + return PropsMethod_To_FullMethod(methodFull, m); } HRESULT CHandler::SetMainMethod( - CCompressionMethodMode &methodMode, - CObjectVector<COneMethodInfo> &methods + CCompressionMethodMode &methodMode #ifndef _7ZIP_ST , UInt32 numThreads #endif ) { - AddDefaultMethod(); + methodMode.Bonds = _bonds; + + CObjectVector<COneMethodInfo> methods = _methods; + + { + FOR_VECTOR (i, methods) + { + AString &methodName = methods[i].MethodName; + if (methodName.IsEmpty()) + methodName = kDefaultMethodName; + } + if (methods.IsEmpty()) + { + COneMethodInfo &m = methods.AddNew(); + m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName); + methodMode.DefaultMethod_was_Inserted = true; + } + } + + if (!_filterMethod.MethodName.IsEmpty()) + { + // if (methodMode.Bonds.IsEmpty()) + { + FOR_VECTOR (k, methodMode.Bonds) + { + CBond2 &bond = methodMode.Bonds[k]; + bond.InCoder++; + bond.OutCoder++; + } + methods.Insert(0, _filterMethod); + methodMode.Filter_was_Inserted = true; + } + } const UInt64 kSolidBytes_Min = (1 << 24); const UInt64 kSolidBytes_Max = ((UInt64)1 << 32) - 1; bool needSolid = false; + FOR_VECTOR (i, methods) { COneMethodInfo &oneMethodInfo = methods[i]; @@ -105,9 +119,8 @@ HRESULT CHandler::SetMainMethod( #endif ); - CMethodFull methodFull; + CMethodFull &methodFull = methodMode.Methods.AddNew(); RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo)); - methodMode.Methods.Add(methodFull); if (methodFull.Id != k_Copy) needSolid = true; @@ -125,6 +138,7 @@ HRESULT CHandler::SetMainMethod( case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break; default: continue; } + _numSolidBytes = (UInt64)dicSize << 7; if (_numSolidBytes < kSolidBytes_Min) _numSolidBytes = kSolidBytes_Min; if (_numSolidBytes > kSolidBytes_Max) _numSolidBytes = kSolidBytes_Max; @@ -517,18 +531,20 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt CCompressionMethodMode methodMode, headerMethod; - HRESULT res = SetMainMethod(methodMode, _methods + HRESULT res = SetMainMethod(methodMode #ifndef _7ZIP_ST , _numThreads #endif ); RINOK(res); - methodMode.Binds = _binds; RINOK(SetHeaderMethod(headerMethod)); + #ifndef _7ZIP_ST methodMode.NumThreads = _numThreads; + methodMode.MultiThreadMixer = _useMultiThreadMixer; headerMethod.NumThreads = 1; + headerMethod.MultiThreadMixer = _useMultiThreadMixer; #endif CMyComPtr<ICryptoGetTextPassword2> getPassword2; @@ -542,7 +558,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt Int32 passwordIsDefined; RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password)); methodMode.PasswordIsDefined = IntToBool(passwordIsDefined); - if (methodMode.PasswordIsDefined && (BSTR)password) + if (methodMode.PasswordIsDefined && password) methodMode.Password = password; } @@ -550,6 +566,15 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt bool encryptHeaders = false; + #ifndef _NO_CRYPTO + if (!methodMode.PasswordIsDefined && _passwordIsDefined) + { + // if header is compressed, we use that password for updated archive + methodMode.PasswordIsDefined = true; + methodMode.Password = _password; + } + #endif + if (methodMode.PasswordIsDefined) { if (_encryptHeadersSpecified) @@ -569,12 +594,14 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (numItems < 2) compressMainHeader = false; + int level = GetLevel(); + CUpdateOptions options; options.Method = &methodMode; - options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : 0; - int level = GetLevel(); - options.UseFilters = level != 0 && _autoFilter; - options.MaxFilter = level >= 8; + options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL; + options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted); + options.MaxFilter = (level >= 8); + options.AnalysisLevel = GetAnalysisLevel(); options.HeaderOptions.CompressMainHeader = compressMainHeader; /* @@ -587,7 +614,9 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt options.NumSolidBytes = _numSolidBytes; options.SolidExtension = _solidExtension; options.RemoveSfxBlock = _removeSfxBlock; - options.VolumeMode = _volumeMode; + // options.VolumeMode = _volumeMode; + + options.MultiThreadMixer = _useMultiThreadMixer; COutArchive archive; CArchiveDatabaseOut newDatabase; @@ -635,20 +664,20 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt COM_TRY_END } -static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream) +static HRESULT ParseBond(UString &srcString, UInt32 &coder, UInt32 &stream) { stream = 0; int index = ParseStringToUInt32(srcString, coder); if (index == 0) return E_INVALIDARG; - srcString.Delete(0, index); + srcString.DeleteFrontal(index); if (srcString[0] == 's') { srcString.Delete(0); int index = ParseStringToUInt32(srcString, stream); if (index == 0) return E_INVALIDARG; - srcString.Delete(0, index); + srcString.DeleteFrontal(index); } return S_OK; } @@ -667,7 +696,10 @@ void COutHandler::InitProps() Write_ATime.Init(); Write_MTime.Init(); - _volumeMode = false; + _useMultiThreadMixer = true; + + // _volumeMode = false; + InitSolid(); } @@ -762,7 +794,7 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val UInt32 number; int index = ParseStringToUInt32(name, number); - UString realName = name.Ptr(index); + // UString realName = name.Ptr(index); if (index == 0) { if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock); @@ -787,15 +819,17 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime); if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime); - if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode); + if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer); + + // 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, UInt32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN - _binds.Clear(); + _bonds.Clear(); InitProps(); for (UInt32 i = 0; i < numProps; i++) @@ -812,15 +846,19 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v if (value.vt != VT_EMPTY) return E_INVALIDARG; name.Delete(0); - CBind bind; - RINOK(GetBindInfoPart(name, bind.OutCoder, bind.OutStream)); + + CBond2 bond; + RINOK(ParseBond(name, bond.OutCoder, bond.OutStream)); if (name[0] != ':') return E_INVALIDARG; name.Delete(0); - RINOK(GetBindInfoPart(name, bind.InCoder, bind.InStream)); + UInt32 inStream = 0; + RINOK(ParseBond(name, bond.InCoder, inStream)); + if (inStream != 0) + return E_INVALIDARG; if (!name.IsEmpty()) return E_INVALIDARG; - _binds.Add(bind); + _bonds.Add(bond); continue; } @@ -831,40 +869,27 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v if (numEmptyMethods > 0) { unsigned k; - for (k = 0; k < _binds.Size(); k++) + for (k = 0; k < _bonds.Size(); k++) { - const CBind &bind = _binds[k]; - if (bind.InCoder < (UInt32)numEmptyMethods || - bind.OutCoder < (UInt32)numEmptyMethods) + const CBond2 &bond = _bonds[k]; + if (bond.InCoder < (UInt32)numEmptyMethods || + bond.OutCoder < (UInt32)numEmptyMethods) return E_INVALIDARG; } - for (k = 0; k < _binds.Size(); k++) + for (k = 0; k < _bonds.Size(); k++) { - CBind &bind = _binds[k]; - bind.InCoder -= (UInt32)numEmptyMethods; - bind.OutCoder -= (UInt32)numEmptyMethods; + CBond2 &bond = _bonds[k]; + bond.InCoder -= (UInt32)numEmptyMethods; + bond.OutCoder -= (UInt32)numEmptyMethods; } _methods.DeleteFrontal(numEmptyMethods); } - AddDefaultMethod(); - - if (!_filterMethod.MethodName.IsEmpty()) - { - FOR_VECTOR (k, _binds) - { - CBind &bind = _binds[k]; - bind.InCoder++; - bind.OutCoder++; - } - _methods.Insert(0, _filterMethod); - } - - FOR_VECTOR (k, _binds) + FOR_VECTOR (k, _bonds) { - const CBind &bind = _binds[k]; - if (bind.InCoder >= (UInt32)_methods.Size() || - bind.OutCoder >= (UInt32)_methods.Size()) + const CBond2 &bond = _bonds[k]; + if (bond.InCoder >= (UInt32)_methods.Size() || + bond.OutCoder >= (UInt32)_methods.Size()) return E_INVALIDARG; } diff --git a/CPP/7zip/Archive/7z/7zHeader.h b/CPP/7zip/Archive/7z/7zHeader.h index d72fdefa..d7f0ae36 100644 --- a/CPP/7zip/Archive/7z/7zHeader.h +++ b/CPP/7zip/Archive/7z/7zHeader.h @@ -96,6 +96,53 @@ namespace NID }; } + +const UInt32 k_Copy = 0; +const UInt32 k_Delta = 3; + +const UInt32 k_LZMA2 = 0x21; + +const UInt32 k_SWAP2 = 0x20302; +const UInt32 k_SWAP4 = 0x20304; + +const UInt32 k_LZMA = 0x30101; +const UInt32 k_PPMD = 0x30401; + +const UInt32 k_Deflate = 0x40108; +const UInt32 k_BZip2 = 0x40202; + +const UInt32 k_BCJ = 0x3030103; +const UInt32 k_BCJ2 = 0x303011B; +const UInt32 k_PPC = 0x3030205; +const UInt32 k_IA64 = 0x3030401; +const UInt32 k_ARM = 0x3030501; +const UInt32 k_ARMT = 0x3030701; +const UInt32 k_SPARC = 0x3030805; + +const UInt32 k_AES = 0x6F10701; + + +static inline bool IsFilterMethod(UInt64 m) +{ + if (m > (UInt64)0xFFFFFFFF) + return false; + switch ((UInt32)m) + { + case k_Delta: + case k_BCJ: + case k_BCJ2: + case k_PPC: + case k_IA64: + case k_ARM: + case k_ARMT: + case k_SPARC: + case k_SWAP2: + case k_SWAP4: + return true; + } + return false; +} + }} #endif diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp index 4f04aa83..bd6c4d95 100644 --- a/CPP/7zip/Archive/7z/7zIn.cpp +++ b/CPP/7zip/Archive/7z/7zIn.cpp @@ -32,9 +32,6 @@ using namespace NCOM; namespace NArchive { namespace N7z { -static const UInt32 k_LZMA2 = 0x21; -static const UInt32 k_LZMA = 0x030101; - static void BoolVector_Fill_False(CBoolVector &v, unsigned size) { v.ClearAndSetSize(size); @@ -43,78 +40,6 @@ static void BoolVector_Fill_False(CBoolVector &v, unsigned size) p[i] = false; } -static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index) -{ - if (index >= (UInt32)v.Size()) - return true; - bool res = v[index]; - v[index] = true; - return res; -} - -bool CFolder::CheckStructure(unsigned numUnpackSizes) const -{ - 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; - - { - CBoolVector v; - BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size()); - - unsigned i; - for (i = 0; i < BindPairs.Size(); i++) - if (BoolVector_GetAndSet(v, BindPairs[i].InIndex)) - return false; - for (i = 0; i < PackStreams.Size(); i++) - if (BoolVector_GetAndSet(v, PackStreams[i])) - return false; - - BoolVector_Fill_False(v, numUnpackSizes); - for (i = 0; i < BindPairs.Size(); i++) - if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex)) - return false; - } - - UInt32 mask[kMaskSize]; - unsigned i; - for (i = 0; i < kMaskSize; i++) - mask[i] = 0; - - { - CUIntVector inStreamToCoder, outStreamToCoder; - for (i = 0; i < Coders.Size(); i++) - { - CNum j; - const CCoderInfo &coder = Coders[i]; - for (j = 0; j < coder.NumInStreams; j++) - inStreamToCoder.Add(i); - for (j = 0; j < coder.NumOutStreams; j++) - outStreamToCoder.Add(i); - } - - for (i = 0; i < BindPairs.Size(); i++) - { - const CBindPair &bp = BindPairs[i]; - mask[inStreamToCoder[bp.InIndex]] |= (1 << outStreamToCoder[bp.OutIndex]); - } - } - - for (i = 0; i < kMaskSize; i++) - for (unsigned j = 0; j < kMaskSize; j++) - if (((1 << j) & mask[i]) != 0) - mask[i] |= mask[j]; - - for (i = 0; i < kMaskSize; i++) - if (((1 << i) & mask[i]) != 0) - return false; - - return true; -} - class CInArchiveException {}; class CUnsupportedFeatureException: public CInArchiveException {}; @@ -193,6 +118,8 @@ Byte CInByte2::ReadByte() void CInByte2::ReadBytes(Byte *data, size_t size) { + if (size == 0) + return; if (size > _size - _pos) ThrowEndOfData(); memcpy(data, _buffer + _pos, size); @@ -218,41 +145,48 @@ static UInt64 ReadNumberSpec(const Byte *p, size_t size, size_t &processed) processed = 0; return 0; } - Byte firstByte = *p++; + + unsigned b = *p++; size--; - if ((firstByte & 0x80) == 0) + + if ((b & 0x80) == 0) { processed = 1; - return firstByte; + return b; } - 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) + unsigned mask = (unsigned)0x80 >> i; + if ((b & mask) == 0) { - UInt64 highPart = firstByte & (mask - 1); - value += (highPart << (i * 8)); + UInt64 high = b & (mask - 1); + value |= (high << (i * 8)); processed = i + 1; return value; } + if (size == 0) { processed = 0; return 0; } + value |= ((UInt64)*p << (i * 8)); p++; size--; - mask >>= 1; } + processed = 9; return value; } @@ -344,6 +278,7 @@ HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *search for (;;) { UInt32 readSize = kBufSize - kHeaderSize; + if (searchHeaderSizeLimit) { UInt64 rem = *searchHeaderSizeLimit - offset; if (readSize > rem) @@ -351,10 +286,12 @@ HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *search 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 = 0;;) { const Byte *p = buf + pos + 1; @@ -376,6 +313,7 @@ HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *search return stream->Seek(_arhiveBeginStreamPosition + kHeaderSize, STREAM_SEEK_SET, NULL); } } + offset += processed; memmove(buf, buf + processed, kHeaderSize); } @@ -415,13 +353,15 @@ void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */) void CInByte2::ParseFolder(CFolder &folder) { - CNum numCoders = ReadNum(); + UInt32 numCoders = ReadNum(); + + if (numCoders == 0) + ThrowUnsupported(); folder.Coders.SetSize(numCoders); - CNum numInStreams = 0; - CNum numOutStreams = 0; - CNum i; + UInt32 numInStreams = 0; + UInt32 i; for (i = 0; i < numCoders; i++) { CCoderInfo &coder = folder.Coders[i]; @@ -441,14 +381,14 @@ void CInByte2::ParseFolder(CFolder &folder) if ((mainByte & 0x10) != 0) { - coder.NumInStreams = ReadNum(); - coder.NumOutStreams = ReadNum(); + coder.NumStreams = ReadNum(); + /* numOutStreams = */ ReadNum(); } else { - coder.NumInStreams = 1; - coder.NumOutStreams = 1; + coder.NumStreams = 1; } + if ((mainByte & 0x20) != 0) { CNum propsSize = ReadNum(); @@ -458,27 +398,27 @@ void CInByte2::ParseFolder(CFolder &folder) else coder.Props.Free(); } - numInStreams += coder.NumInStreams; - numOutStreams += coder.NumOutStreams; + numInStreams += coder.NumStreams; } - CNum numBindPairs = numOutStreams - 1; - folder.BindPairs.SetSize(numBindPairs); - for (i = 0; i < numBindPairs; i++) + UInt32 numBonds = numCoders - 1; + folder.Bonds.SetSize(numBonds); + for (i = 0; i < numBonds; i++) { - CBindPair &bp = folder.BindPairs[i]; - bp.InIndex = ReadNum(); - bp.OutIndex = ReadNum(); + CBond &bp = folder.Bonds[i]; + bp.PackIndex = ReadNum(); + bp.UnpackIndex = ReadNum(); } - if (numInStreams < numBindPairs) + if (numInStreams < numBonds) ThrowUnsupported(); - CNum numPackStreams = numInStreams - numBindPairs; + UInt32 numPackStreams = numInStreams - numBonds; folder.PackStreams.SetSize(numPackStreams); + if (numPackStreams == 1) { for (i = 0; i < numInStreams; i++) - if (folder.FindBindPairForInStream(i) < 0) + if (folder.FindBond_for_PackStream(i) < 0) { folder.PackStreams[0] = i; break; @@ -509,12 +449,12 @@ void CDatabase::GetPath(unsigned index, UString &path) const return; size_t offset = NameOffsets[index]; - size_t size = NameOffsets[index + 1] - offset - 1; + size_t size = NameOffsets[index + 1] - offset; - if (size >= (1 << 20)) + if (size >= (1 << 28)) return; - wchar_t *s = path.GetBuffer((unsigned)size); + wchar_t *s = path.GetBuf((unsigned)size - 1); const Byte *p = ((const Byte *)NamesBuf + offset * 2); @@ -533,7 +473,7 @@ void CDatabase::GetPath(unsigned index, UString &path) const #endif - path.ReleaseBuffer((unsigned)size); + path.ReleaseBuf_SetLen((unsigned)size - 1); } HRESULT CDatabase::GetPath_Prop(unsigned index, PROPVARIANT *path) const throw() @@ -592,7 +532,7 @@ HRESULT CDatabase::GetPath_Prop(unsigned index, PROPVARIANT *path) const throw() { unsigned len = (unsigned)(NameOffsets[cur + 1] - NameOffsets[cur] - 1); const Byte *p = (const Byte *)NamesBuf + (NameOffsets[cur + 1] * 2) - 2; - do + for (; len != 0; len--) { p -= 2; --s; @@ -601,7 +541,7 @@ HRESULT CDatabase::GetPath_Prop(unsigned index, PROPVARIANT *path) const throw() c = WCHAR_PATH_SEPARATOR; *s = c; } - while (--len); + const CFileItem &file = Files[cur]; cur = file.Parent; if (cur < 0) @@ -639,6 +579,9 @@ void CInArchive::ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs) } } +#define k_Scan_NumCoders_MAX 64 +#define k_Scan_NumCodersStreams_in_Folder_MAX 64 + void CInArchive::ReadPackInfo(CFolders &f) { CNum numPackStreams = ReadNum(); @@ -692,27 +635,31 @@ void CInArchive::ReadUnpackInfo( folders.FoCodersDataOffset.Alloc(numFolders + 1); folders.FoToCoderUnpackSizes.Alloc(numFolders + 1); - CRecordVector<bool> InStreamUsed; - CRecordVector<bool> OutStreamUsed; + CBoolVector StreamUsed; + CBoolVector CoderUsed; CNum packStreamIndex = 0; CNum fo; CInByte2 *inByte = _inByteBack; + for (fo = 0; fo < numFolders; fo++) { - UInt32 numOutStreams = 0; UInt32 indexOfMainStream = 0; UInt32 numPackStreams = 0; folders.FoCodersDataOffset[fo] = _inByteBack->GetPtr() - startBufPtr; - numOutStreams = 0; CNum numInStreams = 0; CNum numCoders = inByte->ReadNum(); + + if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) + ThrowUnsupported(); + for (CNum ci = 0; ci < numCoders; ci++) { Byte mainByte = inByte->ReadByte(); if ((mainByte & 0xC0) != 0) ThrowUnsupported(); + unsigned idSize = (mainByte & 0xF); if (idSize > 8) ThrowUnsupported(); @@ -725,19 +672,21 @@ void CInArchive::ReadUnpackInfo( 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(); + if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) + ThrowUnsupported(); + if (inByte->ReadNum() != 1) + ThrowUnsupported(); } + numInStreams += coderInStreams; - if (numInStreams < coderInStreams) - ThrowUnsupported(); - numOutStreams += coderOutStreams; - if (numOutStreams < coderOutStreams) + if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) ThrowUnsupported(); + if ((mainByte & 0x20) != 0) { CNum propsSize = inByte->ReadNum(); @@ -759,7 +708,7 @@ void CInArchive::ReadUnpackInfo( } } - if (numOutStreams == 1 && numInStreams == 1) + if (numCoders == 1 && numInStreams == 1) { indexOfMainStream = 0; numPackStreams = 1; @@ -767,55 +716,55 @@ void CInArchive::ReadUnpackInfo( else { UInt32 i; - if (numOutStreams == 0) - ThrowUnsupported(); - CNum numBindPairs = numOutStreams - 1; - if (numInStreams < numBindPairs) - ThrowUnsupported(); - if (numInStreams >= 256 || numOutStreams >= 256) + CNum numBonds = numCoders - 1; + if (numInStreams < numBonds) ThrowUnsupported(); - InStreamUsed.ClearAndSetSize(numInStreams); - for (i = 0; i < numInStreams; i++) - InStreamUsed[i] = false; + BoolVector_Fill_False(StreamUsed, numInStreams); + BoolVector_Fill_False(CoderUsed, numCoders); - OutStreamUsed.ClearAndSetSize(numOutStreams); - for (i = 0; i < numOutStreams; i++) - OutStreamUsed[i] = false; - - for (i = 0; i < numBindPairs; i++) + for (i = 0; i < numBonds; i++) { CNum index = ReadNum(); - if (index >= numInStreams || InStreamUsed[index]) + if (index >= numInStreams || StreamUsed[index]) ThrowUnsupported(); - InStreamUsed[index] = true; + StreamUsed[index] = true; + index = ReadNum(); - if (index >= numOutStreams || OutStreamUsed[index]) + if (index >= numCoders || CoderUsed[index]) ThrowUnsupported(); - OutStreamUsed[index] = true; + CoderUsed[index] = true; } - numPackStreams = numInStreams - numBindPairs; + numPackStreams = numInStreams - numBonds; if (numPackStreams != 1) for (i = 0; i < numPackStreams; i++) - inByte->ReadNum(); // PackStreams + { + CNum index = inByte->ReadNum(); // PackStreams + if (index >= numInStreams || StreamUsed[index]) + ThrowUnsupported(); + StreamUsed[index] = true; + } - for (i = 0; i < numOutStreams; i++) - if (!OutStreamUsed[i]) + for (i = 0; i < numCoders; i++) + if (!CoderUsed[i]) { indexOfMainStream = i; break; } - if (i == numOutStreams) + + if (i == numCoders) ThrowUnsupported(); } + folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams; - numCodersOutStreams += numOutStreams; + numCodersOutStreams += numCoders; 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; @@ -1105,13 +1054,7 @@ HRESULT CInArchive::ReadAndDecodePackedStreams( unpackSizes, digests); - CDecoder decoder( - #ifdef _ST_MODE - false - #else - true - #endif - ); + CDecoder decoder(_useMixerMT); for (CNum i = 0; i < folders.NumFolders; i++) { @@ -1127,14 +1070,20 @@ HRESULT CInArchive::ReadAndDecodePackedStreams( outStreamSpec->Init(data, unpackSize); HRESULT result = decoder.Decode( - EXTERNAL_CODECS_LOC_VARS - _stream, baseOffset + dataOffset, - folders, i, - outStream, NULL - _7Z_DECODER_CRYPRO_VARS - #if !defined(_7ZIP_ST) && !defined(_SFX) - , false, 1 - #endif + EXTERNAL_CODECS_LOC_VARS + _stream, baseOffset + dataOffset, + folders, i, + NULL, // *unpackSize + + outStream, + NULL, // *compressProgress + NULL // **inStreamMainRes + + _7Z_DECODER_CRYPRO_VARS + #if !defined(_7ZIP_ST) && !defined(_SFX) + , false // mtMode + , 1 // numThreads + #endif ); RINOK(result); @@ -1208,7 +1157,7 @@ HRESULT CInArchive::ReadHeader( db.ArcInfo.FileInfoPopIDs.Add(NID::kSize); // if (!db.PackSizes.IsEmpty()) db.ArcInfo.FileInfoPopIDs.Add(NID::kPackInfo); - if (numFiles > 0 && !digests.Defs.IsEmpty()) + if (numFiles > 0 && !digests.Defs.IsEmpty()) db.ArcInfo.FileInfoPopIDs.Add(NID::kCRC); CBoolVector emptyStreamVector; @@ -1396,6 +1345,9 @@ HRESULT CInArchive::ReadHeader( type = ReadID(); // Read (NID::kEnd) end of headers + if (numFiles - numEmptyStreams != unpackSizes.Size()) + ThrowUnsupported(); + CNum emptyFileIndex = 0; CNum sizeIndex = 0; @@ -1403,7 +1355,7 @@ HRESULT CInArchive::ReadHeader( for (i = 0; i < numEmptyStreams; i++) if (antiFileVector[i]) numAntiItems++; - + for (i = 0; i < numFiles; i++) { CFileItem &file = db.Files[i]; @@ -1444,13 +1396,13 @@ HRESULT CInArchive::ReadHeader( void CDbEx::FillLinks() { - FolderStartFileIndex.ClearAndSetSize(NumFolders); - - FileIndexToFolderIndexMap.ClearAndSetSize(Files.Size()); + FolderStartFileIndex.Alloc(NumFolders); + FileIndexToFolderIndexMap.Alloc(Files.Size()); CNum folderIndex = 0; CNum indexInFolder = 0; unsigned i; + for (i = 0; i < Files.Size(); i++) { bool emptyStream = !Files[i].HasStream; @@ -1489,6 +1441,7 @@ void CDbEx::FillLinks() if (indexInFolder != 0) ThrowIncorrect(); */ + for (;;) { if (folderIndex >= NumFolders) diff --git a/CPP/7zip/Archive/7z/7zIn.h b/CPP/7zip/Archive/7z/7zIn.h index 373000f7..ad8ceba5 100644 --- a/CPP/7zip/Archive/7z/7zIn.h +++ b/CPP/7zip/Archive/7z/7zIn.h @@ -26,8 +26,8 @@ namespace N7z { #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 +#define _7Z_DECODER_CRYPRO_VARS_DECL , ICryptoGetTextPassword *getTextPassword, bool &isEncrypted, bool &passwordIsDefined, UString &password +#define _7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined, password #endif struct CParsedMethods @@ -39,6 +39,11 @@ struct CParsedMethods CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {} }; +struct CFolderEx: public CFolder +{ + unsigned UnpackCoder; +}; + struct CFolders { CNum NumPackStreams; @@ -47,10 +52,10 @@ struct CFolders CObjArray<UInt64> PackPositions; // NumPackStreams + 1 // CUInt32DefVector PackCRCs; // we don't use PackCRCs now - CUInt32DefVector FolderCRCs; // NumFolders + CUInt32DefVector FolderCRCs; // NumFolders CObjArray<CNum> NumUnpackStreamsVector; // NumFolders - CObjArray<UInt64> CoderUnpackSizes; // including unpack sizes of bind coders + CObjArray<UInt64> CoderUnpackSizes; // including unpack sizes of bond coders CObjArray<CNum> FoToCoderUnpackSizes; // NumFolders + 1 CObjArray<CNum> FoStartPackStreamIndex; // NumFolders + 1 CObjArray<Byte> FoToMainUnpackSizeIndex; // NumFolders @@ -61,10 +66,15 @@ struct CFolders CParsedMethods ParsedMethods; void ParseFolderInfo(unsigned folderIndex, CFolder &folder) const; + void ParseFolderEx(unsigned folderIndex, CFolderEx &folder) const + { + ParseFolderInfo(folderIndex, folder); + folder.UnpackCoder = FoToMainUnpackSizeIndex[folderIndex]; + } unsigned GetNumFolderUnpackSizes(unsigned folderIndex) const { - return FoToCoderUnpackSizes[folderIndex + 1] - FoToCoderUnpackSizes[folderIndex]; + return (unsigned)(FoToCoderUnpackSizes[folderIndex + 1] - FoToCoderUnpackSizes[folderIndex]); } UInt64 GetFolderUnpackSize(unsigned folderIndex) const @@ -103,9 +113,9 @@ struct CDatabase: public CFolders CUInt64DefVector ATime; CUInt64DefVector MTime; CUInt64DefVector StartPos; - CRecordVector<bool> IsAnti; + CBoolVector IsAnti; /* - CRecordVector<bool> IsAux; + CBoolVector IsAux; CByteBuffer SecureBuf; CRecordVector<UInt32> SecureIDs; */ @@ -148,13 +158,14 @@ struct CDatabase: public CFolders bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); } // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); } - const void * GetName(unsigned index) const + /* + const void* GetName(unsigned index) const { if (!NameOffsets || !NamesBuf) return NULL; - return (const void *)((const Byte *)NamesBuf + NameOffsets[index] * 2); + return (void *)((const Byte *)NamesBuf + NameOffsets[index] * 2); }; - + */ void GetPath(unsigned index, UString &path) const; HRESULT GetPath_Prop(unsigned index, PROPVARIANT *path) const throw(); }; @@ -181,8 +192,9 @@ struct CInArchiveInfo struct CDbEx: public CDatabase { CInArchiveInfo ArcInfo; - CRecordVector<CNum> FolderStartFileIndex; - CRecordVector<CNum> FileIndexToFolderIndexMap; + + CObjArray<CNum> FolderStartFileIndex; + CObjArray<CNum> FileIndexToFolderIndexMap; UInt64 HeadersSize; UInt64 PhySize; @@ -234,8 +246,8 @@ struct CDbEx: public CDatabase // SecureOffsets.Clear(); ArcInfo.Clear(); - FolderStartFileIndex.Clear(); - FileIndexToFolderIndexMap.Clear(); + FolderStartFileIndex.Free(); + FileIndexToFolderIndexMap.Free(); HeadersSize = 0; PhySize = 0; @@ -243,22 +255,22 @@ struct CDbEx: public CDatabase void FillLinks(); - UInt64 GetFolderStreamPos(unsigned folderIndex, unsigned indexInFolder) const + UInt64 GetFolderStreamPos(CNum folderIndex, unsigned indexInFolder) const { return ArcInfo.DataStartPosition + PackPositions[FoStartPackStreamIndex[folderIndex] + indexInFolder]; } - UInt64 GetFolderFullPackSize(unsigned folderIndex) const + UInt64 GetFolderFullPackSize(CNum folderIndex) const { return PackPositions[FoStartPackStreamIndex[folderIndex + 1]] - PackPositions[FoStartPackStreamIndex[folderIndex]]; } - UInt64 GetFolderPackStreamSize(unsigned folderIndex, unsigned streamIndex) const + UInt64 GetFolderPackStreamSize(CNum folderIndex, unsigned streamIndex) const { - unsigned i = FoStartPackStreamIndex[folderIndex] + streamIndex; + size_t i = FoStartPackStreamIndex[folderIndex] + streamIndex; return PackPositions[i + 1] - PackPositions[i]; } @@ -327,6 +339,8 @@ class CInArchive UInt64 HeadersSize; + bool _useMixerMT; + void AddByteStream(const Byte *buffer, size_t size); void DeleteByteStream(bool needUpdatePos) @@ -340,7 +354,6 @@ class CInArchive } } -private: HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit); void ReadBytes(Byte *data, size_t size) { _inByteBack->ReadBytes(data, size); } @@ -396,7 +409,11 @@ private: _7Z_DECODER_CRYPRO_VARS_DECL ); public: - CInArchive(): _numInByteBufs(0) { } + CInArchive(bool useMixerMT): + _numInByteBufs(0), + _useMixerMT(useMixerMT) + {} + HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive void Close(); diff --git a/CPP/7zip/Archive/7z/7zItem.h b/CPP/7zip/Archive/7z/7zItem.h index 02a86196..5e2b58f2 100644 --- a/CPP/7zip/Archive/7z/7zItem.h +++ b/CPP/7zip/Archive/7z/7zItem.h @@ -13,8 +13,6 @@ namespace NArchive { namespace N7z { -const UInt64 k_AES = 0x06F10701; - typedef UInt32 CNum; const CNum kNumMax = 0x7FFFFFFF; const CNum kNumNoIndex = 0xFFFFFFFF; @@ -23,71 +21,70 @@ struct CCoderInfo { CMethodId MethodID; CByteBuffer Props; - CNum NumInStreams; - CNum NumOutStreams; + UInt32 NumStreams; - bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); } + bool IsSimpleCoder() const { return NumStreams == 1; } }; -struct CBindPair +struct CBond { - CNum InIndex; - CNum OutIndex; + UInt32 PackIndex; + UInt32 UnpackIndex; }; struct CFolder { + CLASS_NO_COPY(CFolder) +public: CObjArray2<CCoderInfo> Coders; - CObjArray2<CBindPair> BindPairs; - CObjArray2<CNum> PackStreams; + CObjArray2<CBond> Bonds; + CObjArray2<UInt32> PackStreams; - CNum GetNumOutStreams() const - { - CNum result = 0; - FOR_VECTOR(i, Coders) - result += Coders[i].NumOutStreams; - return result; - } + CFolder() {} - int FindBindPairForInStream(CNum inStreamIndex) const + bool IsDecodingSupported() const { return Coders.Size() <= 32; } + + int Find_in_PackStreams(UInt32 packStream) const { - FOR_VECTOR(i, BindPairs) - if (BindPairs[i].InIndex == inStreamIndex) + FOR_VECTOR(i, PackStreams) + if (PackStreams[i] == packStream) return i; return -1; } - int FindBindPairForOutStream(CNum outStreamIndex) const + + int FindBond_for_PackStream(UInt32 packStream) const { - FOR_VECTOR(i, BindPairs) - if (BindPairs[i].OutIndex == outStreamIndex) + FOR_VECTOR(i, Bonds) + if (Bonds[i].PackIndex == packStream) return i; return -1; } - int FindPackStreamArrayIndex(CNum inStreamIndex) const + + /* + int FindBond_for_UnpackStream(UInt32 unpackStream) const { - FOR_VECTOR(i, PackStreams) - if (PackStreams[i] == inStreamIndex) + FOR_VECTOR(i, Bonds) + if (Bonds[i].UnpackIndex == unpackStream) return i; return -1; } - int GetIndexOfMainOutStream() const + int FindOutCoder() const { - for (int i = (int)GetNumOutStreams() - 1; i >= 0; i--) - if (FindBindPairForOutStream(i) < 0) + for (int i = (int)Coders.Size() - 1; i >= 0; i--) + if (FindBond_for_UnpackStream(i) < 0) return i; - throw 1; + return -1; } + */ bool IsEncrypted() const { - for (int i = Coders.Size() - 1; i >= 0; i--) + FOR_VECTOR(i, Coders) if (Coders[i].MethodID == k_AES) return true; return false; } - - bool CheckStructure(unsigned numUnpackSizes) const; }; struct CUInt32DefVector diff --git a/CPP/7zip/Archive/7z/7zOut.cpp b/CPP/7zip/Archive/7z/7zOut.cpp index 9ff97595..2f906588 100644 --- a/CPP/7zip/Archive/7z/7zOut.cpp +++ b/CPP/7zip/Archive/7z/7zOut.cpp @@ -199,7 +199,7 @@ void COutArchive::WriteNumber(UInt64 value) mask >>= 1; } WriteByte(firstByte); - for (;i > 0; i--) + for (; i > 0; i--) { WriteByte((Byte)value); value >>= 8; @@ -254,31 +254,33 @@ void COutArchive::WriteFolder(const CFolder &folder) { WriteNumber(folder.Coders.Size()); unsigned i; + for (i = 0; i < folder.Coders.Size(); i++) { const CCoderInfo &coder = folder.Coders[i]; { - size_t propsSize = coder.Props.Size(); - UInt64 id = coder.MethodID; - int idSize; + unsigned idSize; for (idSize = 1; idSize < sizeof(id); idSize++) if ((id >> (8 * idSize)) == 0) break; - Byte longID[15]; - for (int t = idSize - 1; t >= 0 ; t--, id >>= 8) - longID[t] = (Byte)(id & 0xFF); - Byte b; - b = (Byte)(idSize & 0xF); + idSize &= 0xF; + Byte temp[16]; + for (unsigned t = idSize; t != 0; t--, id >>= 8) + temp[t] = (Byte)(id & 0xFF); + + Byte b = (Byte)(idSize); bool isComplex = !coder.IsSimpleCoder(); b |= (isComplex ? 0x10 : 0); - b |= ((propsSize != 0) ? 0x20 : 0 ); - WriteByte(b); - WriteBytes(longID, idSize); + + size_t propsSize = coder.Props.Size(); + b |= ((propsSize != 0) ? 0x20 : 0); + temp[0] = b; + WriteBytes(temp, idSize + 1); if (isComplex) { - WriteNumber(coder.NumInStreams); - WriteNumber(coder.NumOutStreams); + WriteNumber(coder.NumStreams); + WriteNumber(1); // NumOutStreams; } if (propsSize == 0) continue; @@ -286,17 +288,17 @@ void COutArchive::WriteFolder(const CFolder &folder) WriteBytes(coder.Props, propsSize); } } - for (i = 0; i < folder.BindPairs.Size(); i++) + + for (i = 0; i < folder.Bonds.Size(); i++) { - const CBindPair &bindPair = folder.BindPairs[i]; - WriteNumber(bindPair.InIndex); - WriteNumber(bindPair.OutIndex); + const CBond &bond = folder.Bonds[i]; + WriteNumber(bond.PackIndex); + WriteNumber(bond.UnpackIndex); } + if (folder.PackStreams.Size() > 1) for (i = 0; i < folder.PackStreams.Size(); i++) - { WriteNumber(folder.PackStreams[i]); - } } void COutArchive::WriteBoolVector(const CBoolVector &boolVector) @@ -521,7 +523,10 @@ HRESULT COutArchive::EncodeStream( UInt64 unpackSize; RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS - stream, NULL, &dataSize64, folders.AddNew(), outFolders.CoderUnpackSizes, unpackSize, SeqStream, packSizes, NULL)) + stream, + // NULL, + &dataSize64, + folders.AddNew(), outFolders.CoderUnpackSizes, unpackSize, SeqStream, packSizes, NULL)) return S_OK; } diff --git a/CPP/7zip/Archive/7z/7zOut.h b/CPP/7zip/Archive/7z/7zOut.h index cead4bce..6c902668 100644 --- a/CPP/7zip/Archive/7z/7zOut.h +++ b/CPP/7zip/Archive/7z/7zOut.h @@ -29,6 +29,8 @@ public: } void WriteBytes(const void *data, size_t size) { + if (size == 0) + return; if (size > _size - _pos) throw 1; memcpy(_data + _pos, data, size); @@ -92,7 +94,7 @@ struct COutFolders CUInt32DefVector FolderUnpackCRCs; // Now we use it for headers only. CRecordVector<CNum> NumUnpackStreamsVector; - CRecordVector<UInt64> CoderUnpackSizes; // including unpack sizes of bind coders + CRecordVector<UInt64> CoderUnpackSizes; // including unpack sizes of bond coders void OutFoldersClear() { diff --git a/CPP/7zip/Archive/7z/7zProperties.cpp b/CPP/7zip/Archive/7z/7zProperties.cpp index 5ed36947..a2c9bf31 100644 --- a/CPP/7zip/Archive/7z/7zProperties.cpp +++ b/CPP/7zip/Archive/7z/7zProperties.cpp @@ -13,7 +13,7 @@ namespace N7z { struct CPropMap { - UInt64 FilePropID; + UInt32 FilePropID; STATPROPSTG StatPROPSTG; }; @@ -35,7 +35,7 @@ static const CPropMap kPropMap[] = { NID::kMTime, { NULL, kpidMTime, VT_FILETIME } }, { NID::kATime, { NULL, kpidATime, VT_FILETIME } }, { NID::kWinAttrib, { NULL, kpidAttrib, VT_UI4 } }, - { NID::kStartPos, { NULL, kpidPosition, VT_UI4 } }, + { NID::kStartPos, { NULL, kpidPosition, VT_UI8 } }, { NID::kCRC, { NULL, kpidCRC, VT_UI4 } }, @@ -44,20 +44,12 @@ static const CPropMap kPropMap[] = #ifndef _SFX , - { 97, { NULL,kpidEncrypted, VT_BOOL } }, - { 98, { NULL,kpidMethod, VT_BSTR } }, - { 99, { NULL,kpidBlock, VT_UI4 } } + { 97, { NULL, kpidEncrypted, VT_BOOL } }, + { 98, { NULL, kpidMethod, VT_BSTR } }, + { 99, { NULL, kpidBlock, VT_UI4 } } #endif }; -static int FindPropInMap(UInt64 filePropID) -{ - for (int i = 0; i < ARRAY_SIZE(kPropMap); i++) - if (kPropMap[i].FilePropID == filePropID) - return i; - return -1; -} - static void CopyOneItem(CRecordVector<UInt64> &src, CRecordVector<UInt64> &dest, UInt32 item) { @@ -131,6 +123,7 @@ void CHandler::FillPopIDs() _fileInfoPopIDs.Add(98); _fileInfoPopIDs.Add(99); #endif + #ifdef _MULTI_PACK _fileInfoPopIDs.Add(100); _fileInfoPopIDs.Add(101); @@ -155,16 +148,27 @@ STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) { - if ((int)index >= _fileInfoPopIDs.Size()) + if (index >= _fileInfoPopIDs.Size()) return E_INVALIDARG; - int indexInMap = FindPropInMap(_fileInfoPopIDs[index]); - if (indexInMap == -1) - return E_INVALIDARG; - const STATPROPSTG &srcItem = kPropMap[indexInMap].StatPROPSTG; - *propID = srcItem.propid; - *varType = srcItem.vt; - *name = 0; - return S_OK; + UInt64 id = _fileInfoPopIDs[index]; + for (unsigned i = 0; i < ARRAY_SIZE(kPropMap); i++) + { + const CPropMap &pr = kPropMap[i]; + if (pr.FilePropID == id) + { + const STATPROPSTG &st = pr.StatPROPSTG; + *propID = st.propid; + *varType = st.vt; + /* + if (st.lpwstrName) + *name = ::SysAllocString(st.lpwstrName); + else + */ + *name = NULL; + return S_OK; + } + } + return E_INVALIDARG; } }} diff --git a/CPP/7zip/Archive/7z/7zRegister.cpp b/CPP/7zip/Archive/7z/7zRegister.cpp index 37ea29d3..389b5407 100644 --- a/CPP/7zip/Archive/7z/7zRegister.cpp +++ b/CPP/7zip/Archive/7z/7zRegister.cpp @@ -9,17 +9,13 @@ namespace NArchive { namespace N7z { -IMP_CreateArcIn -IMP_CreateArcOut +static Byte k_Signature_Dec[kSignatureSize] = {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C}; -static CArcInfo g_ArcInfo = - { "7z", "7z", 0, 7, - 6, {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C}, +REGISTER_ARC_IO_DECREMENT_SIG( + "7z", "7z", NULL, 7, + k_Signature_Dec, 0, NArcInfoFlags::kFindSignature, - REF_CreateArc_Pair }; - -REGISTER_ARC_DEC_SIG(7z) -// REGISTER_ARC(7z) + NULL); }} diff --git a/CPP/7zip/Archive/7z/7zSpecStream.h b/CPP/7zip/Archive/7z/7zSpecStream.h index 2e26efd5..21155069 100644 --- a/CPP/7zip/Archive/7z/7zSpecStream.h +++ b/CPP/7zip/Archive/7z/7zSpecStream.h @@ -3,10 +3,10 @@ #ifndef __7Z_SPEC_STREAM_H #define __7Z_SPEC_STREAM_H -#include "../../IStream.h" -#include "../../ICoder.h" #include "../../../Common/MyCom.h" +#include "../../ICoder.h" + class CSequentialInStreamSizeCount2: public ISequentialInStream, public ICompressGetSubStreamSize, @@ -18,14 +18,14 @@ class CSequentialInStreamSizeCount2: public: void Init(ISequentialInStream *stream) { + _size = 0; + _getSubStreamSize.Release(); _stream = stream; - _getSubStreamSize = 0; _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize); - _size = 0; } UInt64 GetSize() const { return _size; } - MY_UNKNOWN_IMP1(ICompressGetSubStreamSize) + MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp index 7875ed5b..e7c9ecc6 100644 --- a/CPP/7zip/Archive/7z/7zUpdate.cpp +++ b/CPP/7zip/Archive/7z/7zUpdate.cpp @@ -13,7 +13,6 @@ #include "../../Compress/CopyCoder.h" #include "../Common/ItemNameUtils.h" -#include "../Common/OutStreamWithCRC.h" #include "7zDecode.h" #include "7zEncode.h" @@ -25,9 +24,392 @@ namespace NArchive { namespace N7z { -#ifdef MY_CPU_X86_OR_AMD64 -#define USE_86_FILTER -#endif + +#define k_X86 k_BCJ + +struct CFilterMode +{ + UInt32 Id; + UInt32 Delta; + + CFilterMode(): Id(0), Delta(0) {} + + void SetDelta() + { + if (Id == k_IA64) + Delta = 16; + else if (Id == k_ARM || Id == k_PPC || Id == k_PPC) + Delta = 4; + else if (Id == k_ARMT) + Delta = 2; + else + Delta = 0; + } +}; + + +/* ---------- PE ---------- */ + +#define MZ_SIG 0x5A4D + +#define PE_SIG 0x00004550 +#define PE_OptHeader_Magic_32 0x10B +#define PE_OptHeader_Magic_64 0x20B +#define PE_SectHeaderSize 40 +#define PE_SECT_EXECUTE 0x20000000 + +static int Parse_EXE(const Byte *buf, size_t size, CFilterMode *filterMode) +{ + if (size < 512 || GetUi16(buf) != MZ_SIG) + return 0; + + const Byte *p; + UInt32 peOffset, optHeaderSize, filterId; + + peOffset = GetUi32(buf + 0x3C); + if (peOffset >= 0x1000 || peOffset + 512 > size || (peOffset & 7) != 0) + return 0; + p = buf + peOffset; + if (GetUi32(p) != PE_SIG) + return 0; + p += 4; + + switch (GetUi16(p)) + { + case 0x014C: + case 0x8664: filterId = k_X86; break; + + /* + IMAGE_FILE_MACHINE_ARM 0x01C0 // ARM LE + IMAGE_FILE_MACHINE_THUMB 0x01C2 // ARM Thumb / Thumb-2 LE + IMAGE_FILE_MACHINE_ARMNT 0x01C4 // ARM Thumb-2, LE + Note: We use ARM filter for 0x01C2. (WinCE 5 - 0x01C2) files mostly contain ARM code (not Thumb/Thumb-2). + */ + + case 0x01C0: // WinCE old + case 0x01C2: filterId = k_ARM; break; // WinCE new + case 0x01C4: filterId = k_ARMT; break; // WinRT + + case 0x0200: filterId = k_IA64; break; + default: return 0; + } + + optHeaderSize = GetUi16(p + 16); + if (optHeaderSize > (1 << 10)) + return 0; + + p += 20; /* headerSize */ + + switch (GetUi16(p)) + { + case PE_OptHeader_Magic_32: + case PE_OptHeader_Magic_64: + break; + default: + return 0; + } + + filterMode->Id = filterId; + return 1; +} + + +/* ---------- ELF ---------- */ + +#define ELF_SIG 0x464C457F + +#define ELF_CLASS_32 1 +#define ELF_CLASS_64 2 + +#define ELF_DATA_2LSB 1 +#define ELF_DATA_2MSB 2 + +static UInt16 Get16(const Byte *p, Bool be) { if (be) return (UInt16)GetBe16(p); return (UInt16)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); } + +static int Parse_ELF(const Byte *buf, size_t size, CFilterMode *filterMode) +{ + Bool /* is32, */ be; + UInt32 filterId; + + if (size < 512 || buf[6] != 1) /* ver */ + return 0; + + if (GetUi32(buf) != ELF_SIG) + return 0; + + switch (buf[4]) + { + case ELF_CLASS_32: /* is32 = True; */ break; + case ELF_CLASS_64: /* is32 = False; */ break; + default: return 0; + } + + switch (buf[5]) + { + case ELF_DATA_2LSB: be = False; break; + case ELF_DATA_2MSB: be = True; break; + default: return 0; + } + + switch (Get16(buf + 0x12, be)) + { + case 3: + case 6: + case 62: filterId = k_X86; break; + case 2: + case 18: + case 43: filterId = k_SPARC; break; + case 20: + case 21: if (!be) return 0; filterId = k_PPC; break; + case 40: if ( be) return 0; filterId = k_ARM; break; + + /* Some IA-64 ELF exacutable have size that is not aligned for 16 bytes. + So we don't use IA-64 filter for IA-64 ELF */ + // case 50: if ( be) return 0; filterId = k_IA64; break; + + default: return 0; + } + + filterMode->Id = filterId; + return 1; +} + + + +/* ---------- Mach-O ---------- */ + +#define MACH_SIG_BE_32 0xCEFAEDFE +#define MACH_SIG_BE_64 0xCFFAEDFE +#define MACH_SIG_LE_32 0xFEEDFACE +#define MACH_SIG_LE_64 0xFEEDFACF + +#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 MACH_MACHINE_PPC64 (MACH_ARCH_ABI64 | MACH_MACHINE_PPC) +#define MACH_MACHINE_AMD64 (MACH_ARCH_ABI64 | MACH_MACHINE_386) + +static unsigned Parse_MACH(const Byte *buf, size_t size, CFilterMode *filterMode) +{ + UInt32 filterId, numCommands, commandsSize; + + if (size < 512) + return 0; + + Bool /* mode64, */ be; + switch (GetUi32(buf)) + { + case MACH_SIG_BE_32: /* mode64 = False; */ be = True; break; + case MACH_SIG_BE_64: /* mode64 = True; */ be = True; break; + case MACH_SIG_LE_32: /* mode64 = False; */ be = False; break; + case MACH_SIG_LE_64: /* mode64 = True; */ be = False; break; + default: return 0; + } + + switch (Get32(buf + 4, be)) + { + case MACH_MACHINE_386: + case MACH_MACHINE_AMD64: filterId = k_X86; break; + case MACH_MACHINE_ARM: if ( be) return 0; filterId = k_ARM; break; + case MACH_MACHINE_SPARC: if (!be) return 0; filterId = k_SPARC; break; + case MACH_MACHINE_PPC: + case MACH_MACHINE_PPC64: if (!be) return 0; filterId = k_PPC; break; + default: return 0; + } + + numCommands = Get32(buf + 0x10, be); + commandsSize = Get32(buf + 0x14, be); + + if (commandsSize > (1 << 24) || numCommands > (1 << 18)) + return 0; + + filterMode->Id = filterId; + return 1; +} + + +/* ---------- WAV ---------- */ + +#define WAV_SUBCHUNK_fmt 0x20746D66 +#define WAV_SUBCHUNK_data 0x61746164 + +#define RIFF_SIG 0x46464952 + +static Bool Parse_WAV(const Byte *buf, size_t size, CFilterMode *filterMode) +{ + UInt32 subChunkSize, pos; + if (size < 0x2C) + return False; + + if (GetUi32(buf + 0) != RIFF_SIG || + GetUi32(buf + 8) != 0x45564157 || // WAVE + GetUi32(buf + 0xC) != WAV_SUBCHUNK_fmt) + return False; + subChunkSize = GetUi32(buf + 0x10); + /* [0x14 = format] = 1 (PCM) */ + if (subChunkSize < 0x10 || subChunkSize > 0x12 || GetUi16(buf + 0x14) != 1) + return False; + + unsigned numChannels = GetUi16(buf + 0x16); + unsigned bitsPerSample = GetUi16(buf + 0x22); + + if ((bitsPerSample & 0x7) != 0 || bitsPerSample >= 256 || numChannels >= 256) + return False; + + pos = 0x14 + subChunkSize; + + const int kNumSubChunksTests = 10; + // Do we need to scan more than 3 sub-chunks? + for (int i = 0; i < kNumSubChunksTests; i++) + { + if (pos + 8 > size) + return False; + subChunkSize = GetUi32(buf + pos + 4); + if (GetUi32(buf + pos) == WAV_SUBCHUNK_data) + { + unsigned delta = numChannels * (bitsPerSample >> 3); + if (delta >= 256) + return False; + filterMode->Id = k_Delta; + filterMode->Delta = delta; + return True; + } + if (subChunkSize > (1 << 16)) + return False; + pos += subChunkSize + 8; + } + return False; +} + +static Bool ParseFile(const Byte *buf, size_t size, CFilterMode *filterMode) +{ + filterMode->Id = 0; + filterMode->Delta = 0; + + if (Parse_EXE(buf, size, filterMode)) return True; + if (Parse_ELF(buf, size, filterMode)) return True; + if (Parse_MACH(buf, size, filterMode)) return True; + return Parse_WAV(buf, size, filterMode); +} + + + + +struct CFilterMode2: public CFilterMode +{ + bool Encrypted; + unsigned GroupIndex; + + CFilterMode2(): Encrypted(false) {} + + int Compare(const CFilterMode2 &m) const + { + if (!Encrypted) + { + if (m.Encrypted) + return -1; + } + else if (!m.Encrypted) + return 1; + + if (Id < m.Id) return -1; + if (Id > m.Id) return 1; + + if (Delta < m.Delta) return -1; + if (Delta > m.Delta) return 1; + + return 0; + } + + bool operator ==(const CFilterMode2 &m) const + { + return Id == m.Id && Delta == m.Delta && Encrypted == m.Encrypted; + } +}; + +static unsigned GetGroup(CRecordVector<CFilterMode2> &filters, const CFilterMode2 &m) +{ + unsigned i; + for (i = 0; i < filters.Size(); i++) + { + const CFilterMode2 &m2 = filters[i]; + if (m == m2) + return i; + /* + if (m.Encrypted != m2.Encrypted) + { + if (!m.Encrypted) + break; + continue; + } + + if (m.Id < m2.Id) break; + if (m.Id != m2.Id) continue; + + if (m.Delta < m2.Delta) break; + if (m.Delta != m2.Delta) continue; + */ + } + // filters.Insert(i, m); + // return i; + return filters.Add(m); +} + +static inline bool Is86Filter(CMethodId m) +{ + return (m == k_BCJ || m == k_BCJ2); +} + +static inline bool IsExeFilter(CMethodId m) +{ + switch (m) + { + case k_BCJ: + case k_BCJ2: + case k_ARM: + case k_ARMT: + case k_PPC: + case k_SPARC: + case k_IA64: + return true; + } + return false; +} + +static unsigned Get_FilterGroup_for_Folder(CRecordVector<CFilterMode2> &filters, const CFolderEx &f) +{ + CFilterMode2 m; + m.Id = 0; + m.Delta = 0; + m.Encrypted = f.IsEncrypted(); + + const CCoderInfo &coder = f.Coders[f.UnpackCoder]; + + if (coder.MethodID == k_Delta) + { + if (coder.Props.Size() == 1) + { + m.Delta = (unsigned)coder.Props[0] + 1; + m.Id = k_Delta; + } + } + else if (IsExeFilter(coder.MethodID)) + { + m.Id = (UInt32)coder.MethodID; + if (m.Id == k_BCJ2) + m.Id = k_BCJ; + m.SetDelta(); + } + + return GetGroup(filters, m); +} + + + static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream, UInt64 position, UInt64 size, ICompressProgressInfo *progress) @@ -44,21 +426,12 @@ static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream, return (copyCoderSpec->TotalSize == size ? S_OK : E_FAIL); } -static int GetReverseSlashPos(const UString &name) -{ - int slashPos = name.ReverseFind(L'/'); - #ifdef _WIN32 - int slash1Pos = name.ReverseFind(L'\\'); - slashPos = MyMax(slashPos, slash1Pos); - #endif - return slashPos; -} - -int CUpdateItem::GetExtensionPos() const +/* +unsigned CUpdateItem::GetExtensionPos() const { - int slashPos = GetReverseSlashPos(Name); - int dotPos = Name.ReverseFind(L'.'); - if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0)) + int slashPos = Name.ReverseFind_PathSepar(); + int dotPos = Name.ReverseFind_Dot(); + if (dotPos <= slashPos) return Name.Len(); return dotPos + 1; } @@ -67,6 +440,7 @@ UString CUpdateItem::GetExtension() const { return Name.Ptr(GetExtensionPos()); } +*/ #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } @@ -91,7 +465,7 @@ static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2) return CompareBuffers(c1.Props, c2.Props); } -static int CompareBindPairs(const CBindPair &b1, const CBindPair &b2) +static int CompareBonds(const CBond &b1, const CBond &b2) { RINOZ_COMP(b1.InIndex, b2.InIndex); return MyCompare(b1.OutIndex, b2.OutIndex); @@ -105,11 +479,11 @@ static int CompareFolders(const CFolder &f1, const CFolder &f2) int i; for (i = 0; i < s1; i++) RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i])); - s1 = f1.BindPairs.Size(); - s2 = f2.BindPairs.Size(); + s1 = f1.Bonds.Size(); + s2 = f2.Bonds.Size(); RINOZ_COMP(s1, s2); for (i = 0; i < s1; i++) - RINOZ(CompareBindPairs(f1.BindPairs[i], f2.BindPairs[i])); + RINOZ(CompareBonds(f1.Bonds[i], f2.Bonds[i])); return 0; } */ @@ -123,36 +497,34 @@ static int CompareFiles(const CFileItem &f1, const CFileItem &f2) struct CFolderRepack { - int FolderIndex; - int Group; + unsigned FolderIndex; CNum NumCopyFiles; }; -static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void * /* param */) +/* +static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void *) { - RINOZ_COMP(p1->Group, p2->Group); int i1 = p1->FolderIndex; int i2 = p2->FolderIndex; - /* // 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])); - */ + // const CDbEx &db = *(const CDbEx *)param; + // RINOZ(CompareFolders( + // db.Folders[i1], + // db.Folders[i2])); + return MyCompare(i1, i2); - /* - RINOZ_COMP( - db.NumUnpackStreamsVector[i1], - db.NumUnpackStreamsVector[i2]); - if (db.NumUnpackStreamsVector[i1] == 0) - return 0; - return CompareFiles( - db.Files[db.FolderStartFileIndex[i1]], - db.Files[db.FolderStartFileIndex[i2]]); - */ + + // RINOZ_COMP( + // db.NumUnpackStreamsVector[i1], + // db.NumUnpackStreamsVector[i2]); + // if (db.NumUnpackStreamsVector[i1] == 0) + // return 0; + // return CompareFiles( + // db.Files[db.FolderStartFileIndex[i1]], + // db.Files[db.FolderStartFileIndex[i2]]); } +*/ /* we sort empty files and dirs in such order: @@ -162,7 +534,7 @@ static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2 - Dir.Anti (reverse name sorted) */ -static int CompareEmptyItems(const int *p1, const int *p2, void *param) +static int CompareEmptyItems(const unsigned *p1, const unsigned *p2, void *param) { const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param; const CUpdateItem &u1 = updateItems[*p1]; @@ -211,9 +583,9 @@ static const char *g_Exts = " exe dll ocx vbx sfx sys tlb awx com obj lib out o so " " pdb pch idb ncb opt"; -static int GetExtIndex(const char *ext) +static unsigned GetExtIndex(const char *ext) { - int extIndex = 1; + unsigned extIndex = 1; const char *p = g_Exts; for (;;) { @@ -222,7 +594,7 @@ static int GetExtIndex(const char *ext) return extIndex; if (c == ' ') continue; - int pos = 0; + unsigned pos = 0; for (;;) { char c2 = ext[pos++]; @@ -248,8 +620,8 @@ struct CRefItem { const CUpdateItem *UpdateItem; UInt32 Index; - UInt32 ExtensionPos; - UInt32 NamePos; + unsigned ExtensionPos; + unsigned NamePos; unsigned ExtensionIndex; CRefItem() {}; @@ -262,10 +634,10 @@ struct CRefItem { if (sortByType) { - int slashPos = GetReverseSlashPos(ui.Name); + int slashPos = ui.Name.ReverseFind_PathSepar(); NamePos = slashPos + 1; - int dotPos = ui.Name.ReverseFind(L'.'); - if (dotPos < 0 || dotPos < slashPos) + int dotPos = ui.Name.ReverseFind_Dot(); + if (dotPos <= slashPos) ExtensionPos = ui.Name.Len(); else { @@ -396,35 +768,193 @@ static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *para struct CSolidGroup { CRecordVector<UInt32> Indices; + + CRecordVector<CFolderRepack> folderRefs; }; -static const wchar_t *g_ExeExts[] = +static const char *g_ExeExts[] = { - L"dll" - , L"exe" - , L"ocx" - , L"sfx" - , L"sys" + "dll" + , "exe" + , "ocx" + , "sfx" + , "sys" }; static bool IsExeExt(const wchar_t *ext) { - for (int i = 0; i < ARRAY_SIZE(g_ExeExts); i++) - if (MyStringCompareNoCase(ext, g_ExeExts[i]) == 0) + for (unsigned i = 0; i < ARRAY_SIZE(g_ExeExts); i++) + if (StringsAreEqualNoCase_Ascii(ext, g_ExeExts[i])) return true; return false; } +struct CAnalysis +{ + CMyComPtr<IArchiveUpdateCallbackFile> Callback; + CByteBuffer Buffer; + + bool ParseWav; + bool ParseExe; + bool ParseAll; -static inline void GetMethodFull(UInt64 methodID, UInt32 numInStreams, CMethodFull &m) + CAnalysis(): + ParseWav(true), + ParseExe(false), + ParseAll(false) + {} + + HRESULT GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode); +}; + +static const size_t kAnalysisBufSize = 1 << 14; + +HRESULT CAnalysis::GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode) +{ + filterMode.Id = 0; + filterMode.Delta = 0; + + CFilterMode filterModeTemp = filterMode; + + int slashPos = ui.Name.ReverseFind_PathSepar(); + int dotPos = ui.Name.ReverseFind_Dot(); + + // if (dotPos > slashPos) + { + bool needReadFile = ParseAll; + + bool probablyIsSameIsa = false; + + if (!needReadFile || !Callback) + { + const wchar_t *ext; + if (dotPos > slashPos) + ext = ui.Name.Ptr(dotPos + 1); + else + ext = ui.Name.RightPtr(0); + + // p7zip uses the trick to store posix attributes in high 16 bits + if (ui.Attrib & 0x8000) + { + unsigned st_mode = ui.Attrib >> 16; + // st_mode = 00111; + if ((st_mode & 00111) && (ui.Size >= 2048)) + { + #ifndef _WIN32 + probablyIsSameIsa = true; + #endif + needReadFile = true; + } + } + + if (IsExeExt(ext)) + { + needReadFile = true; + #ifdef _WIN32 + probablyIsSameIsa = true; + needReadFile = ParseExe; + #endif + } + else if (StringsAreEqualNoCase_Ascii(ext, "wav")) + { + needReadFile = ParseWav; + } + /* + else if (!needReadFile && ParseUnixExt) + { + if (StringsAreEqualNoCase_Ascii(ext, "so") + || StringsAreEqualNoCase_Ascii(ext, "")) + + needReadFile = true; + } + */ + } + + if (needReadFile && Callback) + { + if (Buffer.Size() != kAnalysisBufSize) + { + Buffer.Alloc(kAnalysisBufSize); + } + { + CMyComPtr<ISequentialInStream> stream; + HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze); + if (result == S_OK && stream) + { + size_t size = kAnalysisBufSize; + result = ReadStream(stream, Buffer, &size); + stream.Release(); + // RINOK(Callback->SetOperationResult2(index, NUpdate::NOperationResult::kOK)); + if (result == S_OK) + { + Bool parseRes = ParseFile(Buffer, size, &filterModeTemp); + if (parseRes && filterModeTemp.Delta == 0) + { + filterModeTemp.SetDelta(); + if (filterModeTemp.Delta != 0 && filterModeTemp.Id != k_Delta) + { + if (ui.Size % filterModeTemp.Delta != 0) + { + parseRes = false; + } + } + } + if (!parseRes) + { + filterModeTemp.Id = 0; + filterModeTemp.Delta = 0; + } + } + } + } + } + else if ((needReadFile && !Callback) || probablyIsSameIsa) + { + #ifdef MY_CPU_X86_OR_AMD64 + if (probablyIsSameIsa) + filterModeTemp.Id = k_X86; + #endif + } + } + + filterMode = filterModeTemp; + return S_OK; +} + +static inline void GetMethodFull(UInt64 methodID, UInt32 numStreams, CMethodFull &m) { m.Id = methodID; - m.NumInStreams = numInStreams; - m.NumOutStreams = 1; + m.NumStreams = numStreams; +} + +static HRESULT AddBondForFilter(CCompressionMethodMode &mode) +{ + for (unsigned c = 1; c < mode.Methods.Size(); c++) + { + if (!mode.IsThereBond_to_Coder(c)) + { + CBond2 bond; + bond.OutCoder = 0; + bond.OutStream = 0; + bond.InCoder = c; + mode.Bonds.Add(bond); + return S_OK; + } + } + return E_INVALIDARG; } -static void AddBcj2Methods(CCompressionMethodMode &mode) +static HRESULT AddFilterBond(CCompressionMethodMode &mode) { + if (!mode.Bonds.IsEmpty()) + return AddBondForFilter(mode); + return S_OK; +} + +static HRESULT AddBcj2Methods(CCompressionMethodMode &mode) +{ + // mode.Methods[0] must be k_BCJ2 method ! + CMethodFull m; GetMethodFull(k_LZMA, 1, m); @@ -433,54 +963,121 @@ static void AddBcj2Methods(CCompressionMethodMode &mode) m.AddProp32(NCoderPropID::kNumThreads, 1); m.AddProp32(NCoderPropID::kLitPosBits, 2); m.AddProp32(NCoderPropID::kLitContextBits, 0); - // m.AddPropString(NCoderPropID::kMatchFinder, L"BT2"); + // m.AddProp_Ascii(NCoderPropID::kMatchFinder, "BT2"); + + unsigned methodIndex = mode.Methods.Size(); + + if (mode.Bonds.IsEmpty()) + { + for (unsigned i = 1; i + 1 < mode.Methods.Size(); i++) + { + CBond2 bond; + bond.OutCoder = i; + bond.OutStream = 0; + bond.InCoder = i + 1; + mode.Bonds.Add(bond); + } + } mode.Methods.Add(m); mode.Methods.Add(m); - CBind bind; - bind.OutCoder = 0; - bind.InStream = 0; - bind.InCoder = 1; bind.OutStream = 0; mode.Binds.Add(bind); - bind.InCoder = 2; bind.OutStream = 1; mode.Binds.Add(bind); - bind.InCoder = 3; bind.OutStream = 2; mode.Binds.Add(bind); + RINOK(AddBondForFilter(mode)); + CBond2 bond; + bond.OutCoder = 0; + bond.InCoder = methodIndex; bond.OutStream = 1; mode.Bonds.Add(bond); + bond.InCoder = methodIndex + 1; bond.OutStream = 2; mode.Bonds.Add(bond); + return S_OK; } -static void MakeExeMethod(CCompressionMethodMode &mode, - bool useFilters, bool addFilter, bool bcj2Filter) +static HRESULT MakeExeMethod(CCompressionMethodMode &mode, + const CFilterMode &filterMode, /* bool addFilter, */ bool bcj2Filter) { - if (!mode.Binds.IsEmpty() || !useFilters || mode.Methods.Size() > 2) - return; - if (mode.Methods.Size() == 2) + if (mode.Filter_was_Inserted) { - if (mode.Methods[0].Id == k_BCJ2) - AddBcj2Methods(mode); - return; + const CMethodFull &m = mode.Methods[0]; + CMethodId id = m.Id; + if (id == k_BCJ2) + return AddBcj2Methods(mode); + if (!m.IsSimpleCoder()) + return E_NOTIMPL; + // if (Bonds.IsEmpty()) we can create bonds later + return AddFilterBond(mode); + } + + if (filterMode.Id == 0) + return S_OK; + + CMethodFull &m = mode.Methods.InsertNew(0); + + { + FOR_VECTOR(k, mode.Bonds) + { + CBond2 &bond = mode.Bonds[k]; + bond.InCoder++; + bond.OutCoder++; + } } - if (!addFilter) - return; - bcj2Filter = bcj2Filter; - #ifdef USE_86_FILTER - if (bcj2Filter) + + HRESULT res; + + if (bcj2Filter && Is86Filter(filterMode.Id)) { - CMethodFull m; GetMethodFull(k_BCJ2, 4, m); - mode.Methods.Insert(0, m); - AddBcj2Methods(mode); + res = AddBcj2Methods(mode); } else { - CMethodFull m; - GetMethodFull(k_BCJ, 1, m); - mode.Methods.Insert(0, m); - CBind bind; - bind.OutCoder = 0; - bind.InStream = 0; - bind.InCoder = 1; - bind.OutStream = 0; - mode.Binds.Add(bind); + GetMethodFull(filterMode.Id, 1, m); + if (filterMode.Id == k_Delta) + m.AddProp32(NCoderPropID::kDefaultProp, filterMode.Delta); + res = AddFilterBond(mode); + + int alignBits = -1; + if (filterMode.Id == k_Delta || filterMode.Delta != 0) + { + if (filterMode.Delta == 1) alignBits = 0; + else if (filterMode.Delta == 2) alignBits = 1; + else if (filterMode.Delta == 4) alignBits = 2; + else if (filterMode.Delta == 8) alignBits = 3; + else if (filterMode.Delta == 16) alignBits = 4; + } + else + { + // alignBits = GetAlignForFilterMethod(filterMode.Id); + } + + if (res == S_OK && alignBits >= 0) + { + unsigned nextCoder = 1; + if (!mode.Bonds.IsEmpty()) + { + nextCoder = mode.Bonds.Back().InCoder; + } + if (nextCoder < mode.Methods.Size()) + { + CMethodFull &nextMethod = mode.Methods[nextCoder]; + if (nextMethod.Id == k_LZMA || nextMethod.Id == k_LZMA2) + { + if (!nextMethod.Are_Lzma_Model_Props_Defined()) + { + if (alignBits != 0) + { + if (alignBits > 2 || filterMode.Id == k_Delta) + nextMethod.AddProp32(NCoderPropID::kPosStateBits, alignBits); + unsigned lc = 0; + if (alignBits < 3) + lc = 3 - alignBits; + nextMethod.AddProp32(NCoderPropID::kLitContextBits, lc); + nextMethod.AddProp32(NCoderPropID::kLitPosBits, alignBits); + } + } + } + } + } } - #endif + + return res; } @@ -503,133 +1100,336 @@ static void FromUpdateItemToFileItem(const CUpdateItem &ui, // file.IsAltStream = ui.IsAltStream; } -class CFolderOutStream2: - public ISequentialOutStream, +class CRepackInStreamWithSizes: + public ISequentialInStream, + public ICompressGetSubStreamSize, public CMyUnknownImp { - COutStreamWithCRC *_crcStreamSpec; - CMyComPtr<ISequentialOutStream> _crcStream; - const CDbEx *_db; + CMyComPtr<ISequentialInStream> _stream; + // UInt64 _size; const CBoolVector *_extractStatuses; - CMyComPtr<ISequentialOutStream> _outStream; UInt32 _startIndex; - unsigned _currentIndex; +public: + const CDbEx *_db; + + void Init(ISequentialInStream *stream, UInt32 startIndex, const CBoolVector *extractStatuses) + { + _startIndex = startIndex; + _extractStatuses = extractStatuses; + // _size = 0; + _stream = stream; + } + // UInt64 GetSize() const { return _size; } + + MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize) + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + + STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); +}; + +STDMETHODIMP CRepackInStreamWithSizes::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + return _stream->Read(data, size, processedSize); + /* + UInt32 realProcessedSize; + HRESULT result = _stream->Read(data, size, &realProcessedSize); + _size += realProcessedSize; + if (processedSize) + *processedSize = realProcessedSize; + return result; + */ +} + +STDMETHODIMP CRepackInStreamWithSizes::GetSubStreamSize(UInt64 subStream, UInt64 *value) +{ + *value = 0; + if (subStream >= _extractStatuses->Size()) + return S_FALSE; // E_FAIL; + unsigned index = (unsigned)subStream; + if ((*_extractStatuses)[index]) + { + const CFileItem &fi = _db->Files[_startIndex + index]; + if (fi.HasStream) + *value = fi.Size; + } + return S_OK; +} + + +class CRepackStreamBase +{ +protected: + bool _needWrite; bool _fileIsOpen; + bool _calcCrc; + UInt32 _crc; UInt64 _rem; - void OpenFile(); - void CloseFile(); - HRESULT CloseFileAndSetResult(); + const CBoolVector *_extractStatuses; + UInt32 _startIndex; + unsigned _currentIndex; + + HRESULT OpenFile(); + HRESULT CloseFile(); HRESULT ProcessEmptyFiles(); + public: - MY_UNKNOWN_IMP - - CFolderOutStream2() - { - _crcStreamSpec = new COutStreamWithCRC; - _crcStream = _crcStreamSpec; - } + const CDbEx *_db; + CMyComPtr<IArchiveUpdateCallbackFile> _opCallback; + CMyComPtr<IArchiveExtractCallbackMessage> _extractCallback; - HRESULT Init(const CDbEx *db, UInt32 startIndex, - const CBoolVector *extractStatuses, ISequentialOutStream *outStream); - void ReleaseOutStream(); + HRESULT Init(UInt32 startIndex, const CBoolVector *extractStatuses); HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; } - - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; -HRESULT CFolderOutStream2::Init(const CDbEx *db, UInt32 startIndex, - const CBoolVector *extractStatuses, ISequentialOutStream *outStream) +HRESULT CRepackStreamBase::Init(UInt32 startIndex, const CBoolVector *extractStatuses) { - _db = db; _startIndex = startIndex; _extractStatuses = extractStatuses; - _outStream = outStream; _currentIndex = 0; _fileIsOpen = false; + return ProcessEmptyFiles(); } -void CFolderOutStream2::ReleaseOutStream() +HRESULT CRepackStreamBase::OpenFile() { - _outStream.Release(); - _crcStreamSpec->ReleaseStream(); -} + UInt32 arcIndex = _startIndex + _currentIndex; + const CFileItem &fi = _db->Files[arcIndex]; + + _needWrite = (*_extractStatuses)[_currentIndex]; + if (_opCallback) + { + RINOK(_opCallback->ReportOperation( + NEventIndexType::kInArcIndex, arcIndex, + _needWrite ? + NUpdateNotifyOp::kRepack : + NUpdateNotifyOp::kSkip)); + } + + _crc = CRC_INIT_VAL; + _calcCrc = (fi.CrcDefined && !fi.IsDir); -void CFolderOutStream2::OpenFile() -{ - _crcStreamSpec->SetStream((*_extractStatuses)[_currentIndex] ? _outStream : NULL); - _crcStreamSpec->Init(true); _fileIsOpen = true; - _rem = _db->Files[_startIndex + _currentIndex].Size; + _rem = fi.Size; + return S_OK; } -void CFolderOutStream2::CloseFile() +const HRESULT k_My_HRESULT_CRC_ERROR = 0x20000002; + +HRESULT CRepackStreamBase::CloseFile() { - _crcStreamSpec->ReleaseStream(); + UInt32 arcIndex = _startIndex + _currentIndex; + const CFileItem &fi = _db->Files[arcIndex]; _fileIsOpen = false; _currentIndex++; -} + if (!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc)) + return S_OK; -HRESULT CFolderOutStream2::CloseFileAndSetResult() -{ - const CFileItem &file = _db->Files[_startIndex + _currentIndex]; - CloseFile(); - return (file.IsDir || !file.CrcDefined || file.Crc == _crcStreamSpec->GetCRC()) ? S_OK: S_FALSE; + if (_extractCallback) + { + RINOK(_extractCallback->ReportExtractResult( + NEventIndexType::kInArcIndex, arcIndex, + NExtract::NOperationResult::kCRCError)); + } + // return S_FALSE; + return k_My_HRESULT_CRC_ERROR; } -HRESULT CFolderOutStream2::ProcessEmptyFiles() +HRESULT CRepackStreamBase::ProcessEmptyFiles() { while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0) { - OpenFile(); - RINOK(CloseFileAndSetResult()); + RINOK(OpenFile()); + RINOK(CloseFile()); } return S_OK; } + + + +#ifndef _7ZIP_ST + +class CFolderOutStream2: + public CRepackStreamBase, + public ISequentialOutStream, + public CMyUnknownImp +{ +public: + CMyComPtr<ISequentialOutStream> _stream; + + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; STDMETHODIMP CFolderOutStream2::Write(const void *data, UInt32 size, UInt32 *processedSize) { - if (processedSize != NULL) + if (processedSize) *processedSize = 0; + while (size != 0) { if (_fileIsOpen) { - UInt32 cur = size < _rem ? size : (UInt32)_rem; - RINOK(_crcStream->Write(data, cur, &cur)); - if (cur == 0) - break; + UInt32 cur = (size < _rem ? size : (UInt32)_rem); + HRESULT result = S_OK; + if (_needWrite) + result = _stream->Write(data, cur, &cur); + if (_calcCrc) + _crc = CrcUpdate(_crc, data, cur); + if (processedSize) + *processedSize += cur; data = (const Byte *)data + cur; size -= cur; _rem -= cur; - if (processedSize != NULL) - *processedSize += cur; if (_rem == 0) { - RINOK(CloseFileAndSetResult()); + RINOK(CloseFile()); RINOK(ProcessEmptyFiles()); - continue; } + RINOK(result); + if (cur == 0) + break; + continue; } - else + + RINOK(ProcessEmptyFiles()); + if (_currentIndex == _extractStatuses->Size()) { - RINOK(ProcessEmptyFiles()); - if (_currentIndex == _extractStatuses->Size()) + // we don't support write cut here + return E_FAIL; + } + RINOK(OpenFile()); + } + + return S_OK; +} + +#endif + + + +static const UInt32 kTempBufSize = 1 << 16; + +class CFolderInStream2: + public CRepackStreamBase, + public ISequentialInStream, + public CMyUnknownImp +{ + Byte *_buf; +public: + CMyComPtr<ISequentialInStream> _inStream; + HRESULT Result; + + MY_UNKNOWN_IMP + + CFolderInStream2(): + Result(S_OK) + { + _buf = new Byte[kTempBufSize]; + } + + ~CFolderInStream2() + { + delete []_buf; + } + + void Init() { Result = S_OK; } + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CFolderInStream2::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + + while (size != 0) + { + if (_fileIsOpen) + { + UInt32 cur = (size < _rem ? size : (UInt32)_rem); + + void *buf; + if (_needWrite) + buf = data; + else { - // we don't support partial extracting - return E_FAIL; + buf = _buf; + if (cur > kTempBufSize) + cur = kTempBufSize; } - OpenFile(); + + HRESULT result = _inStream->Read(buf, cur, &cur); + _crc = CrcUpdate(_crc, buf, cur); + _rem -= cur; + + if (_needWrite) + { + data = (Byte *)data + cur; + size -= cur; + if (processedSize) + *processedSize += cur; + } + + if (result != S_OK) + Result = result; + + if (_rem == 0) + { + RINOK(CloseFile()); + RINOK(ProcessEmptyFiles()); + } + + RINOK(result); + + if (cur == 0) + return E_FAIL; + + continue; } + + RINOK(ProcessEmptyFiles()); + if (_currentIndex == _extractStatuses->Size()) + { + return S_OK; + } + RINOK(OpenFile()); } + return S_OK; } -class CThreadDecoder: public CVirtThread + +class CThreadDecoder + #ifndef _7ZIP_ST + : public CVirtThread + #endif { public: + CDecoder Decoder; + + CThreadDecoder(bool multiThreadMixer): + Decoder(multiThreadMixer) + { + #ifndef _7ZIP_ST + if (multiThreadMixer) + { + MtMode = false; + NumThreads = 1; + FosSpec = new CFolderOutStream2; + Fos = FosSpec; + Result = E_FAIL; + } + #endif + // UnpackSize = 0; + // send_UnpackSize = false; + } + + #ifndef _7ZIP_ST + HRESULT Result; CMyComPtr<IInStream> InStream; @@ -639,33 +1439,30 @@ public: UInt64 StartPos; const CFolders *Folders; int FolderIndex; + + // bool send_UnpackSize; + // UInt64 UnpackSize; + #ifndef _NO_CRYPTO CMyComPtr<ICryptoGetTextPassword> getTextPassword; #endif DECL_EXTERNAL_CODECS_LOC_VARS2; - CDecoder Decoder; #ifndef _7ZIP_ST bool MtMode; UInt32 NumThreads; #endif - CThreadDecoder(): - Decoder(true) - { - #ifndef _7ZIP_ST - MtMode = false; - NumThreads = 1; - #endif - FosSpec = new CFolderOutStream2; - Fos = FosSpec; - Result = E_FAIL; - } + ~CThreadDecoder() { CVirtThread::WaitThreadFinish(); } virtual void Execute(); + + #endif }; +#ifndef _7ZIP_ST + void CThreadDecoder::Execute() { try @@ -673,6 +1470,7 @@ void CThreadDecoder::Execute() #ifndef _NO_CRYPTO bool isEncrypted = false; bool passwordIsDefined = false; + UString password; #endif Result = Decoder.Decode( @@ -680,8 +1478,14 @@ void CThreadDecoder::Execute() InStream, StartPos, *Folders, FolderIndex, + + // send_UnpackSize ? &UnpackSize : NULL, + NULL, // unpackSize : FULL unpack + Fos, - NULL + NULL, // compressProgress + NULL // *inStreamMainRes + _7Z_DECODER_CRYPRO_VARS #ifndef _7ZIP_ST , MtMode, NumThreads @@ -692,21 +1496,15 @@ void CThreadDecoder::Execute() { Result = E_FAIL; } + + /* if (Result == S_OK) Result = FosSpec->CheckFinishedState(); - FosSpec->ReleaseOutStream(); + */ + FosSpec->_stream.Release(); } -bool static Is86FilteredFolder(const CFolder &f) -{ - FOR_VECTOR(i, f.Coders) - { - CMethodId m = f.Coders[i].MethodID; - if (m == k_BCJ || m == k_BCJ2) - return true; - } - return false; -} +#endif #ifndef _NO_CRYPTO @@ -728,14 +1526,8 @@ STDMETHODIMP CCryptoGetTextPassword::CryptoGetTextPassword(BSTR *password) #endif -static const int kNumGroupsMax = 4; - -static bool Is86Group(int group) { return (group & 1) != 0; } -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) +static void GetFile(const CDatabase &inDb, unsigned index, CFileItem &file, CFileItem2 &file2) { file = inDb.Files[index]; file2.CTimeDefined = inDb.CTime.GetItem(index, file2.CTime); @@ -767,6 +1559,12 @@ HRESULT Update( if (numSolidFiles == 0) numSolidFiles = 1; + CMyComPtr<IArchiveUpdateCallbackFile> opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + + CMyComPtr<IArchiveExtractCallbackMessage> extractCallback; + updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback); + // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes(); /* @@ -783,14 +1581,19 @@ HRESULT Update( } CIntArr fileIndexToUpdateIndexMap; - CRecordVector<CFolderRepack> folderRefs; UInt64 complexity = 0; UInt64 inSizeForReduce2 = 0; bool needEncryptedRepack = false; + + CRecordVector<CFilterMode2> filters; + CObjectVector<CSolidGroup> groups; + bool thereAreRepacks = false; + if (db != 0) { fileIndexToUpdateIndexMap.Alloc(db->Files.Size()); unsigned i; + for (i = 0; i < db->Files.Size(); i++) fileIndexToUpdateIndexMap[i] = -1; @@ -798,15 +1601,16 @@ HRESULT Update( { int index = updateItems[i].IndexInArchive; if (index != -1) - fileIndexToUpdateIndexMap[index] = i; + fileIndexToUpdateIndexMap[(unsigned)index] = i; } - for (i = 0; i < (int)db->NumFolders; i++) + for (i = 0; i < db->NumFolders; i++) { CNum indexInFolder = 0; CNum numCopyItems = 0; CNum numUnpackStreams = db->NumUnpackStreamsVector[i]; UInt64 repackSize = 0; + for (CNum fi = db->FolderStartFileIndex[i]; indexInFolder < numUnpackStreams; fi++) { const CFileItem &file = db->Files[fi]; @@ -828,23 +1632,30 @@ HRESULT Update( CFolderRepack rep; rep.FolderIndex = i; rep.NumCopyFiles = numCopyItems; - CFolder f; - db->ParseFolderInfo(i, f); + CFolderEx f; + db->ParseFolderEx(i, f); + bool isEncrypted = f.IsEncrypted(); - rep.Group = GetGroupIndex(isEncrypted, Is86FilteredFolder(f)); - folderRefs.Add(rep); + + unsigned groupIndex = Get_FilterGroup_for_Folder(filters, f); + + while (groupIndex >= groups.Size()) + groups.AddNew(); + + groups[groupIndex].folderRefs.Add(rep); + if (numCopyItems == numUnpackStreams) complexity += db->GetFolderFullPackSize(i); else { + thereAreRepacks = true; complexity += repackSize; - if (repackSize > inSizeForReduce2) + if (inSizeForReduce2 < repackSize) inSizeForReduce2 = repackSize; if (isEncrypted) needEncryptedRepack = true; } } - folderRefs.Sort(CompareFolderRepacks, (void *)db); } UInt64 inSizeForReduce = 0; @@ -857,12 +1668,12 @@ HRESULT Update( complexity += ui.Size; if (numSolidFiles != 1) inSizeForReduce += ui.Size; - else if (ui.Size > inSizeForReduce) + else if (inSizeForReduce < ui.Size) inSizeForReduce = ui.Size; } } - if (inSizeForReduce2 > inSizeForReduce) + if (inSizeForReduce < inSizeForReduce2) inSizeForReduce = inSizeForReduce2; RINOK(updateCallback->SetTotal(complexity)); @@ -871,52 +1682,102 @@ HRESULT Update( CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(updateCallback, true); + #ifndef _7ZIP_ST + CStreamBinder sb; - RINOK(sb.CreateEvents()); + if (options.MultiThreadMixer) + { + RINOK(sb.CreateEvents()); + } + + #endif - CThreadDecoder threadDecoder; - if (!folderRefs.IsEmpty()) + CThreadDecoder threadDecoder(options.MultiThreadMixer); + + #ifndef _7ZIP_ST + if (options.MultiThreadMixer && thereAreRepacks) { #ifdef EXTERNAL_CODECS threadDecoder.__externalCodecs = __externalCodecs; #endif RINOK(threadDecoder.Create()); } - - CObjectVector<CSolidGroup> groups; - for (i = 0; i < kNumGroupsMax; i++) - groups.AddNew(); + #endif { + CAnalysis analysis; + if (options.AnalysisLevel == 0) + { + analysis.ParseWav = false; + analysis.ParseExe = false; + analysis.ParseAll = false; + } + else + { + analysis.Callback = opCallback; + if (options.AnalysisLevel > 0) + { + analysis.ParseWav = true; + if (options.AnalysisLevel >= 7) + { + analysis.ParseExe = true; + if (options.AnalysisLevel >= 9) + analysis.ParseAll = true; + } + } + } + // ---------- Split files to groups ---------- bool useFilters = options.UseFilters; const CCompressionMethodMode &method = *options.Method; - if (method.Methods.Size() != 1 || method.Binds.Size() != 0) + + if (useFilters) + for (i = 0; i < method.Methods.Size(); i++) + if (IsFilterMethod(method.Methods[i].Id)) + { + useFilters = false; + break; + } + + /* + if (!method.Bonds.IsEmpty()) useFilters = false; + */ + for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; if (!ui.NewData || !ui.HasStream()) continue; - bool filteredGroup = false; + + CFilterMode2 fm; if (useFilters) { - int dotPos = ui.Name.ReverseFind(L'.'); - if (dotPos >= 0) - filteredGroup = IsExeExt(ui.Name.Ptr(dotPos + 1)); + RINOK(analysis.GetFilterGroup(i, ui, fm)); } - groups[GetGroupIndex(method.PasswordIsDefined, filteredGroup)].Indices.Add(i); + fm.Encrypted = method.PasswordIsDefined; + + unsigned groupIndex = GetGroup(filters, fm); + while (groupIndex >= groups.Size()) + groups.AddNew(); + groups[groupIndex].Indices.Add(i); } } + #ifndef _NO_CRYPTO CCryptoGetTextPassword *getPasswordSpec = NULL; + CMyComPtr<ICryptoGetTextPassword> getTextPassword; if (needEncryptedRepack) { getPasswordSpec = new CCryptoGetTextPassword; + getTextPassword = getPasswordSpec; + + #ifndef _7ZIP_ST threadDecoder.getTextPassword = getPasswordSpec; + #endif if (options.Method->PasswordIsDefined) getPasswordSpec->Password = options.Method->Password; @@ -926,7 +1787,7 @@ HRESULT Update( return E_NOTIMPL; CMyComBSTR password; RINOK(getDecoderPassword->CryptoGetTextPassword(&password)); - if ((BSTR)password) + if (password) getPasswordSpec->Password = password; } } @@ -986,7 +1847,8 @@ HRESULT Update( { /* ---------- Write non-AUX dirs and Empty files ---------- */ - CRecordVector<int> emptyRefs; + CUIntVector emptyRefs; + for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; @@ -1003,7 +1865,9 @@ HRESULT Update( */ emptyRefs.Add(i); } + emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems); + for (i = 0; i < emptyRefs.Size(); i++) { const CUpdateItem &ui = updateItems[emptyRefs[i]]; @@ -1030,17 +1894,34 @@ HRESULT Update( } } - unsigned folderRefIndex = 0; lps->ProgressOffset = 0; - for (int groupIndex = 0; groupIndex < kNumGroupsMax; groupIndex++) { - const CSolidGroup &group = groups[groupIndex]; + // ---------- Sort Filters ---------- + + FOR_VECTOR (i, filters) + { + filters[i].GroupIndex = i; + } + filters.Sort2(); + } + + for (unsigned groupIndex = 0; groupIndex < filters.Size(); groupIndex++) + { + const CFilterMode2 &filterMode = filters[groupIndex]; CCompressionMethodMode method = *options.Method; - MakeExeMethod(method, options.UseFilters, Is86Group(groupIndex), options.MaxFilter); + HRESULT res = MakeExeMethod(method, filterMode, + #ifdef _7ZIP_ST + false + #else + options.MaxFilter && options.MultiThreadMixer + #endif + ); + + RINOK(res); - if (IsEncryptedGroup(groupIndex)) + if (filterMode.Encrypted) { if (!method.PasswordIsDefined) { @@ -1059,83 +1940,260 @@ HRESULT Update( CEncoder encoder(method); - for (; folderRefIndex < folderRefs.Size(); folderRefIndex++) + // ---------- Repack and copy old solid blocks ---------- + + const CSolidGroup &group = groups[filterMode.GroupIndex]; + + FOR_VECTOR(folderRefIndex, group.folderRefs) { - const CFolderRepack &rep = folderRefs[folderRefIndex]; - if (rep.Group != groupIndex) - break; - int folderIndex = rep.FolderIndex; + const CFolderRepack &rep = group.folderRefs[folderRefIndex]; + + unsigned folderIndex = rep.FolderIndex; - if (rep.NumCopyFiles == db->NumUnpackStreamsVector[folderIndex]) + CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex]; + + if (rep.NumCopyFiles == numUnpackStreams) { + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, + NUpdateNotifyOp::kReplicate)); + + // ---------- Copy old solid block ---------- + { + CNum indexInFolder = 0; + for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) + { + if (db->Files[fi].HasStream) + { + indexInFolder++; + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, (UInt32)fi, + NUpdateNotifyOp::kReplicate)); + } + } + } + } + UInt64 packSize = db->GetFolderFullPackSize(folderIndex); RINOK(WriteRange(inStream, archive.SeqStream, - db->GetFolderStreamPos(folderIndex, 0), packSize, progress)); + db->GetFolderStreamPos(folderIndex, 0), packSize, progress)); lps->ProgressOffset += packSize; CFolder &folder = newDatabase.Folders.AddNew(); db->ParseFolderInfo(folderIndex, folder); CNum startIndex = db->FoStartPackStreamIndex[folderIndex]; - for (unsigned j = 0; j < folder.PackStreams.Size(); j++) + FOR_VECTOR(j, folder.PackStreams) { newDatabase.PackSizes.Add(db->GetStreamPackSize(startIndex + j)); // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]); // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]); } - UInt32 indexStart = db->FoToCoderUnpackSizes[folderIndex]; - UInt32 indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1]; + size_t indexStart = db->FoToCoderUnpackSizes[folderIndex]; + size_t indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1]; for (; indexStart < indexEnd; indexStart++) newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes[indexStart]); } else { + // ---------- Repack old solid block ---------- + CBoolVector extractStatuses; - CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex]; CNum indexInFolder = 0; - + + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, + NUpdateNotifyOp::kRepack)) + } + + /* We could reduce data size of decoded folder, if we don't need to repack + last files in folder. But the gain in speed is small in most cases. + So we unpack full folder. */ + + UInt64 sizeToEncode = 0; + + /* + UInt64 importantUnpackSize = 0; + unsigned numImportantFiles = 0; + UInt64 decodeSize = 0; + */ + for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) { bool needExtract = false; - if (db->Files[fi].HasStream) + const CFileItem &file = db->Files[fi]; + + if (file.HasStream) { indexInFolder++; int updateIndex = fileIndexToUpdateIndexMap[fi]; if (updateIndex >= 0 && !updateItems[updateIndex].NewData) needExtract = true; + // decodeSize += file.Size; } + extractStatuses.Add(needExtract); + if (needExtract) + { + sizeToEncode += file.Size; + /* + numImportantFiles = extractStatuses.Size(); + importantUnpackSize = decodeSize; + */ + } } + // extractStatuses.DeleteFrom(numImportantFiles); + unsigned startPackIndex = newDatabase.PackSizes.Size(); UInt64 curUnpackSize; { + CMyComPtr<ISequentialInStream> sbInStream; + CRepackStreamBase *repackBase; + CFolderInStream2 *FosSpec2 = NULL; + + CRepackInStreamWithSizes *inStreamSizeCountSpec = new CRepackInStreamWithSizes; + CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec; { - CMyComPtr<ISequentialOutStream> sbOutStream; - sb.CreateStreams(&sbInStream, &sbOutStream); - sb.ReInit(); - RINOK(threadDecoder.FosSpec->Init(db, db->FolderStartFileIndex[folderIndex], &extractStatuses, sbOutStream)); - } - - threadDecoder.InStream = inStream; - threadDecoder.Folders = (const CFolders *)db; - threadDecoder.FolderIndex = folderIndex; - threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0); - - threadDecoder.Start(); + #ifndef _7ZIP_ST + if (options.MultiThreadMixer) + { + repackBase = threadDecoder.FosSpec; + CMyComPtr<ISequentialOutStream> sbOutStream; + sb.CreateStreams(&sbInStream, &sbOutStream); + sb.ReInit(); + + threadDecoder.FosSpec->_stream = sbOutStream; + + threadDecoder.InStream = inStream; + threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0); + threadDecoder.Folders = (const CFolders *)db; + threadDecoder.FolderIndex = folderIndex; + + // threadDecoder.UnpackSize = importantUnpackSize; + // threadDecoder.send_UnpackSize = true; + } + else + #endif + { + FosSpec2 = new CFolderInStream2; + FosSpec2->Init(); + sbInStream = FosSpec2; + repackBase = FosSpec2; + + #ifndef _NO_CRYPTO + bool isEncrypted = false; + bool passwordIsDefined = false; + UString password; + #endif + + CMyComPtr<ISequentialInStream> decodedStream; + HRESULT res = threadDecoder.Decoder.Decode( + EXTERNAL_CODECS_LOC_VARS + inStream, + db->ArcInfo.DataStartPosition, // db->GetFolderStreamPos(folderIndex, 0);, + *db, folderIndex, + // &importantUnpackSize, // *unpackSize + NULL, // *unpackSize : FULL unpack + + NULL, // *outStream + NULL, // *compressProgress + &decodedStream + + _7Z_DECODER_CRYPRO_VARS + #ifndef _7ZIP_ST + , false // mtMode + , 1 // numThreads + #endif + ); - RINOK(encoder.Encode( + RINOK(res); + if (!decodedStream) + return E_FAIL; + + FosSpec2->_inStream = decodedStream; + } + + repackBase->_db = db; + repackBase->_opCallback = opCallback; + repackBase->_extractCallback = extractCallback; + + UInt32 startIndex = db->FolderStartFileIndex[folderIndex]; + RINOK(repackBase->Init(startIndex, &extractStatuses)); + + inStreamSizeCountSpec->_db = db; + inStreamSizeCountSpec->Init(sbInStream, startIndex, &extractStatuses); + + #ifndef _7ZIP_ST + if (options.MultiThreadMixer) + { + threadDecoder.Start(); + } + #endif + } + + + HRESULT encodeRes = encoder.Encode( EXTERNAL_CODECS_LOC_VARS - sbInStream, NULL, &inSizeForReduce, + inStreamSizeCount, + // NULL, + &inSizeForReduce, newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curUnpackSize, - archive.SeqStream, newDatabase.PackSizes, progress)); - - threadDecoder.WaitExecuteFinish(); - } + archive.SeqStream, newDatabase.PackSizes, progress); - RINOK(threadDecoder.Result); + if (encodeRes == k_My_HRESULT_CRC_ERROR) + return E_FAIL; + + #ifndef _7ZIP_ST + if (options.MultiThreadMixer) + { + threadDecoder.WaitExecuteFinish(); + HRESULT decodeRes = threadDecoder.Result; + // if (res == k_My_HRESULT_CRC_ERROR) + if (decodeRes == S_FALSE) + { + if (extractCallback) + { + RINOK(extractCallback->ReportExtractResult( + NEventIndexType::kInArcIndex, db->FolderStartFileIndex[folderIndex], + // NEventIndexType::kBlockIndex, (UInt32)folderIndex, + NExtract::NOperationResult::kDataError)); + } + return E_FAIL; + } + RINOK(decodeRes); + if (encodeRes == S_OK) + if (sb.ProcessedSize != sizeToEncode) + encodeRes = E_FAIL; + } + else + #endif + { + if (FosSpec2->Result == S_FALSE) + { + if (extractCallback) + { + RINOK(extractCallback->ReportExtractResult( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, + NExtract::NOperationResult::kDataError)); + } + return E_FAIL; + } + RINOK(FosSpec2->Result); + } + + RINOK(encodeRes); + RINOK(repackBase->CheckFinishedState()); + + if (curUnpackSize != sizeToEncode) + return E_FAIL; + } for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) lps->OutSize += newDatabase.PackSizes[startPackIndex]; @@ -1144,8 +2202,6 @@ HRESULT Update( newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles); - CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex]; - CNum indexInFolder = 0; for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) { @@ -1187,6 +2243,9 @@ HRESULT Update( } } + + // ---------- Compress files to new solid blocks ---------- + unsigned numFiles = group.Indices.Size(); if (numFiles == 0) continue; @@ -1222,10 +2281,11 @@ HRESULT Update( for (i = 0; i < numFiles;) { UInt64 totalSize = 0; - int numSubFiles; - UString prevExtension; - for (numSubFiles = 0; i + numSubFiles < numFiles && - numSubFiles < numSolidFiles; numSubFiles++) + unsigned numSubFiles; + + const wchar_t *prevExtension = NULL; + + for (numSubFiles = 0; i + numSubFiles < numFiles && numSubFiles < numSolidFiles; numSubFiles++) { const CUpdateItem &ui = updateItems[indices[i + numSubFiles]]; totalSize += ui.Size; @@ -1233,17 +2293,21 @@ HRESULT Update( break; if (options.SolidExtension) { - UString ext = ui.GetExtension(); + int slashPos = ui.Name.ReverseFind_PathSepar(); + int dotPos = ui.Name.ReverseFind_Dot(); + const wchar_t *ext = ui.Name.Ptr(dotPos <= slashPos ? ui.Name.Len() : dotPos + 1); if (numSubFiles == 0) prevExtension = ext; - else - if (!ext.IsEqualToNoCase(prevExtension)) - break; + else if (!StringsAreEqualNoCase(ext, prevExtension)) + break; } } + if (numSubFiles < 1) numSubFiles = 1; + RINOK(lps->SetCur()); + CFolderInStream *inStreamSpec = new CFolderInStream; CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec); inStreamSpec->Init(updateCallback, &indices[i], numSubFiles); @@ -1252,10 +2316,15 @@ HRESULT Update( UInt64 curFolderUnpackSize; RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS - solidInStream, NULL, &inSizeForReduce, + solidInStream, + // NULL, + &inSizeForReduce, newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curFolderUnpackSize, archive.SeqStream, newDatabase.PackSizes, progress)); + if (!inStreamSpec->WasFinished()) + return E_FAIL; + for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) lps->OutSize += newDatabase.PackSizes[startPackIndex]; @@ -1263,9 +2332,11 @@ HRESULT Update( // for () // newDatabase.PackCRCsDefined.Add(false); // newDatabase.PackCRCs.Add(0); - + CNum numUnpackStreams = 0; - for (int subIndex = 0; subIndex < numSubFiles; subIndex++) + UInt64 skippedSize = 0; + + for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++) { const CUpdateItem &ui = updateItems[indices[i + subIndex]]; CFileItem file; @@ -1290,12 +2361,15 @@ HRESULT Update( */ if (!inStreamSpec->Processed[subIndex]) { + skippedSize += ui.Size; continue; - // file.Name += L".locked"; + // file.Name.AddAscii(".locked"); } file.Crc = inStreamSpec->CRCs[subIndex]; file.Size = inStreamSpec->Sizes[subIndex]; + + // if (file.Size >= 0) // test purposes if (file.Size != 0) { file.CrcDefined = true; @@ -1307,6 +2381,7 @@ HRESULT Update( file.CrcDefined = false; file.HasStream = false; } + /* file.Parent = ui.ParentFolderIndex; if (ui.TreeFolderIndex >= 0) @@ -1316,20 +2391,23 @@ HRESULT Update( */ newDatabase.AddFile(file, file2, name); } + // numUnpackStreams = 0 is very bad case for locked files // v3.13 doesn't understand it. newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams); i += numSubFiles; + + if (skippedSize != 0 && complexity >= skippedSize) + { + complexity -= skippedSize; + RINOK(updateCallback->SetTotal(complexity)); + } } } - if (folderRefIndex != folderRefs.Size()) - return E_FAIL; - RINOK(lps->SetCur()); /* - folderRefs.ClearAndFree(); fileIndexToUpdateIndexMap.ClearAndFree(); groups.ClearAndFree(); */ @@ -1350,13 +2428,18 @@ HRESULT Update( { const CByteBuffer &buf = secureBlocks.Bufs[secureBlocks.Sorted[i]]; size_t size = buf.GetCapacity(); - memcpy(newDatabase.SecureBuf + pos, buf, size); + if (size != 0) + memcpy(newDatabase.SecureBuf + pos, buf, size); newDatabase.SecureSizes.Add((UInt32)size); pos += size; } } */ newDatabase.ReserveDown(); + + if (opCallback) + RINOK(opCallback->ReportOperation(NEventIndexType::kNoIndex, (UInt32)(Int32)-1, NUpdateNotifyOp::kHeader)); + return S_OK; } diff --git a/CPP/7zip/Archive/7z/7zUpdate.h b/CPP/7zip/Archive/7z/7zUpdate.h index d00276e0..3986af43 100644 --- a/CPP/7zip/Archive/7z/7zUpdate.h +++ b/CPP/7zip/Archive/7z/7zUpdate.h @@ -65,6 +65,7 @@ struct CUpdateItem // int SecureIndex; // 0 means (no_security) bool HasStream() const { return !IsDir && !IsAnti && Size != 0; } + // bool HasStream() const { return !IsDir && !IsAnti /* && Size != 0 */; } // for test purposes CUpdateItem(): // ParentSortIndex(-1), @@ -77,18 +78,19 @@ struct CUpdateItem MTimeDefined(false) // SecureIndex(0) {} - void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); }; + void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); } - int GetExtensionPos() const; - UString GetExtension() const; + // unsigned GetExtensionPos() const; + // UString GetExtension() const; }; struct CUpdateOptions { const CCompressionMethodMode *Method; const CCompressionMethodMode *HeaderMethod; - bool UseFilters; - bool MaxFilter; + bool UseFilters; // use additional filters for some files + bool MaxFilter; // use BCJ2 filter instead of BCJ + int AnalysisLevel; CHeaderOptions HeaderOptions; @@ -96,7 +98,20 @@ struct CUpdateOptions UInt64 NumSolidBytes; bool SolidExtension; bool RemoveSfxBlock; - bool VolumeMode; + bool MultiThreadMixer; + + CUpdateOptions(): + Method(NULL), + HeaderMethod(NULL), + UseFilters(false), + MaxFilter(false), + AnalysisLevel(-1), + NumSolidFiles((UInt64)(Int64)(-1)), + NumSolidBytes((UInt64)(Int64)(-1)), + SolidExtension(false), + RemoveSfxBlock(false), + MultiThreadMixer(true) + {} }; HRESULT Update( diff --git a/CPP/7zip/Archive/ApmHandler.cpp b/CPP/7zip/Archive/ApmHandler.cpp index 96656733..d5a111e9 100644 --- a/CPP/7zip/Archive/ApmHandler.cpp +++ b/CPP/7zip/Archive/ApmHandler.cpp @@ -376,15 +376,13 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -IMP_CreateArcIn +static const Byte k_Signature[] = { kSig0, kSig1 }; -static CArcInfo g_ArcInfo = - { "APM", "apm", 0, 0xD4, - 2, { kSig0, kSig1 }, +REGISTER_ARC_I( + "APM", "apm", 0, 0xD4, + k_Signature, 0, 0, - CreateArc, NULL, IsArc_Apm }; - -REGISTER_ARC(Apm) + IsArc_Apm) }} diff --git a/CPP/7zip/Archive/ArHandler.cpp b/CPP/7zip/Archive/ArHandler.cpp index b7dcda85..1eec728f 100644 --- a/CPP/7zip/Archive/ArHandler.cpp +++ b/CPP/7zip/Archive/ArHandler.cpp @@ -77,7 +77,7 @@ enum EType kType_Lib }; -static const char *k_TypeExtionsions[] = +static const char * const k_TypeExtionsions[] = { "ar" , "a" @@ -121,7 +121,7 @@ struct CItem int SameNameIndex; CItem(): TextFileIndex(-1), SameNameIndex(-1) {} - UInt64 GetDataPos() const { return HeaderPos + HeaderSize; }; + UInt64 GetDataPos() const { return HeaderPos + HeaderSize; } }; class CInArchive @@ -257,10 +257,9 @@ HRESULT CInArchive::GetNextItem(CItem &item, bool &filled) { SubType = kSubType_BSD; size_t processedSize = longNameLen; - char *s = item.Name.GetBuffer(longNameLen); + char *s = item.Name.GetBuf(longNameLen); HRESULT res = ReadStream(m_Stream, s, &processedSize); - s[longNameLen] = 0; - item.Name.ReleaseBuffer(); + item.Name.ReleaseBuf_CalcLen(longNameLen); RINOK(res); if (processedSize != longNameLen) return S_OK; @@ -683,11 +682,11 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { case kpidPhySize: prop = _phySize; break; case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; - case kpidExtension: prop = k_TypeExtionsions[_type]; break; + case kpidExtension: prop = k_TypeExtionsions[(unsigned)_type]; break; case kpidShortComment: case kpidSubType: { - AString s = k_TypeExtionsions[_type]; + AString s = k_TypeExtionsions[(unsigned)_type]; if (_subType == kSubType_BSD) s += ":BSD"; prop = s; @@ -724,7 +723,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidSize: case kpidPackSize: if (item.TextFileIndex >= 0) - prop = (UInt64)_libFiles[item.TextFileIndex].Len(); + prop = (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len(); else prop = item.Size; break; @@ -766,7 +765,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, const CItem &item = _items[allFilesMode ? i : indices[i]]; totalSize += (item.TextFileIndex >= 0) ? - (UInt64)_libFiles[item.TextFileIndex].Len() : item.Size; + (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len() : item.Size; } extractCallback->SetTotal(totalSize); @@ -795,7 +794,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, const CItem &item = _items[index]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); currentTotalSize += (item.TextFileIndex >= 0) ? - (UInt64)_libFiles[item.TextFileIndex].Len() : item.Size; + (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len() : item.Size; if (!testMode && !realOutStream) continue; @@ -808,7 +807,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, bool isOk = true; if (item.TextFileIndex >= 0) { - const AString &f = _libFiles[item.TextFileIndex]; + const AString &f = _libFiles[(unsigned)item.TextFileIndex]; if (realOutStream) RINOK(WriteStream(realOutStream, f, f.Len())); } @@ -834,8 +833,8 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) 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); + const AString &f = _libFiles[(unsigned)item.TextFileIndex]; + Create_BufInStream_WithNewBuffer((const void *)(const char *)f, f.Len(), stream); return S_OK; } else @@ -843,15 +842,11 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -IMP_CreateArcIn - -static CArcInfo g_ArcInfo = - { "Ar", "ar a deb lib", 0, 0xEC, - kSignatureLen, SIGNATURE, +REGISTER_ARC_I( + "Ar", "ar a deb lib", 0, 0xEC, + kSignature, 0, 0, - CreateArc }; - -REGISTER_ARC(Ar) + NULL) }} diff --git a/CPP/7zip/Archive/Archive.def b/CPP/7zip/Archive/Archive.def index 55b530b2..145516d7 100644 --- a/CPP/7zip/Archive/Archive.def +++ b/CPP/7zip/Archive/Archive.def @@ -1,6 +1,12 @@ EXPORTS CreateObject PRIVATE + GetHandlerProperty PRIVATE GetNumberOfFormats PRIVATE GetHandlerProperty2 PRIVATE - CreateObject PRIVATE + GetIsArc PRIVATE + + SetCodecs PRIVATE + + SetLargePageMode PRIVATE + SetCaseSensitive PRIVATE diff --git a/CPP/7zip/Archive/Archive2.def b/CPP/7zip/Archive/Archive2.def index 66feb41d..c7582742 100644 --- a/CPP/7zip/Archive/Archive2.def +++ b/CPP/7zip/Archive/Archive2.def @@ -1,11 +1,19 @@ EXPORTS CreateObject PRIVATE + GetHandlerProperty PRIVATE GetNumberOfFormats PRIVATE GetHandlerProperty2 PRIVATE + GetIsArc PRIVATE + GetNumberOfMethods PRIVATE GetMethodProperty PRIVATE + CreateDecoder PRIVATE + CreateEncoder PRIVATE + GetHashers PRIVATE + + SetCodecs 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 0a520413..28e9946d 100644 --- a/CPP/7zip/Archive/ArchiveExports.cpp +++ b/CPP/7zip/Archive/ArchiveExports.cpp @@ -22,17 +22,19 @@ void RegisterArc(const CArcInfo *arcInfo) throw() 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_NumArcs++; + g_Arcs[g_NumArcs++] = arcInfo; } } DEFINE_GUID(CLSID_CArchiveHandler, -0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00); + k_7zip_GUID_Data1, + k_7zip_GUID_Data2, + k_7zip_GUID_Data3_Common, + 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00); #define CLS_ARC_ID_ITEM(cls) ((cls).Data4[5]) -static inline HRESULT SetPropString(const char *s, unsigned size, PROPVARIANT *value) +static inline HRESULT SetPropStrFromBin(const char *s, unsigned size, PROPVARIANT *value) { if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != 0) value->vt = VT_BSTR; @@ -41,18 +43,18 @@ static inline HRESULT SetPropString(const char *s, unsigned size, PROPVARIANT *v static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value) { - return SetPropString((const char *)&guid, sizeof(GUID), value); + return SetPropStrFromBin((const char *)&guid, sizeof(guid), value); } -int FindFormatCalssId(const GUID *clsID) +int FindFormatCalssId(const GUID *clsid) { - GUID cls = *clsID; + GUID cls = *clsid; CLS_ARC_ID_ITEM(cls) = 0; if (cls != CLSID_CArchiveHandler) return -1; - Byte id = CLS_ARC_ID_ITEM(*clsID); + Byte id = CLS_ARC_ID_ITEM(*clsid); for (unsigned i = 0; i < g_NumArcs; i++) - if (g_Arcs[i]->ClassId == id) + if (g_Arcs[i]->Id == id) return (int)i; return -1; } @@ -101,7 +103,7 @@ STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value case NArchive::NHandlerPropID::kClassID: { GUID clsId = CLSID_CArchiveHandler; - CLS_ARC_ID_ITEM(clsId) = arc.ClassId; + CLS_ARC_ID_ITEM(clsId) = arc.Id; return SetPropGUID(clsId, value); } case NArchive::NHandlerPropID::kExtension: if (arc.Ext) prop = arc.Ext; break; @@ -115,12 +117,12 @@ STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value // 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); + if (arc.SignatureSize != 0 && !arc.IsMultiSignature()) + return SetPropStrFromBin((const char *)arc.Signature, arc.SignatureSize, value); break; case NArchive::NHandlerPropID::kMultiSignature: - if (arc.IsMultiSignature()) - return SetPropString((const char *)arc.Signature, arc.SignatureSize, value); + if (arc.SignatureSize != 0 && arc.IsMultiSignature()) + return SetPropStrFromBin((const char *)arc.Signature, arc.SignatureSize, value); break; } prop.Detach(value); diff --git a/CPP/7zip/Archive/ArjHandler.cpp b/CPP/7zip/Archive/ArjHandler.cpp index 737b8fc9..90819753 100644 --- a/CPP/7zip/Archive/ArjHandler.cpp +++ b/CPP/7zip/Archive/ArjHandler.cpp @@ -17,13 +17,180 @@ #include "../Common/StreamObjects.h" #include "../Common/StreamUtils.h" -#include "../Compress/ArjDecoder1.h" -#include "../Compress/ArjDecoder2.h" #include "../Compress/CopyCoder.h" +#include "../Compress/LzhDecoder.h" #include "Common/ItemNameUtils.h" #include "Common/OutStreamWithCRC.h" +namespace NCompress { +namespace NArj { +namespace NDecoder { + +static const unsigned kMatchMinLen = 3; + +static const UInt32 kWindowSize = 1 << 15; // must be >= (1 << 14) + +class CCoder: + public ICompressCoder, + public CMyUnknownImp +{ + CLzOutWindow _outWindow; + NBitm::CDecoder<CInBuffer> _inBitStream; + + class CCoderReleaser + { + CCoder *_coder; + public: + CCoderReleaser(CCoder *coder): _coder(coder) {} + void Disable() { _coder = NULL; } + ~CCoderReleaser() { if (_coder) _coder->_outWindow.Flush(); } + }; + friend class CCoderReleaser; + + HRESULT CodeReal(UInt64 outSize, ICompressProgressInfo *progress); +public: + MY_UNKNOWN_IMP + + bool FinishMode; + CCoder(): FinishMode(false) {} + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); } +}; + +HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress) +{ + const UInt32 kStep = 1 << 20; + UInt64 next = 0; + if (rem > kStep && progress) + next = rem - kStep; + + while (rem != 0) + { + if (rem <= next) + { + if (_inBitStream.ExtraBitsWereRead()) + return S_FALSE; + + UInt64 packSize = _inBitStream.GetProcessedSize(); + UInt64 pos = _outWindow.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &pos)); + next = 0; + if (rem > kStep) + next = rem - kStep; + } + + UInt32 len; + + { + const unsigned kNumBits = 7 + 7; + UInt32 val = _inBitStream.GetValue(kNumBits); + + if ((val & (1 << (kNumBits - 1))) == 0) + { + _outWindow.PutByte((Byte)(val >> 5)); + _inBitStream.MovePos(1 + 8); + rem--; + continue; + } + + UInt32 mask = 1 << (kNumBits - 2); + unsigned w; + + for (w = 1; w < 7; w++, mask >>= 1) + if ((val & mask) == 0) + break; + + unsigned readBits = (w != 7 ? 1 : 0); + readBits += w + w; + len = (1 << w) - 1 + kMatchMinLen - 1 + + (((val >> (kNumBits - readBits)) & ((1 << w) - 1))); + _inBitStream.MovePos(readBits); + } + + { + const unsigned kNumBits = 4 + 13; + UInt32 val = _inBitStream.GetValue(kNumBits); + + unsigned readBits = 1; + unsigned w; + + if ((val & ((UInt32)1 << 16)) == 0) w = 9; + else if ((val & ((UInt32)1 << 15)) == 0) w = 10; + else if ((val & ((UInt32)1 << 14)) == 0) w = 11; + else if ((val & ((UInt32)1 << 13)) == 0) w = 12; + else { w = 13; readBits = 0; } + + readBits += w + w - 9; + + UInt32 dist = ((UInt32)1 << w) - (1 << 9) + + (((val >> (kNumBits - readBits)) & ((1 << w) - 1))); + _inBitStream.MovePos(readBits); + + if (len > rem) + len = (UInt32)rem; + + if (!_outWindow.CopyBlock(dist, len)) + return S_FALSE; + rem -= len; + } + } + + if (FinishMode) + { + if (_inBitStream.ReadAlignBits() != 0) + return S_FALSE; + } + + if (_inBitStream.ExtraBitsWereRead()) + return S_FALSE; + + return S_OK; +} + + + +STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try + { + if (!outSize) + return E_INVALIDARG; + + if (!_outWindow.Create(kWindowSize)) + return E_OUTOFMEMORY; + if (!_inBitStream.Create(1 << 17)) + return E_OUTOFMEMORY; + + _outWindow.SetStream(outStream); + _outWindow.Init(false); + _inBitStream.SetStream(inStream); + _inBitStream.Init(); + + CCoderReleaser coderReleaser(this); + HRESULT res; + { + res = CodeReal(*outSize, progress); + if (res != S_OK) + return res; + } + + coderReleaser.Disable(); + return _outWindow.Flush(); + } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +}}} + + + + using namespace NWindows; #define Get16(p) GetUi16(p) @@ -95,7 +262,7 @@ namespace NHostOS }; } -static const char *kHostOS[] = +static const char * const kHostOS[] = { "MSDOS" , "PRIMOS" @@ -164,10 +331,10 @@ API_FUNC_static_IsArc IsArc_Arj(const Byte *p, size_t size) static HRESULT ReadString(const Byte *p, unsigned &size, AString &res) { - for (unsigned i = 0; i < size;) + unsigned num = size; + for (unsigned i = 0; i < num;) { - char c = (char)p[i++]; - if (c == 0) + if (p[i++] == 0) { size = i; res = (const char *)p; @@ -656,15 +823,19 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { const CItem &item = _items[allFilesMode ? i : indices[i]]; totalUnpacked += item.Size; - totalPacked += item.PackSize; + // totalPacked += item.PackSize; } extractCallback->SetTotal(totalUnpacked); totalUnpacked = totalPacked = 0; UInt64 curUnpacked, curPacked; - CMyComPtr<ICompressCoder> arj1Decoder; - CMyComPtr<ICompressCoder> arj2Decoder; + NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = NULL; + CMyComPtr<ICompressCoder> lzhDecoder; + + NCompress::NArj::NDecoder::CCoder *arjDecoderSpec = NULL; + CMyComPtr<ICompressCoder> arjDecoder; + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; @@ -741,22 +912,37 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, case NCompressionMethod::kCompressed1b: case NCompressionMethod::kCompressed1c: { - if (!arj1Decoder) - arj1Decoder = new NCompress::NArj::NDecoder1::CCoder; - result = arj1Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress); + if (!lzhDecoder) + { + lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder; + lzhDecoder = lzhDecoderSpec; + } + lzhDecoderSpec->FinishMode = true; + const UInt32 kHistorySize = 26624; + lzhDecoderSpec->SetDictSize(kHistorySize); + result = lzhDecoder->Code(inStream, outStream, NULL, &curUnpacked, progress); + if (result == S_OK && lzhDecoderSpec->GetInputProcessedSize() != item.PackSize) + result = S_FALSE; break; } case NCompressionMethod::kCompressed2: { - if (!arj2Decoder) - arj2Decoder = new NCompress::NArj::NDecoder2::CCoder; - result = arj2Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress); + if (!arjDecoder) + { + arjDecoderSpec = new NCompress::NArj::NDecoder::CCoder; + arjDecoder = arjDecoderSpec; + } + arjDecoderSpec->FinishMode = true; + result = arjDecoder->Code(inStream, outStream, NULL, &curUnpacked, progress); + if (result == S_OK && arjDecoderSpec->GetInputProcessedSize() != item.PackSize) + result = S_FALSE; break; } default: opRes = NExtract::NOperationResult::kUnsupportedMethod; } } + if (opRes == NExtract::NOperationResult::kOK) { if (result == S_FALSE) @@ -769,23 +955,23 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, NExtract::NOperationResult::kCRCError; } } + outStream.Release(); RINOK(extractCallback->SetOperationResult(opRes)); } } + return S_OK; COM_TRY_END } -IMP_CreateArcIn +static const Byte k_Signature[] = { kSig0, kSig1 }; -static CArcInfo g_ArcInfo = - { "Arj", "arj", 0, 4, - 2, { kSig0, kSig1 }, +REGISTER_ARC_I( + "Arj", "arj", 0, 4, + k_Signature, 0, 0, - CreateArc, NULL, IsArc_Arj }; - -REGISTER_ARC(Arj) + IsArc_Arj) }} diff --git a/CPP/7zip/Archive/Bz2Handler.cpp b/CPP/7zip/Archive/Bz2Handler.cpp index a49e8293..d1d5f727 100644 --- a/CPP/7zip/Archive/Bz2Handler.cpp +++ b/CPP/7zip/Archive/Bz2Handler.cpp @@ -56,7 +56,7 @@ public: INTERFACE_IInArchive(;) INTERFACE_IOutArchive(;) STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); CHandler() { } }; @@ -367,6 +367,8 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) { + COM_TRY_BEGIN + if (numItems != 1) return E_INVALIDARG; @@ -381,13 +383,9 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)); - if (prop.vt == VT_BOOL) - { - if (prop.boolVal != VARIANT_FALSE) + if (prop.vt != VT_EMPTY) + if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE) return E_INVALIDARG; - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; } } @@ -403,28 +401,43 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt } return UpdateArchive(size, outStream, _props, updateCallback); } + if (indexInArchive != 0) return E_INVALIDARG; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(updateCallback, true); + + CMyComPtr<IArchiveUpdateCallbackFile> opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, 0, + NUpdateNotifyOp::kReplicate)) + } + if (_stream) RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - return NCompress::CopyStream(_stream, outStream, NULL); + + return NCompress::CopyStream(_stream, outStream, progress); + + COM_TRY_END } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { return _props.SetProperties(names, values, numProps); } -IMP_CreateArcIn -IMP_CreateArcOut +static const Byte k_Signature[] = { 'B', 'Z', 'h' }; -static CArcInfo g_ArcInfo = - { "bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2, - 3, { 'B', 'Z', 'h' }, +REGISTER_ARC_IO( + "bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2, + k_Signature, 0, NArcInfoFlags::kKeepName, - REF_CreateArc_Pair, IsArc_BZip2 }; - -REGISTER_ARC(BZip2) + IsArc_BZip2) }} diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp index cebec610..625276f3 100644 --- a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp +++ b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp @@ -75,11 +75,14 @@ HRESULT CCabBlockInStream::PreRead(ISequentialInStream *stream, UInt32 &packSize STDMETHODIMP CCabBlockInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { - UInt32 rem = _size - _pos; - if (size > rem) - size = rem; - memcpy(data, _buf + _pos, size); - _pos += size; + if (size != 0) + { + 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/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp index 22bc93a0..4235ec34 100644 --- a/CPP/7zip/Archive/Cab/CabHandler.cpp +++ b/CPP/7zip/Archive/Cab/CabHandler.cpp @@ -71,7 +71,7 @@ static const Byte kArcProps[] = IMP_IInArchive_Props IMP_IInArchive_ArcProps -static const char *kMethods[] = +static const char * const kMethods[] = { "None" , "MSZip" @@ -124,17 +124,19 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } } } + AString s; + for (unsigned i = 0; i < kNumMethodsMax; i++) { if ((mask & (1 << i)) == 0) continue; - if (!s.IsEmpty()) - s += ' '; + s.Add_Space_if_NotEmpty(); char temp[kMethodNameBufSize]; SetMethodName(temp, i, params[i == NHeader::NMethod::kQuantum ? 0 : 1]); s += temp; } + prop = s; break; } @@ -466,8 +468,8 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, return result; if (!_errorMessage.IsEmpty()) - _errorMessage += L"\n"; - _errorMessage += L"Can't open volume: "; + _errorMessage.Add_LF(); + _errorMessage.AddAscii("Can't open volume: "); _errorMessage += fullName; if (prevChecked) @@ -528,7 +530,7 @@ private: Byte *TempBuf; UInt32 TempBufSize; - int NumIdenticalFiles; + unsigned NumIdenticalFiles; bool TempBufMode; UInt32 m_BufStartFolderOffset; @@ -619,8 +621,9 @@ 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; + unsigned numExtractItems = 0; unsigned curIndex; + for (curIndex = m_CurrentIndex; curIndex < m_ExtractStatuses->Size(); curIndex++) { const CMvItem &mvItem2 = m_Database->Items[m_StartIndex + curIndex]; @@ -632,10 +635,12 @@ HRESULT CFolderOutStream::OpenFile() if (!m_TestMode && (*m_ExtractStatuses)[curIndex]) numExtractItems++; } + NumIdenticalFiles = (curIndex - m_CurrentIndex); if (NumIdenticalFiles == 0) NumIdenticalFiles = 1; TempBufMode = false; + if (numExtractItems > 1) { if (!TempBuf || item.Size > TempBufSize) @@ -699,7 +704,7 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe { COM_TRY_BEGIN UInt32 realProcessed = 0; - if (processedSize != NULL) + if (processedSize) *processedSize = 0; while (size != 0) { @@ -707,7 +712,7 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe { UInt32 numBytesToWrite = MyMin(m_RemainFileSize, size); HRESULT res = S_OK; - if (numBytesToWrite > 0) + if (numBytesToWrite != 0) { if (!isOK) m_IsOk = false; @@ -721,7 +726,7 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe memcpy(TempBuf + (m_PosInFolder - m_BufStartFolderOffset), data, numBytesToWrite); } realProcessed += numBytesToWrite; - if (processedSize != NULL) + if (processedSize) *processedSize = realProcessed; data = (const void *)((const Byte *)data + numBytesToWrite); size -= numBytesToWrite; @@ -773,7 +778,7 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe { UInt32 numBytesToWrite = MyMin(fileOffset - (UInt32)m_PosInFolder, size); realProcessed += numBytesToWrite; - if (processedSize != NULL) + if (processedSize) *processedSize = realProcessed; data = (const void *)((const Byte *)data + numBytesToWrite); size -= numBytesToWrite; @@ -799,24 +804,24 @@ STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *proc HRESULT CFolderOutStream::FlushCorrupted() { - const UInt32 kBufferSize = (1 << 10); - Byte buffer[kBufferSize]; - for (int i = 0; i < kBufferSize; i++) - buffer[i] = 0; + const unsigned kBufSize = (1 << 10); + Byte buf[kBufSize]; + for (unsigned i = 0; i < kBufSize; i++) + buf[i] = 0; for (;;) { UInt64 remain = GetRemain(); if (remain == 0) return S_OK; - UInt32 size = (UInt32)MyMin(remain, (UInt64)kBufferSize); + UInt32 size = (remain < kBufSize ? (UInt32)remain : (UInt32)kBufSize); UInt32 processedSizeLocal = 0; - RINOK(Write2(buffer, size, &processedSizeLocal, false)); + RINOK(Write2(buf, size, &processedSizeLocal, false)); } } HRESULT CFolderOutStream::Unsupported() { - while(m_CurrentIndex < m_ExtractStatuses->Size()) + while (m_CurrentIndex < m_ExtractStatuses->Size()) { HRESULT result = OpenFile(); if (result != S_FALSE && result != S_OK) @@ -844,9 +849,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt32 i; int lastFolder = -2; UInt64 lastFolderSize = 0; - for(i = 0; i < numItems; i++) + + for (i = 0; i < numItems; i++) { - int index = allFilesMode ? i : indices[i]; + unsigned index = allFilesMode ? i : indices[i]; const CMvItem &mvItem = m_Database.Items[index]; const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; if (item.IsDir()) @@ -857,6 +863,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, lastFolder = folderIndex; lastFolderSize = item.GetEndOffset(); } + totalUnPacked += lastFolderSize; extractCallback->SetTotal(totalUnPacked); @@ -887,9 +894,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, return E_OUTOFMEMORY; CRecordVector<bool> extractStatuses; - for(i = 0; i < numItems;) + + for (i = 0; i < numItems;) { - int index = allFilesMode ? i : indices[i]; + unsigned index = allFilesMode ? i : indices[i]; const CMvItem &mvItem = m_Database.Items[index]; const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; @@ -909,7 +917,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); continue; } + int folderIndex = m_Database.GetFolderIndex(&mvItem); + if (folderIndex < 0) { // If we need previous archive @@ -923,17 +933,19 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError)); continue; } - int startIndex2 = m_Database.FolderStartFileIndex[folderIndex]; - int startIndex = startIndex2; + + unsigned startIndex2 = m_Database.FolderStartFileIndex[folderIndex]; + unsigned startIndex = startIndex2; extractStatuses.Clear(); for (; startIndex < index; startIndex++) extractStatuses.Add(false); extractStatuses.Add(true); startIndex++; UInt64 curUnpack = item.GetEndOffset(); + for (; i < numItems; i++) { - int indexNext = allFilesMode ? i : indices[i]; + unsigned indexNext = allFilesMode ? i : indices[i]; const CMvItem &mvItem = m_Database.Items[indexNext]; const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; if (item.IsDir()) @@ -963,6 +975,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, cabBlockInStreamSpec->MsZip = false; HRESULT res = S_OK; + switch (folder.GetMethod()) { case NHeader::NMethod::kNone: @@ -1009,7 +1022,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, int locFolderIndex = item.GetFolderIndex(db.Folders.Size()); bool keepHistory = false; bool keepInputBuffer = false; - for (UInt32 f = 0; cabFolderOutStream->GetRemain() != 0;) + + for (UInt32 bl = 0; cabFolderOutStream->GetRemain() != 0;) { if (volIndex >= m_Database.Volumes.Size()) { @@ -1019,19 +1033,32 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, const CDatabaseEx &db = m_Database.Volumes[volIndex]; const CFolder &folder = db.Folders[locFolderIndex]; - if (f == 0) + + if (bl == 0) { cabBlockInStreamSpec->ReservedSize = db.ArcInfo.GetDataBlockReserveSize(); RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL)); } - if (f == folder.NumDataBlocks) + + if (bl == folder.NumDataBlocks) { - volIndex++; - locFolderIndex = 0; - f = 0; - continue; + /* + CFolder::NumDataBlocks (CFFOLDER::cCFData in CAB specification) is 16-bit. + But there are some big CAB archives from MS that contain more + than (0xFFFF) CFDATA blocks in folder. + Old cab extracting software can show error (or ask next volume) + but cab extracting library in new Windows ignores this error. + 15.00 : We also try to ignore such error, if archive is not multi-volume. + */ + if (m_Database.Volumes.Size() > 1) + { + volIndex++; + locFolderIndex = 0; + bl = 0; + continue; + } } - f++; + bl++; if (!keepInputBuffer) cabBlockInStreamSpec->InitForNewBlock(); @@ -1059,7 +1086,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, unpackRemain = kBlockSizeMax; if (unpackRemain > unpackSize) unpackRemain = unpackSize; - + switch (folder.GetMethod()) { case NHeader::NMethod::kNone: @@ -1092,14 +1119,17 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; } + if (res != S_OK) { if (res != S_FALSE) RINOK(res); break; } + keepHistory = true; } + if (res == S_OK) { RINOK(cabFolderOutStream->WriteEmptyFiles()); @@ -1111,6 +1141,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } totalUnPacked += curUnpack; } + return S_OK; COM_TRY_END } diff --git a/CPP/7zip/Archive/Cab/CabHeader.cpp b/CPP/7zip/Archive/Cab/CabHeader.cpp index 0cba1b0b..370a2f1e 100644 --- a/CPP/7zip/Archive/Cab/CabHeader.cpp +++ b/CPP/7zip/Archive/Cab/CabHeader.cpp @@ -8,8 +8,8 @@ namespace NArchive { namespace NCab { namespace NHeader { -Byte kMarker[kMarkerSize] = {'M', 'S', 'C', 'F', 0, 0, 0, 0 }; +const Byte kMarker[kMarkerSize] = {'M', 'S', 'C', 'F', 0, 0, 0, 0 }; -// struct CSignatureInitializer { CSignatureInitializer() { kMarker[0]--; }; } g_SignatureInitializer; +// struct CSignatureInitializer { CSignatureInitializer() { kMarker[0]--; } } g_SignatureInitializer; }}} diff --git a/CPP/7zip/Archive/Cab/CabHeader.h b/CPP/7zip/Archive/Cab/CabHeader.h index 9ec0760a..2f2bd109 100644 --- a/CPP/7zip/Archive/Cab/CabHeader.h +++ b/CPP/7zip/Archive/Cab/CabHeader.h @@ -1,4 +1,4 @@ -// Archive/Cab/Header.h +// Archive/CabHeader.h #ifndef __ARCHIVE_CAB_HEADER_H #define __ARCHIVE_CAB_HEADER_H @@ -10,7 +10,7 @@ namespace NCab { namespace NHeader { const unsigned kMarkerSize = 8; -extern Byte kMarker[kMarkerSize]; +extern const Byte kMarker[kMarkerSize]; namespace NArcFlags { diff --git a/CPP/7zip/Archive/Cab/CabIn.cpp b/CPP/7zip/Archive/Cab/CabIn.cpp index c499f05f..a72e05f7 100644 --- a/CPP/7zip/Archive/Cab/CabIn.cpp +++ b/CPP/7zip/Archive/Cab/CabIn.cpp @@ -40,8 +40,7 @@ void CInArchive::ReadName(AString &s) throw CUnexpectedEndException(); if (b == 0) { - memcpy(s.GetBuffer((unsigned)i), _tempBuf, i); - s.ReleaseBuffer((unsigned)i); + s.SetFrom((const char *)(const Byte *)_tempBuf, (unsigned)i); return; } if (_tempBuf.Size() == i) diff --git a/CPP/7zip/Archive/Cab/CabIn.h b/CPP/7zip/Archive/Cab/CabIn.h index 4fdab77b..baeeb7b2 100644 --- a/CPP/7zip/Archive/Cab/CabIn.h +++ b/CPP/7zip/Archive/Cab/CabIn.h @@ -17,6 +17,12 @@ struct COtherArc { AString FileName; AString DiskName; + + void Clear() + { + FileName.Empty(); + DiskName.Empty(); + } }; struct CArchInfo @@ -43,7 +49,9 @@ struct CArchInfo CArchInfo() { - Clear(); + PerCabinet_AreaSize = 0; + PerFolder_AreaSize = 0; + PerDataBlock_AreaSize = 0; } void Clear() @@ -51,6 +59,9 @@ struct CArchInfo PerCabinet_AreaSize = 0; PerFolder_AreaSize = 0; PerDataBlock_AreaSize = 0; + + PrevArc.Clear(); + NextArc.Clear(); } }; diff --git a/CPP/7zip/Archive/Cab/CabItem.h b/CPP/7zip/Archive/Cab/CabItem.h index eda62bda..9b513202 100644 --- a/CPP/7zip/Archive/Cab/CabItem.h +++ b/CPP/7zip/Archive/Cab/CabItem.h @@ -51,7 +51,7 @@ struct CItem FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext; } - int GetFolderIndex(int numFolders) const + int GetFolderIndex(unsigned numFolders) const { if (ContinuedFromPrev()) return 0; diff --git a/CPP/7zip/Archive/Cab/CabRegister.cpp b/CPP/7zip/Archive/Cab/CabRegister.cpp index acad4c4a..0b5cc93a 100644 --- a/CPP/7zip/Archive/Cab/CabRegister.cpp +++ b/CPP/7zip/Archive/Cab/CabRegister.cpp @@ -9,15 +9,11 @@ namespace NArchive { namespace NCab { -IMP_CreateArcIn - -static CArcInfo g_ArcInfo = - { "Cab", "cab", 0, 8, - 8, { 'M', 'S', 'C', 'F', 0, 0, 0, 0 }, +REGISTER_ARC_I( + "Cab", "cab", 0, 8, + NHeader::kMarker, 0, NArcInfoFlags::kFindSignature, - CreateArc }; - -REGISTER_ARC(Cab) + NULL) }} diff --git a/CPP/7zip/Archive/Chm/ChmHandler.cpp b/CPP/7zip/Archive/Chm/ChmHandler.cpp index c67ded28..3035ef9e 100644 --- a/CPP/7zip/Archive/Chm/ChmHandler.cpp +++ b/CPP/7zip/Archive/Chm/ChmHandler.cpp @@ -123,15 +123,16 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidPath: { UString us; - if (ConvertUTF8ToUnicode(item.Name, us)) + // if ( + ConvertUTF8ToUnicode(item.Name, us); { if (!m_Database.LowLevel) { - if (us.Len() > 1) - if (us[0] == L'/') - us.Delete(0); + if (us.Len() > 1 && us[0] == L'/') + us.Delete(0); } - prop = NItemName::GetOSName2(us); + NItemName::ConvertToOSName2(us); + prop = us; } break; } @@ -141,7 +142,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { if (!item.IsDir()) if (item.Section == 0) - prop = L"Copy"; + prop = "Copy"; else if (item.Section < m_Database.Sections.Size()) prop = m_Database.Sections[(int)item.Section].GetMethodName(); break; @@ -734,30 +735,30 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) namespace NChm { -IMP_CreateArcIn_2(CHandler(false)) +static const Byte k_Signature[] = { 'I', 'T', 'S', 'F', 3, 0, 0, 0, 0x60, 0, 0, 0 }; -static CArcInfo g_ArcInfo = - { "Chm", "chm chi chq chw", 0, 0xE9, - 12, { 'I', 'T', 'S', 'F', 3, 0, 0, 0, 0x60, 0, 0, 0 }, +REGISTER_ARC_I_CLS( + CHandler(false), + "Chm", "chm chi chq chw", 0, 0xE9, + k_Signature, 0, 0, - CreateArc }; + NULL) -REGISTER_ARC(Chm) } namespace NHxs { -IMP_CreateArcIn_2(CHandler(true)) +static const Byte k_Signature[] = { 'I', 'T', 'O', 'L', 'I', 'T', 'L', 'S', 1, 0, 0, 0, 0x28, 0, 0, 0 }; -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 }, +REGISTER_ARC_I_CLS( + CHandler(true), + "Hxs", "hxs hxi hxr hxq hxw lit", 0, 0xCE, + k_Signature, 0, NArcInfoFlags::kFindSignature, - CreateArc }; + NULL) -REGISTER_ARC(Hxs) } }} diff --git a/CPP/7zip/Archive/Chm/ChmIn.cpp b/CPP/7zip/Archive/Chm/ChmIn.cpp index 9b0bb199..e8da227d 100644 --- a/CPP/7zip/Archive/Chm/ChmIn.cpp +++ b/CPP/7zip/Archive/Chm/ChmIn.cpp @@ -107,10 +107,10 @@ UString CMethodInfo::GetName() const UString s; if (IsLzx()) { - s = L"LZX:"; - wchar_t temp[16]; + s.SetFromAscii("LZX:"); + char temp[16]; ConvertUInt32ToString(LzxInfo.GetNumDictBits(), temp); - s += temp; + s.AddAscii(temp); } else { @@ -147,12 +147,12 @@ UString CSectionInfo::GetMethodName() const UString temp; if (ConvertUTF8ToUnicode(Name, temp)) s += temp; - s += L": "; + s.AddAscii(": "); } FOR_VECTOR (i, Methods) { if (i != 0) - s += L' '; + s.Add_Space(); s += Methods[i].GetName(); } return s; @@ -584,9 +584,9 @@ HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) AString s; ConvertUnicodeToUTF8(name, s); Byte b = ReadByte(); - s += ' '; + s.Add_Space(); PrintByte(b, s); - s += ' '; + s.Add_Space(); UInt64 len = ReadEncInt(); // then number of items ? // then length ? @@ -641,7 +641,10 @@ static const char *kTransformList = "List"; static AString GetSectionPrefix(const AString &name) { - return AString(kStorage) + name + AString("/"); + AString s = kStorage; + s += name; + s += '/'; + return s; } #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } @@ -721,8 +724,8 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) ReadUString(nameLen, name); if (ReadUInt16() != 0) return S_FALSE; - if (!ConvertUnicodeToUTF8(name, section.Name)) - return S_FALSE; + ConvertUnicodeToUTF8(name, section.Name); + // if (!ConvertUnicodeToUTF8(name, section.Name)) return S_FALSE; database.Sections.Add(section); } } diff --git a/CPP/7zip/Archive/Chm/ChmIn.h b/CPP/7zip/Archive/Chm/ChmIn.h index 70764ab9..c4ce83ed 100644 --- a/CPP/7zip/Archive/Chm/ChmIn.h +++ b/CPP/7zip/Archive/Chm/ChmIn.h @@ -120,10 +120,10 @@ struct CLzxInfo return 0; } - UInt64 GetFolderSize() const { return ResetTable.BlockSize * ResetInterval; }; - UInt64 GetFolder(UInt64 offset) const { return offset / GetFolderSize(); }; - UInt64 GetFolderPos(UInt64 folderIndex) const { return folderIndex * GetFolderSize(); }; - UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex * ResetInterval; }; + UInt64 GetFolderSize() const { return ResetTable.BlockSize * ResetInterval; } + UInt64 GetFolder(UInt64 offset) const { return offset / GetFolderSize(); } + UInt64 GetFolderPos(UInt64 folderIndex) const { return folderIndex * GetFolderSize(); } + UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex * ResetInterval; } bool GetOffsetOfFolder(UInt64 folderIndex, UInt64 &offset) const { UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex); diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp index fc686b94..9cfd40cc 100644 --- a/CPP/7zip/Archive/ComHandler.cpp +++ b/CPP/7zip/Archive/ComHandler.cpp @@ -27,8 +27,7 @@ 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; +static const Byte kSignature[] = SIGNATURE; enum EType { @@ -40,7 +39,7 @@ enum EType k_Type_Xls, }; -static const char *kExtensions[] = +static const char * const kExtensions[] = { "compound" , "msi" @@ -240,8 +239,8 @@ HRESULT CDatabase::AddNode(int parent, UInt32 did) return S_OK; } -static const char kCharOpenBracket = '['; -static const char kCharCloseBracket = ']'; +static const wchar_t kCharOpenBracket = L'['; +static const wchar_t kCharCloseBracket = L']'; static UString CompoundNameToFileName(const UString &s) { @@ -263,23 +262,25 @@ static UString CompoundNameToFileName(const UString &s) return res; } -static char g_MsiChars[] = +static const char k_Msi_Chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._"; -static const wchar_t *kMsi_ID = L""; // L"{msi}"; +// static const char *k_Msi_ID = ""; // "{msi}"; +static const wchar_t k_Msi_SpecChar = L'!'; + +static const unsigned k_Msi_NumBits = 6; +static const unsigned k_Msi_NumChars = 1 << k_Msi_NumBits; +static const unsigned k_Msi_CharMask = k_Msi_NumChars - 1; +static const unsigned k_Msi_StartUnicodeChar = 0x3800; +static const unsigned k_Msi_UnicodeRange = k_Msi_NumChars * (k_Msi_NumChars + 1); -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; + c >= k_Msi_StartUnicodeChar && + c <= k_Msi_StartUnicodeChar + k_Msi_UnicodeRange; } static bool AreEqualNames(const Byte *rawName, const char *asciiName) @@ -296,30 +297,32 @@ static bool AreEqualNames(const Byte *rawName, const char *asciiName) return false; } -static bool CompoundMsiNameToFileName(const UString &name, UString &resultName) +static bool CompoundMsiNameToFileName(const UString &name, UString &res) { - resultName.Empty(); + res.Empty(); for (unsigned i = 0; i < name.Len(); i++) { wchar_t c = name[i]; - if (c < kMsiStartUnicodeChar || c > kMsiStartUnicodeChar + kMsiUnicodeRange) + if (c < k_Msi_StartUnicodeChar || c > k_Msi_StartUnicodeChar + k_Msi_UnicodeRange) return false; + /* if (i == 0) - resultName += kMsi_ID; - c -= kMsiStartUnicodeChar; + res += k_Msi_ID; + */ + c -= k_Msi_StartUnicodeChar; - UInt32 c0 = c & kMsiCharMask; - UInt32 c1 = c >> kMsiNumBits; + unsigned c0 = (unsigned)c & k_Msi_CharMask; + unsigned c1 = (unsigned)c >> k_Msi_NumBits; - if (c1 <= kMsiNumChars) + if (c1 <= k_Msi_NumChars) { - resultName += (wchar_t)g_MsiChars[c0]; - if (c1 == kMsiNumChars) + res += (wchar_t)(Byte)k_Msi_Chars[c0]; + if (c1 == k_Msi_NumChars) break; - resultName += (wchar_t)g_MsiChars[c1]; + res += (wchar_t)(Byte)k_Msi_Chars[c1]; } else - resultName += L'!'; + res += k_Msi_SpecChar; } return true; } @@ -328,6 +331,7 @@ 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); @@ -335,6 +339,7 @@ static UString ConvertName(const Byte *p, bool &isMsi) break; s += c; } + UString msiName; if (CompoundMsiNameToFileName(s, msiName)) { @@ -416,7 +421,7 @@ HRESULT CDatabase::Open(IInStream *inStream) Byte p[kHeaderSize]; PhySize = kHeaderSize; RINOK(ReadStream_FALSE(inStream, p, kHeaderSize)); - if (memcmp(p, kSignature, kSignatureSize) != 0) + if (memcmp(p, kSignature, ARRAY_SIZE(kSignature)) != 0) return S_FALSE; if (Get16(p + 0x1A) > 4) // majorVer return S_FALSE; @@ -573,11 +578,14 @@ HRESULT CDatabase::Open(IInStream *inStream) continue; bool isMsiName; UString msiName = ConvertName(item.Name, isMsiName); - if (isMsiName && msiName.Len() >= 4 && - MyStringCompareNoCase(msiName.RightPtr(4), L".cab") == 0) + if (isMsiName) { - numCabs++; - MainSubfile = i; + if (msiName.Len() >= 4 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(4), ".cab") + || msiName.Len() >= 3 && msiName[0] != k_Msi_SpecChar && StringsAreEqualNoCase_Ascii(msiName.RightPtr(3), "exe")) + { + numCabs++; + MainSubfile = i; + } } } if (numCabs > 1) @@ -663,7 +671,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) NWindows::NCOM::CPropVariant prop; switch (propID) { - case kpidExtension: prop = kExtensions[_db.Type]; break; + case kpidExtension: prop = kExtensions[(unsigned)_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; @@ -861,15 +869,11 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -IMP_CreateArcIn - -static CArcInfo g_ArcInfo = - { "Compound", "msi msp doc xls ppt", 0, 0xE5, - kSignatureSize, SIGNATURE, +REGISTER_ARC_I( + "Compound", "msi msp doc xls ppt", 0, 0xE5, + kSignature, 0, 0, - CreateArc }; - -REGISTER_ARC(Com) + NULL) }} diff --git a/CPP/7zip/Archive/Common/CoderMixer2.cpp b/CPP/7zip/Archive/Common/CoderMixer2.cpp index 13019d1f..41b5805c 100644 --- a/CPP/7zip/Archive/Common/CoderMixer2.cpp +++ b/CPP/7zip/Archive/Common/CoderMixer2.cpp @@ -4,116 +4,1041 @@ #include "CoderMixer2.h" -namespace NCoderMixer { +#ifdef USE_MIXER_ST -CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo): - _srcBindInfo(srcBindInfo) +STDMETHODIMP CSequentialInStreamCalcSize::Read(void *data, UInt32 size, UInt32 *processedSize) { - srcBindInfo.GetNumStreams(NumSrcInStreams, _numSrcOutStreams); + UInt32 realProcessed = 0; + HRESULT result = S_OK; + if (_stream) + result = _stream->Read(data, size, &realProcessed); + _size += realProcessed; + if (size != 0 && realProcessed == 0) + _wasFinished = true; + if (processedSize) + *processedSize = realProcessed; + return result; +} + - UInt32 j; - _srcInToDestOutMap.ClearAndSetSize(NumSrcInStreams); - DestOutToSrcInMap.ClearAndSetSize(NumSrcInStreams); +STDMETHODIMP COutStreamCalcSize::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + _size += size; + if (processedSize) + *processedSize = size; + return result; +} - for (j = 0; j < NumSrcInStreams; j++) +STDMETHODIMP COutStreamCalcSize::OutStreamFinish() +{ + HRESULT result = S_OK; + if (_stream) { - _srcInToDestOutMap[j] = 0; - DestOutToSrcInMap[j] = 0; + CMyComPtr<IOutStreamFinish> outStreamFinish; + _stream.QueryInterface(IID_IOutStreamFinish, &outStreamFinish); + if (outStreamFinish) + result = outStreamFinish->OutStreamFinish(); } + return result; +} - _srcOutToDestInMap.ClearAndSetSize(_numSrcOutStreams); - _destInToSrcOutMap.ClearAndSetSize(_numSrcOutStreams); +#endif - for (j = 0; j < _numSrcOutStreams; j++) + + + +namespace NCoderMixer2 { + +static void BoolVector_Fill_False(CBoolVector &v, unsigned size) +{ + v.ClearAndSetSize(size); + bool *p = &v[0]; + for (unsigned i = 0; i < size; i++) + p[i] = false; +} + +class CBondsChecks +{ + CBoolVector _coderUsed; + + bool Init(); + bool CheckCoder(unsigned coderIndex); +public: + const CBindInfo *BindInfo; + + bool Check(); +}; + +bool CBondsChecks::CheckCoder(unsigned coderIndex) +{ + const CCoderStreamsInfo &coder = BindInfo->Coders[coderIndex]; + + if (coderIndex >= _coderUsed.Size() || _coderUsed[coderIndex]) + return false; + _coderUsed[coderIndex] = true; + + UInt32 start = BindInfo->Coder_to_Stream[coderIndex]; + + for (unsigned i = 0; i < coder.NumStreams; i++) { - _srcOutToDestInMap[j] = 0; - _destInToSrcOutMap[j] = 0; + UInt32 ind = start + i; + + if (BindInfo->IsStream_in_PackStreams(ind)) + continue; + + int bond = BindInfo->FindBond_for_PackStream(ind); + if (bond < 0) + return false; + if (!CheckCoder(BindInfo->Bonds[bond].UnpackIndex)) + return false; } + + return true; +} + +bool CBondsChecks::Check() +{ + BoolVector_Fill_False(_coderUsed, BindInfo->Coders.Size()); + + if (!CheckCoder(BindInfo->UnpackCoder)) + return false; + + FOR_VECTOR(i, _coderUsed) + if (!_coderUsed[i]) + return false; + + return true; +} + +void CBindInfo::ClearMaps() +{ + Coder_to_Stream.Clear(); + Stream_to_Coder.Clear(); +} - UInt32 destInOffset = 0; - UInt32 destOutOffset = 0; - UInt32 srcInOffset = NumSrcInStreams; - UInt32 srcOutOffset = _numSrcOutStreams; +bool CBindInfo::CalcMapsAndCheck() +{ + ClearMaps(); + + UInt32 numStreams = 0; + + if (Coders.Size() == 0) + return false; + if (Coders.Size() - 1 != Bonds.Size()) + return false; - for (int i = srcBindInfo.Coders.Size() - 1; i >= 0; i--) + FOR_VECTOR(i, Coders) { - const CCoderStreamsInfo &srcCoderInfo = srcBindInfo.Coders[i]; + Coder_to_Stream.Add(numStreams); + + const CCoderStreamsInfo &c = Coders[i]; + + for (unsigned j = 0; j < c.NumStreams; j++) + Stream_to_Coder.Add(i); + + numStreams += c.NumStreams; + } + + if (numStreams != GetNum_Bonds_and_PackStreams()) + return false; + + CBondsChecks bc; + bc.BindInfo = this; + return bc.Check(); +} + + +void CCoder::SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes) +{ + if (unpackSize) + { + UnpackSize = *unpackSize; + UnpackSizePointer = &UnpackSize; + } + else + { + UnpackSize = 0; + UnpackSizePointer = NULL; + } + + PackSizes.ClearAndSetSize((unsigned)NumStreams); + PackSizePointers.ClearAndSetSize((unsigned)NumStreams); + + for (unsigned i = 0; i < NumStreams; i++) + { + if (packSizes && packSizes[i]) + { + PackSizes[i] = *(packSizes[i]); + PackSizePointers[i] = &PackSizes[i]; + } + else + { + PackSizes[i] = 0; + PackSizePointers[i] = NULL; + } + } +} + +bool CMixer::Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex) +{ + if (coderIndex == _bi.UnpackCoder) + return true; + + int bond = _bi.FindBond_for_UnpackStream(coderIndex); + if (bond < 0) + throw 20150213; + + /* + UInt32 coderIndex, coderStreamIndex; + _bi.GetCoder_for_Stream(_bi.Bonds[bond].PackIndex, coderIndex, coderStreamIndex); + */ + UInt32 nextCoder = _bi.Stream_to_Coder[_bi.Bonds[bond].PackIndex]; + + if (!IsFilter_Vector[nextCoder]) + return false; + + return Is_UnpackSize_Correct_for_Coder(nextCoder); +} + +bool CMixer::Is_PackSize_Correct_for_Stream(UInt32 streamIndex) +{ + if (_bi.IsStream_in_PackStreams(streamIndex)) + return true; + + int bond = _bi.FindBond_for_PackStream(streamIndex); + if (bond < 0) + throw 20150213; + + UInt32 nextCoder = _bi.Bonds[bond].UnpackIndex; + + if (!IsFilter_Vector[nextCoder]) + return false; + + return Is_PackSize_Correct_for_Coder(nextCoder); +} + +bool CMixer::Is_PackSize_Correct_for_Coder(UInt32 coderIndex) +{ + UInt32 startIndex = _bi.Coder_to_Stream[coderIndex]; + UInt32 numStreams = _bi.Coders[coderIndex].NumStreams; + for (UInt32 i = 0; i < numStreams; i++) + if (!Is_PackSize_Correct_for_Stream(startIndex + i)) + return false; + return true; +} + +bool CMixer::IsThere_ExternalCoder_in_PackTree(UInt32 coderIndex) +{ + if (IsExternal_Vector[coderIndex]) + return true; + UInt32 startIndex = _bi.Coder_to_Stream[coderIndex]; + UInt32 numStreams = _bi.Coders[coderIndex].NumStreams; + for (UInt32 i = 0; i < numStreams; i++) + { + UInt32 si = startIndex + i; + if (_bi.IsStream_in_PackStreams(si)) + continue; + + int bond = _bi.FindBond_for_PackStream(si); + if (bond < 0) + throw 20150213; + + if (IsThere_ExternalCoder_in_PackTree(_bi.Bonds[bond].UnpackIndex)) + return true; + } + return false; +} + + + + +#ifdef USE_MIXER_ST + +CMixerST::CMixerST(bool encodeMode): + CMixer(encodeMode) + {} + +CMixerST::~CMixerST() {} + +void CMixerST::AddCoder(const CCreatedCoder &cod) +{ + IsFilter_Vector.Add(cod.IsFilter); + IsExternal_Vector.Add(cod.IsExternal); + // const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()]; + CCoderST &c2 = _coders.AddNew(); + c2.NumStreams = cod.NumStreams; + c2.Coder = cod.Coder; + c2.Coder2 = cod.Coder2; - srcInOffset -= srcCoderInfo.NumInStreams; - srcOutOffset -= srcCoderInfo.NumOutStreams; + /* + if (isFilter) + { + c2.CanRead = true; + c2.CanWrite = true; + } + else + */ + { + IUnknown *unk = (cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2); + { + CMyComPtr<ISequentialInStream> s; + unk->QueryInterface(IID_ISequentialInStream, (void**)&s); + c2.CanRead = (s != NULL); + } + { + CMyComPtr<ISequentialOutStream> s; + unk->QueryInterface(IID_ISequentialOutStream, (void**)&s); + c2.CanWrite = (s != NULL); + } + } +} + +CCoder &CMixerST::GetCoder(unsigned index) +{ + return _coders[index]; +} + +void CMixerST::ReInit() {} + +HRESULT CMixerST::GetInStream2( + ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ + UInt32 outStreamIndex, ISequentialInStream **inStreamRes) +{ + UInt32 coderIndex = outStreamIndex, coderStreamIndex = 0; + + if (EncodeMode) + { + _bi.GetCoder_for_Stream(outStreamIndex, coderIndex, coderStreamIndex); + if (coderStreamIndex != 0) + return E_NOTIMPL; + } + + const CCoder &coder = _coders[coderIndex]; + + CMyComPtr<ISequentialInStream> seqInStream; + coder.QueryInterface(IID_ISequentialInStream, (void **)&seqInStream); + if (!seqInStream) + return E_NOTIMPL; + + UInt32 numInStreams = EncodeMode ? 1 : coder.NumStreams; + UInt32 startIndex = EncodeMode ? coderIndex : _bi.Coder_to_Stream[coderIndex]; + + bool isSet = false; + + if (numInStreams == 1) + { + CMyComPtr<ICompressSetInStream> setStream; + coder.QueryInterface(IID_ICompressSetInStream, (void **)&setStream); + if (setStream) + { + CMyComPtr<ISequentialInStream> seqInStream2; + RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + 0, &seqInStream2)); + RINOK(setStream->SetInStream(seqInStream2)); + isSet = true; + } + } + + if (!isSet && numInStreams != 0) + { + CMyComPtr<ICompressSetInStream2> setStream2; + coder.QueryInterface(IID_ICompressSetInStream2, (void **)&setStream2); + if (!setStream2) + return E_NOTIMPL; - UInt32 j; - for (j = 0; j < srcCoderInfo.NumInStreams; j++, destOutOffset++) + for (UInt32 i = 0; i < numInStreams; i++) + { + CMyComPtr<ISequentialInStream> seqInStream2; + RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + i, &seqInStream2)); + RINOK(setStream2->SetInStream2(i, seqInStream2)); + } + } + + *inStreamRes = seqInStream.Detach(); + return S_OK; +} + + +HRESULT CMixerST::GetInStream( + ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ + UInt32 inStreamIndex, ISequentialInStream **inStreamRes) +{ + CMyComPtr<ISequentialInStream> seqInStream; + + { + int index = -1; + if (EncodeMode) + { + if (_bi.UnpackCoder == inStreamIndex) + index = 0; + } + else + index = _bi.FindStream_in_PackStreams(inStreamIndex); + + if (index >= 0) + { + seqInStream = inStreams[(unsigned)index]; + *inStreamRes = seqInStream.Detach(); + return S_OK; + } + } + + int bond = FindBond_for_Stream( + true, // forInputStream + inStreamIndex); + if (bond < 0) + return E_INVALIDARG; + + RINOK(GetInStream2(inStreams, /* inSizes, */ + _bi.Bonds[bond].Get_OutIndex(EncodeMode), &seqInStream)); + + while (_binderStreams.Size() <= (unsigned)bond) + _binderStreams.AddNew(); + CStBinderStream &bs = _binderStreams[bond]; + + if (bs.StreamRef || bs.InStreamSpec) + return E_NOTIMPL; + + CSequentialInStreamCalcSize *spec = new CSequentialInStreamCalcSize; + bs.StreamRef = spec; + bs.InStreamSpec = spec; + + spec->SetStream(seqInStream); + spec->Init(); + + seqInStream = bs.InStreamSpec; + + *inStreamRes = seqInStream.Detach(); + return S_OK; +} + + +HRESULT CMixerST::GetOutStream( + ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */ + UInt32 outStreamIndex, ISequentialOutStream **outStreamRes) +{ + CMyComPtr<ISequentialOutStream> seqOutStream; + + { + int index = -1; + if (!EncodeMode) + { + if (_bi.UnpackCoder == outStreamIndex) + index = 0; + } + else + index = _bi.FindStream_in_PackStreams(outStreamIndex); + + if (index >= 0) + { + seqOutStream = outStreams[(unsigned)index]; + *outStreamRes = seqOutStream.Detach(); + return S_OK; + } + } + + int bond = FindBond_for_Stream( + false, // forInputStream + outStreamIndex); + if (bond < 0) + return E_INVALIDARG; + + UInt32 inStreamIndex = _bi.Bonds[bond].Get_InIndex(EncodeMode); + + UInt32 coderIndex = inStreamIndex; + UInt32 coderStreamIndex = 0; + + if (!EncodeMode) + _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex); + + CCoder &coder = _coders[coderIndex]; + + /* + if (!coder.Coder) + return E_NOTIMPL; + */ + + coder.QueryInterface(IID_ISequentialOutStream, (void **)&seqOutStream); + if (!seqOutStream) + return E_NOTIMPL; + + UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1; + UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex; + + bool isSet = false; + + if (numOutStreams == 1) + { + CMyComPtr<ICompressSetOutStream> setOutStream; + coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream); + if (setOutStream) + { + CMyComPtr<ISequentialOutStream> seqOutStream2; + RINOK(GetOutStream(outStreams, /* outSizes, */ startIndex + 0, &seqOutStream2)); + RINOK(setOutStream->SetOutStream(seqOutStream2)); + isSet = true; + } + } + + if (!isSet && numOutStreams != 0) + { + return E_NOTIMPL; + /* + CMyComPtr<ICompressSetOutStream2> setStream2; + coder.QueryInterface(IID_ICompressSetOutStream2, (void **)&setStream2); + if (!setStream2) + return E_NOTIMPL; + for (UInt32 i = 0; i < numOutStreams; i++) + { + CMyComPtr<ISequentialOutStream> seqOutStream2; + RINOK(GetOutStream(outStreams, startIndex + i, &seqOutStream2)); + RINOK(setStream2->SetOutStream2(i, seqOutStream2)); + } + */ + } + + while (_binderStreams.Size() <= (unsigned)bond) + _binderStreams.AddNew(); + CStBinderStream &bs = _binderStreams[bond]; + + if (bs.StreamRef || bs.OutStreamSpec) + return E_NOTIMPL; + + COutStreamCalcSize *spec = new COutStreamCalcSize; + bs.StreamRef = (ISequentialOutStream *)spec; + bs.OutStreamSpec = spec; + + spec->SetStream(seqOutStream); + spec->Init(); + + seqOutStream = bs.OutStreamSpec; + + *outStreamRes = seqOutStream.Detach(); + return S_OK; +} + + +static HRESULT GetError(HRESULT res, HRESULT res2) +{ + if (res == res2) + return res; + if (res == S_OK) + return res2; + if (res == k_My_HRESULT_WritingWasCut) + { + if (res2 != S_OK) + return res2; + } + return res; +} + + +HRESULT CMixerST::FinishStream(UInt32 streamIndex) +{ + { + int index = -1; + if (!EncodeMode) { - UInt32 index = srcInOffset + j; - _srcInToDestOutMap[index] = destOutOffset; - DestOutToSrcInMap[destOutOffset] = index; + if (_bi.UnpackCoder == streamIndex) + index = 0; } - for (j = 0; j < srcCoderInfo.NumOutStreams; j++, destInOffset++) + else + index = _bi.FindStream_in_PackStreams(streamIndex); + + if (index >= 0) + return S_OK; + } + + int bond = FindBond_for_Stream( + false, // forInputStream + streamIndex); + if (bond < 0) + return E_INVALIDARG; + + UInt32 inStreamIndex = _bi.Bonds[bond].Get_InIndex(EncodeMode); + + UInt32 coderIndex = inStreamIndex; + UInt32 coderStreamIndex = 0; + if (!EncodeMode) + _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex); + + CCoder &coder = _coders[coderIndex]; + CMyComPtr<IOutStreamFinish> finish; + coder.QueryInterface(IID_IOutStreamFinish, (void **)&finish); + HRESULT res = S_OK; + if (finish) + { + res = finish->OutStreamFinish(); + } + return GetError(res, FinishCoder(coderIndex)); +} + + +HRESULT CMixerST::FinishCoder(UInt32 coderIndex) +{ + CCoder &coder = _coders[coderIndex]; + + UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1; + UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex; + + HRESULT res = S_OK; + for (unsigned i = 0; i < numOutStreams; i++) + res = GetError(res, FinishStream(startIndex + i)); + return res; +} + + +void CMixerST::SelectMainCoder(bool useFirst) +{ + unsigned ci = _bi.UnpackCoder; + + int firstNonFilter = -1; + int firstAllowed = ci; + + for (;;) + { + const CCoderST &coder = _coders[ci]; + // break; + + if (ci != _bi.UnpackCoder) + if (EncodeMode ? !coder.CanWrite : !coder.CanRead) + { + firstAllowed = ci; + firstNonFilter = -2; + } + + if (coder.NumStreams != 1) + break; + + UInt32 st = _bi.Coder_to_Stream[ci]; + if (_bi.IsStream_in_PackStreams(st)) + break; + int bond = _bi.FindBond_for_PackStream(st); + if (bond < 0) + throw 20150213; + + if (EncodeMode ? !coder.CanRead : !coder.CanWrite) + break; + + if (firstNonFilter == -1 && !IsFilter_Vector[ci]) + firstNonFilter = ci; + + ci = _bi.Bonds[bond].UnpackIndex; + } + + if (useFirst) + ci = firstAllowed; + else if (firstNonFilter >= 0) + ci = firstNonFilter; + + MainCoderIndex = ci; +} + + +HRESULT CMixerST::Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, + ICompressProgressInfo *progress) +{ + _binderStreams.Clear(); + unsigned ci = MainCoderIndex; + + const CCoder &mainCoder = _coders[MainCoderIndex]; + + CObjectVector< CMyComPtr<ISequentialInStream> > seqInStreams; + CObjectVector< CMyComPtr<ISequentialOutStream> > seqOutStreams; + + UInt32 numInStreams = EncodeMode ? 1 : mainCoder.NumStreams; + UInt32 numOutStreams = !EncodeMode ? 1 : mainCoder.NumStreams; + + UInt32 startInIndex = EncodeMode ? ci : _bi.Coder_to_Stream[ci]; + UInt32 startOutIndex = !EncodeMode ? ci : _bi.Coder_to_Stream[ci]; + + UInt32 i; + + for (i = 0; i < numInStreams; i++) + { + CMyComPtr<ISequentialInStream> seqInStream; + RINOK(GetInStream(inStreams, /* inSizes, */ startInIndex + i, &seqInStream)); + seqInStreams.Add(seqInStream); + } + + for (i = 0; i < numOutStreams; i++) + { + CMyComPtr<ISequentialOutStream> seqOutStream; + RINOK(GetOutStream(outStreams, /* outSizes, */ startOutIndex + i, &seqOutStream)); + seqOutStreams.Add(seqOutStream); + } + + CRecordVector< ISequentialInStream * > seqInStreamsSpec; + CRecordVector< ISequentialOutStream * > seqOutStreamsSpec; + + for (i = 0; i < numInStreams; i++) + seqInStreamsSpec.Add(seqInStreams[i]); + for (i = 0; i < numOutStreams; i++) + seqOutStreamsSpec.Add(seqOutStreams[i]); + + for (i = 0; i < _coders.Size(); i++) + { + if (i == ci) + continue; + + CCoder &coder = _coders[i]; + + if (EncodeMode) + { + CMyComPtr<ICompressInitEncoder> initEncoder; + coder.QueryInterface(IID_ICompressInitEncoder, (void **)&initEncoder); + if (initEncoder) + RINOK(initEncoder->InitEncoder()); + } + else + { + CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize; + coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize); + if (setOutStreamSize) + RINOK(setOutStreamSize->SetOutStreamSize( + EncodeMode ? coder.PackSizePointers[0] : coder.UnpackSizePointer)); + } + } + + const UInt64 * const *isSizes2 = EncodeMode ? &mainCoder.UnpackSizePointer : &mainCoder.PackSizePointers.Front(); + const UInt64 * const *outSizes2 = EncodeMode ? &mainCoder.PackSizePointers.Front() : &mainCoder.UnpackSizePointer; + + HRESULT res; + if (mainCoder.Coder) + { + res = mainCoder.Coder->Code( + seqInStreamsSpec[0], seqOutStreamsSpec[0], + isSizes2[0], outSizes2[0], + progress); + } + else + { + res = mainCoder.Coder2->Code( + &seqInStreamsSpec.Front(), isSizes2, numInStreams, + &seqOutStreamsSpec.Front(), outSizes2, numOutStreams, + progress); + } + + if (res == k_My_HRESULT_WritingWasCut) + res = S_OK; + + if (res == S_OK || res == S_FALSE) + { + res = GetError(res, FinishCoder(ci)); + } + + for (i = 0; i < _binderStreams.Size(); i++) + { + const CStBinderStream &bs = _binderStreams[i]; + if (bs.InStreamSpec) + bs.InStreamSpec->ReleaseStream(); + else + bs.OutStreamSpec->ReleaseStream(); + } + + if (res == k_My_HRESULT_WritingWasCut) + res = S_OK; + return res; +} + + +HRESULT CMixerST::GetMainUnpackStream( + ISequentialInStream * const *inStreams, + ISequentialInStream **inStreamRes) +{ + CMyComPtr<ISequentialInStream> seqInStream; + + RINOK(GetInStream2(inStreams, /* inSizes, */ + _bi.UnpackCoder, &seqInStream)) + + FOR_VECTOR (i, _coders) + { + CCoder &coder = _coders[i]; + CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize; + coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize); + if (setOutStreamSize) { - UInt32 index = srcOutOffset + j; - _srcOutToDestInMap[index] = destInOffset; - _destInToSrcOutMap[destInOffset] = index; + RINOK(setOutStreamSize->SetOutStreamSize(coder.UnpackSizePointer)); } } + + *inStreamRes = seqInStream.Detach(); + return S_OK; } -void CBindReverseConverter::CreateReverseBindInfo(CBindInfo &destBindInfo) + +UInt64 CMixerST::GetBondStreamSize(unsigned bondIndex) const { - destBindInfo.Coders.ClearAndReserve(_srcBindInfo.Coders.Size()); - destBindInfo.BindPairs.ClearAndReserve(_srcBindInfo.BindPairs.Size()); - destBindInfo.InStreams.ClearAndReserve(_srcBindInfo.OutStreams.Size()); - destBindInfo.OutStreams.ClearAndReserve(_srcBindInfo.InStreams.Size()); + const CStBinderStream &bs = _binderStreams[bondIndex]; + if (bs.InStreamSpec) + return bs.InStreamSpec->GetSize(); + return bs.OutStreamSpec->GetSize(); +} + +#endif + + + + + + +#ifdef USE_MIXER_MT + + +void CCoderMT::Execute() +{ + try + { + Code(NULL); + } + catch(...) + { + Result = E_FAIL; + } +} + +void CCoderMT::Code(ICompressProgressInfo *progress) +{ + unsigned numInStreams = EncodeMode ? 1 : NumStreams; + unsigned numOutStreams = EncodeMode ? NumStreams : 1; + + InStreamPointers.ClearAndReserve(numInStreams); + OutStreamPointers.ClearAndReserve(numOutStreams); unsigned i; - for (i = _srcBindInfo.Coders.Size(); i != 0;) + + for (i = 0; i < numInStreams; i++) + InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]); + + for (i = 0; i < numOutStreams; i++) + OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]); + + // we suppose that UnpackSizePointer and PackSizePointers contain correct pointers. + /* + if (UnpackSizePointer) + UnpackSizePointer = &UnpackSize; + for (i = 0; i < NumStreams; i++) + if (PackSizePointers[i]) + PackSizePointers[i] = &PackSizes[i]; + */ + + CReleaser releaser(*this); + + if (Coder) + Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0], + EncodeMode ? UnpackSizePointer : PackSizePointers[0], + EncodeMode ? PackSizePointers[0] : UnpackSizePointer, + progress); + else + Result = Coder2->Code( + &InStreamPointers.Front(), EncodeMode ? &UnpackSizePointer : &PackSizePointers.Front(), numInStreams, + &OutStreamPointers.Front(), EncodeMode ? &PackSizePointers.Front(): &UnpackSizePointer, numOutStreams, + progress); +} + +HRESULT CMixerMT::SetBindInfo(const CBindInfo &bindInfo) +{ + CMixer::SetBindInfo(bindInfo); + + _streamBinders.Clear(); + FOR_VECTOR (i, _bi.Bonds) { - i--; - const CCoderStreamsInfo &srcCoderInfo = _srcBindInfo.Coders[i]; - CCoderStreamsInfo destCoderInfo; - destCoderInfo.NumInStreams = srcCoderInfo.NumOutStreams; - destCoderInfo.NumOutStreams = srcCoderInfo.NumInStreams; - destBindInfo.Coders.AddInReserved(destCoderInfo); + RINOK(_streamBinders.AddNew().CreateEvents()); } - for (i = _srcBindInfo.BindPairs.Size(); i != 0;) + return S_OK; +} + +void CMixerMT::AddCoder(const CCreatedCoder &cod) +{ + IsFilter_Vector.Add(cod.IsFilter); + IsExternal_Vector.Add(cod.IsExternal); + // const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()]; + CCoderMT &c2 = _coders.AddNew(); + c2.NumStreams = cod.NumStreams; + c2.Coder = cod.Coder; + c2.Coder2 = cod.Coder2; + c2.EncodeMode = EncodeMode; +} + +CCoder &CMixerMT::GetCoder(unsigned index) +{ + return _coders[index]; +} + +void CMixerMT::ReInit() +{ + FOR_VECTOR (i, _streamBinders) + _streamBinders[i].ReInit(); +} + +void CMixerMT::SelectMainCoder(bool useFirst) +{ + unsigned ci = _bi.UnpackCoder; + + if (!useFirst) + for (;;) { - i--; - const CBindPair &srcBindPair = _srcBindInfo.BindPairs[i]; - CBindPair destBindPair; - destBindPair.InIndex = _srcOutToDestInMap[srcBindPair.OutIndex]; - destBindPair.OutIndex = _srcInToDestOutMap[srcBindPair.InIndex]; - destBindInfo.BindPairs.AddInReserved(destBindPair); + if (_coders[ci].NumStreams != 1) + break; + if (!IsFilter_Vector[ci]) + break; + + UInt32 st = _bi.Coder_to_Stream[ci]; + if (_bi.IsStream_in_PackStreams(st)) + break; + int bond = _bi.FindBond_for_PackStream(st); + if (bond < 0) + throw 20150213; + ci = _bi.Bonds[bond].UnpackIndex; } - for (i = 0; i < _srcBindInfo.InStreams.Size(); i++) - destBindInfo.OutStreams.AddInReserved(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]); - for (i = 0; i < _srcBindInfo.OutStreams.Size(); i++) - destBindInfo.InStreams.AddInReserved(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]); + + MainCoderIndex = ci; } -void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes, - CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems) +HRESULT CMixerMT::Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams) { - sizes.ClearAndSetSize(numItems); - sizePointers.ClearAndSetSize(numItems); - for(UInt32 i = 0; i < numItems; i++) + unsigned i; + + for (i = 0; i < _coders.Size(); i++) + { + CCoderMT &coderInfo = _coders[i]; + const CCoderStreamsInfo &csi = _bi.Coders[i]; + + UInt32 j; + + unsigned numInStreams = EncodeMode ? 1 : csi.NumStreams; + unsigned numOutStreams = EncodeMode ? csi.NumStreams : 1; + + coderInfo.InStreams.Clear(); + for (j = 0; j < numInStreams; j++) + coderInfo.InStreams.AddNew(); + + coderInfo.OutStreams.Clear(); + for (j = 0; j < numOutStreams; j++) + coderInfo.OutStreams.AddNew(); + } + + for (i = 0; i < _bi.Bonds.Size(); i++) { - if (!srcSizes || !srcSizes[i]) + const CBond &bond = _bi.Bonds[i]; + + UInt32 inCoderIndex, inCoderStreamIndex; + UInt32 outCoderIndex, outCoderStreamIndex; + + { + UInt32 coderIndex, coderStreamIndex; + _bi.GetCoder_for_Stream(bond.PackIndex, coderIndex, coderStreamIndex); + + inCoderIndex = EncodeMode ? bond.UnpackIndex : coderIndex; + outCoderIndex = EncodeMode ? coderIndex : bond.UnpackIndex; + + inCoderStreamIndex = EncodeMode ? 0 : coderStreamIndex; + outCoderStreamIndex = EncodeMode ? coderStreamIndex : 0; + } + + _streamBinders[i].CreateStreams( + &_coders[inCoderIndex].InStreams[inCoderStreamIndex], + &_coders[outCoderIndex].OutStreams[outCoderStreamIndex]); + + CMyComPtr<ICompressSetBufSize> inSetSize, outSetSize; + _coders[inCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&inSetSize); + _coders[outCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&outSetSize); + if (inSetSize && outSetSize) { - sizes[i] = 0; - sizePointers[i] = NULL; + const UInt32 kBufSize = 1 << 19; + inSetSize->SetInBufSize(inCoderStreamIndex, kBufSize); + outSetSize->SetOutBufSize(outCoderStreamIndex, kBufSize); } + } + + { + CCoderMT &cod = _coders[_bi.UnpackCoder]; + if (EncodeMode) + cod.InStreams[0] = inStreams[0]; else + cod.OutStreams[0] = outStreams[0]; + } + + for (i = 0; i < _bi.PackStreams.Size(); i++) + { + UInt32 coderIndex, coderStreamIndex; + _bi.GetCoder_for_Stream(_bi.PackStreams[i], coderIndex, coderStreamIndex); + CCoderMT &cod = _coders[coderIndex]; + if (EncodeMode) + cod.OutStreams[coderStreamIndex] = outStreams[i]; + else + cod.InStreams[coderStreamIndex] = inStreams[i]; + } + + return S_OK; +} + +HRESULT CMixerMT::ReturnIfError(HRESULT code) +{ + FOR_VECTOR (i, _coders) + if (_coders[i].Result == code) + return code; + return S_OK; +} + +HRESULT CMixerMT::Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, + ICompressProgressInfo *progress) +{ + Init(inStreams, outStreams); + + unsigned i; + for (i = 0; i < _coders.Size(); i++) + if (i != MainCoderIndex) { - sizes[i] = *(srcSizes[i]); - sizePointers[i] = &sizes[i]; + RINOK(_coders[i].Create()); } + + for (i = 0; i < _coders.Size(); i++) + if (i != MainCoderIndex) + _coders[i].Start(); + + _coders[MainCoderIndex].Code(progress); + + for (i = 0; i < _coders.Size(); i++) + if (i != MainCoderIndex) + _coders[i].WaitExecuteFinish(); + + RINOK(ReturnIfError(E_ABORT)); + RINOK(ReturnIfError(E_OUTOFMEMORY)); + + for (i = 0; i < _coders.Size(); i++) + { + HRESULT result = _coders[i].Result; + if (result != S_OK + && result != k_My_HRESULT_WritingWasCut + && result != S_FALSE + && result != E_FAIL) + return result; + } + + RINOK(ReturnIfError(S_FALSE)); + + for (i = 0; i < _coders.Size(); i++) + { + HRESULT result = _coders[i].Result; + if (result != S_OK && result != k_My_HRESULT_WritingWasCut) + return result; } + + return S_OK; } -void CCoderInfo2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes) +UInt64 CMixerMT::GetBondStreamSize(unsigned bondIndex) const { - SetSizes(inSizes, InSizes, InSizePointers, NumInStreams); - SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams); + return _streamBinders[bondIndex].ProcessedSize; } +#endif + } diff --git a/CPP/7zip/Archive/Common/CoderMixer2.h b/CPP/7zip/Archive/Common/CoderMixer2.h index 50e7077a..e63f2ff0 100644 --- a/CPP/7zip/Archive/Common/CoderMixer2.h +++ b/CPP/7zip/Archive/Common/CoderMixer2.h @@ -8,172 +8,430 @@ #include "../../ICoder.h" -namespace NCoderMixer { +#include "../../Common/CreateCoder.h" -struct CBindPair +#ifdef _7ZIP_ST + #define USE_MIXER_ST +#else + #define USE_MIXER_MT + #ifndef _SFX + #define USE_MIXER_ST + #endif +#endif + +#ifdef USE_MIXER_MT +#include "../../Common/StreamBinder.h" +#include "../../Common/VirtThread.h" +#endif + + + +#ifdef USE_MIXER_ST + +class CSequentialInStreamCalcSize: + public ISequentialInStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP1(ISequentialInStream) + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +private: + CMyComPtr<ISequentialInStream> _stream; + UInt64 _size; + bool _wasFinished; +public: + void SetStream(ISequentialInStream *stream) { _stream = stream; } + void Init() + { + _size = 0; + _wasFinished = false; + } + void ReleaseStream() { _stream.Release(); } + UInt64 GetSize() const { return _size; } + bool WasFinished() const { return _wasFinished; } +}; + + +class COutStreamCalcSize: + public ISequentialOutStream, + public IOutStreamFinish, + public CMyUnknownImp +{ + CMyComPtr<ISequentialOutStream> _stream; + UInt64 _size; +public: + MY_UNKNOWN_IMP2(ISequentialOutStream, IOutStreamFinish) + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(OutStreamFinish)(); + + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init() { _size = 0; } + UInt64 GetSize() const { return _size; } +}; + +#endif + + + +namespace NCoderMixer2 { + +struct CBond { - UInt32 InIndex; - UInt32 OutIndex; + UInt32 PackIndex; + UInt32 UnpackIndex; + + UInt32 Get_InIndex(bool encodeMode) const { return encodeMode ? UnpackIndex : PackIndex; } + UInt32 Get_OutIndex(bool encodeMode) const { return encodeMode ? PackIndex : UnpackIndex; } }; + struct CCoderStreamsInfo { - UInt32 NumInStreams; - UInt32 NumOutStreams; + UInt32 NumStreams; }; + struct CBindInfo { CRecordVector<CCoderStreamsInfo> Coders; - CRecordVector<CBindPair> BindPairs; - CRecordVector<UInt32> InStreams; - CRecordVector<UInt32> OutStreams; + CRecordVector<CBond> Bonds; + CRecordVector<UInt32> PackStreams; + unsigned UnpackCoder; - void Clear() + unsigned GetNum_Bonds_and_PackStreams() const { return Bonds.Size() + PackStreams.Size(); } + + int FindBond_for_PackStream(UInt32 packStream) const { - Coders.Clear(); - BindPairs.Clear(); - InStreams.Clear(); - OutStreams.Clear(); + FOR_VECTOR (i, Bonds) + if (Bonds[i].PackIndex == packStream) + return i; + return -1; } - /* - UInt32 GetCoderStartOutStream(UInt32 coderIndex) const + int FindBond_for_UnpackStream(UInt32 unpackStream) const { - UInt32 numOutStreams = 0; - for (UInt32 i = 0; i < coderIndex; i++) - numOutStreams += Coders[i].NumOutStreams; - return numOutStreams; + FOR_VECTOR (i, Bonds) + if (Bonds[i].UnpackIndex == unpackStream) + return i; + return -1; } - */ - - void GetNumStreams(UInt32 &numInStreams, UInt32 &numOutStreams) const + bool SetUnpackCoder() { - numInStreams = 0; - numOutStreams = 0; - FOR_VECTOR (i, Coders) + bool isOk = false; + FOR_VECTOR(i, Coders) { - const CCoderStreamsInfo &coderStreamsInfo = Coders[i]; - numInStreams += coderStreamsInfo.NumInStreams; - numOutStreams += coderStreamsInfo.NumOutStreams; + if (FindBond_for_UnpackStream(i) < 0) + { + if (isOk) + return false; + UnpackCoder = i; + isOk = true; + } } + return isOk; } - - int FindBinderForInStream(UInt32 inStream) const + + bool IsStream_in_PackStreams(UInt32 streamIndex) const { - FOR_VECTOR (i, BindPairs) - if (BindPairs[i].InIndex == inStream) - return i; - return -1; + return FindStream_in_PackStreams(streamIndex) >= 0; } - int FindBinderForOutStream(UInt32 outStream) const + + int FindStream_in_PackStreams(UInt32 streamIndex) const { - FOR_VECTOR (i, BindPairs) - if (BindPairs[i].OutIndex == outStream) + FOR_VECTOR(i, PackStreams) + if (PackStreams[i] == streamIndex) return i; return -1; } - UInt32 GetCoderInStreamIndex(UInt32 coderIndex) const + + // that function is used before Maps is calculated + + UInt32 GetStream_for_Coder(UInt32 coderIndex) const { UInt32 streamIndex = 0; for (UInt32 i = 0; i < coderIndex; i++) - streamIndex += Coders[i].NumInStreams; + streamIndex += Coders[i].NumStreams; return streamIndex; } + + // ---------- Maps Section ---------- + + CRecordVector<UInt32> Coder_to_Stream; + CRecordVector<UInt32> Stream_to_Coder; + + void ClearMaps(); + bool CalcMapsAndCheck(); + + // ---------- End of Maps Section ---------- - UInt32 GetCoderOutStreamIndex(UInt32 coderIndex) const + void Clear() { - UInt32 streamIndex = 0; - for (UInt32 i = 0; i < coderIndex; i++) - streamIndex += Coders[i].NumOutStreams; - return streamIndex; + Coders.Clear(); + Bonds.Clear(); + PackStreams.Clear(); + + ClearMaps(); } + + void GetCoder_for_Stream(UInt32 streamIndex, UInt32 &coderIndex, UInt32 &coderStreamIndex) const + { + coderIndex = Stream_to_Coder[streamIndex]; + coderStreamIndex = streamIndex - Coder_to_Stream[coderIndex]; + } +}; - void FindInStream(UInt32 streamIndex, UInt32 &coderIndex, - UInt32 &coderStreamIndex) const + +class CCoder +{ + CLASS_NO_COPY(CCoder); +public: + CMyComPtr<ICompressCoder> Coder; + CMyComPtr<ICompressCoder2> Coder2; + UInt32 NumStreams; + + UInt64 UnpackSize; + const UInt64 *UnpackSizePointer; + + CRecordVector<UInt64> PackSizes; + CRecordVector<const UInt64 *> PackSizePointers; + + CCoder() {} + + void SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes); + + IUnknown *GetUnknown() const { - for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++) - { - UInt32 curSize = Coders[coderIndex].NumInStreams; - if (streamIndex < curSize) - { - coderStreamIndex = streamIndex; - return; - } - streamIndex -= curSize; - } - throw 1; + return Coder ? (IUnknown *)Coder : (IUnknown *)Coder2; } - void FindOutStream(UInt32 streamIndex, UInt32 &coderIndex, - UInt32 &coderStreamIndex) const + + HRESULT QueryInterface(REFGUID iid, void** pp) const { - for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++) - { - UInt32 curSize = Coders[coderIndex].NumOutStreams; - if (streamIndex < curSize) + return GetUnknown()->QueryInterface(iid, pp); + } +}; + + + +class CMixer +{ + bool Is_PackSize_Correct_for_Stream(UInt32 streamIndex); + +protected: + CBindInfo _bi; + + int FindBond_for_Stream(bool forInputStream, UInt32 streamIndex) const + { + if (EncodeMode == forInputStream) + return _bi.FindBond_for_UnpackStream(streamIndex); + else + return _bi.FindBond_for_PackStream(streamIndex); + } + + CBoolVector IsFilter_Vector; + CBoolVector IsExternal_Vector; + bool EncodeMode; +public: + unsigned MainCoderIndex; + + CMixer(bool encodeMode): + EncodeMode(encodeMode), + MainCoderIndex(0) + {} + + /* + Sequence of calling: + + SetBindInfo(); + for each coder + AddCoder(); + SelectMainCoder(); + + for each file { - coderStreamIndex = streamIndex; - return; + ReInit() + for each coder + SetCoderInfo(); + Code(); } - streamIndex -= curSize; - } - throw 1; + */ + + virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) + { + _bi = bindInfo; + IsFilter_Vector.Clear(); + MainCoderIndex = 0; + return S_OK; } + + virtual void AddCoder(const CCreatedCoder &cod) = 0; + virtual CCoder &GetCoder(unsigned index) = 0; + virtual void SelectMainCoder(bool useFirst) = 0; + virtual void ReInit() = 0; + virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes) = 0; + virtual HRESULT Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, + ICompressProgressInfo *progress) = 0; + virtual UInt64 GetBondStreamSize(unsigned bondIndex) const = 0; + + bool Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex); + bool Is_PackSize_Correct_for_Coder(UInt32 coderIndex); + bool IsThere_ExternalCoder_in_PackTree(UInt32 coderIndex); }; -class CBindReverseConverter + + + +#ifdef USE_MIXER_ST + +struct CCoderST: public CCoder { - UInt32 _numSrcOutStreams; - NCoderMixer::CBindInfo _srcBindInfo; - CRecordVector<UInt32> _srcInToDestOutMap; - CRecordVector<UInt32> _srcOutToDestInMap; - CRecordVector<UInt32> _destInToSrcOutMap; -public: - UInt32 NumSrcInStreams; - CRecordVector<UInt32> DestOutToSrcInMap; + bool CanRead; + bool CanWrite; + + CCoderST(): CanRead(false), CanWrite(false) {} +}; - CBindReverseConverter(const NCoderMixer::CBindInfo &srcBindInfo); - void CreateReverseBindInfo(NCoderMixer::CBindInfo &destBindInfo); + +struct CStBinderStream +{ + CSequentialInStreamCalcSize *InStreamSpec; + COutStreamCalcSize *OutStreamSpec; + CMyComPtr<IUnknown> StreamRef; + + CStBinderStream(): InStreamSpec(NULL), OutStreamSpec(NULL) {} }; -void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes, - CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems); -struct CCoderInfo2 +class CMixerST: + public IUnknown, + public CMixer, + public CMyUnknownImp { - CMyComPtr<ICompressCoder> Coder; - CMyComPtr<ICompressCoder2> Coder2; - UInt32 NumInStreams; - UInt32 NumOutStreams; + HRESULT GetInStream2(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ + UInt32 outStreamIndex, ISequentialInStream **inStreamRes); + HRESULT GetInStream(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ + UInt32 inStreamIndex, ISequentialInStream **inStreamRes); + HRESULT GetOutStream(ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */ + UInt32 outStreamIndex, ISequentialOutStream **outStreamRes); - CRecordVector<UInt64> InSizes; - CRecordVector<UInt64> OutSizes; - CRecordVector<const UInt64 *> InSizePointers; - CRecordVector<const UInt64 *> OutSizePointers; + HRESULT FinishStream(UInt32 streamIndex); + HRESULT FinishCoder(UInt32 coderIndex); - CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams): - NumInStreams(numInStreams), - NumOutStreams(numOutStreams) {} - void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes); +public: + CObjectVector<CCoderST> _coders; + + CObjectVector<CStBinderStream> _binderStreams; - HRESULT QueryInterface(REFGUID iid, void** pp) const + MY_UNKNOWN_IMP + + CMixerST(bool encodeMode); + ~CMixerST(); + + virtual void AddCoder(const CCreatedCoder &cod); + virtual CCoder &GetCoder(unsigned index); + virtual void SelectMainCoder(bool useFirst); + virtual void ReInit(); + virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes) + { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes); } + virtual HRESULT Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, + ICompressProgressInfo *progress); + virtual UInt64 GetBondStreamSize(unsigned bondIndex) const; + + HRESULT GetMainUnpackStream( + ISequentialInStream * const *inStreams, + ISequentialInStream **inStreamRes); +}; + +#endif + + + + +#ifdef USE_MIXER_MT + +class CCoderMT: public CCoder, public CVirtThread +{ + CLASS_NO_COPY(CCoderMT) + CRecordVector<ISequentialInStream*> InStreamPointers; + CRecordVector<ISequentialOutStream*> OutStreamPointers; + +private: + void Execute(); +public: + bool EncodeMode; + HRESULT Result; + CObjectVector< CMyComPtr<ISequentialInStream> > InStreams; + CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams; + + void Release() { - IUnknown *p = Coder ? (IUnknown *)Coder : (IUnknown *)Coder2; - return p->QueryInterface(iid, pp); + InStreamPointers.Clear(); + OutStreamPointers.Clear(); + unsigned i; + for (i = 0; i < InStreams.Size(); i++) + InStreams[i].Release(); + for (i = 0; i < OutStreams.Size(); i++) + OutStreams[i].Release(); } + + class CReleaser + { + CLASS_NO_COPY(CReleaser) + CCoderMT &_c; + public: + CReleaser(CCoderMT &c): _c(c) {} + ~CReleaser() { _c.Release(); } + }; + + CCoderMT(): EncodeMode(false) {} + ~CCoderMT() { CVirtThread::WaitThreadFinish(); } + + void Code(ICompressProgressInfo *progress); }; -class CCoderMixer2 + +class CMixerMT: + public IUnknown, + public CMixer, + public CMyUnknownImp { + CObjectVector<CStreamBinder> _streamBinders; + + HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams); + HRESULT ReturnIfError(HRESULT code); + public: - virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) = 0; - virtual void ReInit() = 0; - virtual void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) = 0; + CObjectVector<CCoderMT> _coders; + + MY_UNKNOWN_IMP + + virtual HRESULT SetBindInfo(const CBindInfo &bindInfo); + virtual void AddCoder(const CCreatedCoder &cod); + virtual CCoder &GetCoder(unsigned index); + virtual void SelectMainCoder(bool useFirst); + virtual void ReInit(); + virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes) + { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes); } + virtual HRESULT Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, + ICompressProgressInfo *progress); + virtual UInt64 GetBondStreamSize(unsigned bondIndex) const; + + CMixerMT(bool encodeMode): CMixer(encodeMode) {} }; +#endif + } #endif diff --git a/CPP/7zip/Archive/Common/CoderMixer2MT.cpp b/CPP/7zip/Archive/Common/CoderMixer2MT.cpp index 5288fbc1..c0139862 100644 --- a/CPP/7zip/Archive/Common/CoderMixer2MT.cpp +++ b/CPP/7zip/Archive/Common/CoderMixer2MT.cpp @@ -4,125 +4,153 @@ #include "CoderMixer2MT.h" -namespace NCoderMixer { +namespace NCoderMixer2 { -CCoder2::CCoder2(UInt32 numInStreams, UInt32 numOutStreams): - CCoderInfo2(numInStreams, numOutStreams) +void CCoderMT::Execute() { Code(NULL); } + +void CCoderMT::Code(ICompressProgressInfo *progress) { - InStreams.ClearAndReserve(NumInStreams); - OutStreams.ClearAndReserve(NumOutStreams); -} + unsigned numInStreams = EncodeMode ? 1 : NumStreams; + unsigned numOutStreams = EncodeMode ? NumStreams : 1; -void CCoder2::Execute() { Code(NULL); } + InStreamPointers.ClearAndReserve(numInStreams); + OutStreamPointers.ClearAndReserve(numOutStreams); -void CCoder2::Code(ICompressProgressInfo *progress) -{ - InStreamPointers.ClearAndReserve(NumInStreams); - OutStreamPointers.ClearAndReserve(NumOutStreams); - UInt32 i; - for (i = 0; i < NumInStreams; i++) - { - if (InSizePointers[i]) - InSizePointers[i] = &InSizes[i]; + unsigned i; + + for (i = 0; i < numInStreams; i++) InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]); - } - for (i = 0; i < NumOutStreams; i++) - { - if (OutSizePointers[i]) - OutSizePointers[i] = &OutSizes[i]; + + for (i = 0; i < numOutStreams; i++) OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]); - } + + // we suppose that UnpackSizePointer and PackSizePointers contain correct pointers. + /* + if (UnpackSizePointer) + UnpackSizePointer = &UnpackSize; + for (i = 0; i < NumStreams; i++) + if (PackSizePointers[i]) + PackSizePointers[i] = &PackSizes[i]; + */ + if (Coder) Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0], - InSizePointers[0], OutSizePointers[0], progress); + EncodeMode ? UnpackSizePointer : PackSizePointers[0], + EncodeMode ? PackSizePointers[0] : UnpackSizePointer, + progress); else - Result = Coder2->Code(&InStreamPointers.Front(), &InSizePointers.Front(), NumInStreams, - &OutStreamPointers.Front(), &OutSizePointers.Front(), NumOutStreams, progress); - { - unsigned i; - for (i = 0; i < InStreams.Size(); i++) - InStreams[i].Release(); - for (i = 0; i < OutStreams.Size(); i++) - OutStreams[i].Release(); - } -} + Result = Coder2->Code( + &InStreamPointers.Front(), EncodeMode ? &UnpackSizePointer : &PackSizePointers.Front(), numInStreams, + &OutStreamPointers.Front(), EncodeMode ? &PackSizePointers.Front(): &UnpackSizePointer, numOutStreams, + progress); + + InStreamPointers.Clear(); + OutStreamPointers.Clear(); -/* -void CCoder2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes) -{ - SetSizes(inSizes, InSizes, InSizePointers, NumInStreams); - SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams); + for (i = 0; i < InStreams.Size(); i++) + InStreams[i].Release(); + for (i = 0; i < OutStreams.Size(); i++) + OutStreams[i].Release(); } -*/ - -////////////////////////////////////// -// CCoderMixer2MT -HRESULT CCoderMixer2MT::SetBindInfo(const CBindInfo &bindInfo) +HRESULT CMixerMT::SetBindInfo(const CBindInfo &bindInfo) { - _bindInfo = bindInfo; + CMixer::SetBindInfo(bindInfo); + _streamBinders.Clear(); - FOR_VECTOR (i, _bindInfo.BindPairs) + FOR_VECTOR (i, _bi.Bonds) { RINOK(_streamBinders.AddNew().CreateEvents()); } return S_OK; } -void CCoderMixer2MT::AddCoderCommon() -{ - const CCoderStreamsInfo &c = _bindInfo.Coders[_coders.Size()]; - CCoder2 threadCoderInfo(c.NumInStreams, c.NumOutStreams); - _coders.Add(threadCoderInfo); -} - -void CCoderMixer2MT::AddCoder(ICompressCoder *coder) +void CMixerMT::AddCoder(ICompressCoder *coder, ICompressCoder2 *coder2, bool isFilter) { - AddCoderCommon(); - _coders.Back().Coder = coder; + const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()]; + CCoderMT &c2 = _coders.AddNew(); + c2.NumStreams = c.NumStreams; + c2.EncodeMode = EncodeMode; + c2.Coder = coder; + c2.Coder2 = coder2; + IsFilter_Vector.Add(isFilter); } -void CCoderMixer2MT::AddCoder2(ICompressCoder2 *coder) +CCoder &CMixerMT::GetCoder(unsigned index) { - AddCoderCommon(); - _coders.Back().Coder2 = coder; + return _coders[index]; } - -void CCoderMixer2MT::ReInit() +void CMixerMT::ReInit() { FOR_VECTOR (i, _streamBinders) _streamBinders[i].ReInit(); } +void CMixerMT::SelectMainCoder(bool useFirst) +{ + unsigned ci = _bi.UnpackCoder; + + if (!useFirst) + for (;;) + { + if (_coders[ci].NumStreams != 1) + break; + if (!IsFilter_Vector[ci]) + break; + + UInt32 st = _bi.Coder_to_Stream[ci]; + if (_bi.IsStream_in_PackStreams(st)) + break; + int bond = _bi.FindBond_for_PackStream(st); + if (bond < 0) + throw 20150213; + ci = _bi.Bonds[bond].UnpackIndex; + } + + MainCoderIndex = ci; +} -HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams) +HRESULT CMixerMT::Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams) { - /* - if (_coders.Size() != _bindInfo.Coders.Size()) - throw 0; - */ unsigned i; + for (i = 0; i < _coders.Size(); i++) { - CCoder2 &coderInfo = _coders[i]; - const CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[i]; - coderInfo.InStreams.Clear(); + CCoderMT &coderInfo = _coders[i]; + const CCoderStreamsInfo &csi = _bi.Coders[i]; + UInt32 j; - for (j = 0; j < coderStreamsInfo.NumInStreams; j++) - coderInfo.InStreams.Add(NULL); + + unsigned numInStreams = EncodeMode ? 1 : csi.NumStreams; + unsigned numOutStreams = EncodeMode ? csi.NumStreams : 1; + + coderInfo.InStreams.Clear(); + for (j = 0; j < numInStreams; j++) + coderInfo.InStreams.AddNew(); + coderInfo.OutStreams.Clear(); - for (j = 0; j < coderStreamsInfo.NumOutStreams; j++) - coderInfo.OutStreams.Add(NULL); + for (j = 0; j < numOutStreams; j++) + coderInfo.OutStreams.AddNew(); } - for (i = 0; i < _bindInfo.BindPairs.Size(); i++) + for (i = 0; i < _bi.Bonds.Size(); i++) { - const CBindPair &bindPair = _bindInfo.BindPairs[i]; + const CBond &bond = _bi.Bonds[i]; + UInt32 inCoderIndex, inCoderStreamIndex; UInt32 outCoderIndex, outCoderStreamIndex; - _bindInfo.FindInStream(bindPair.InIndex, inCoderIndex, inCoderStreamIndex); - _bindInfo.FindOutStream(bindPair.OutIndex, outCoderIndex, outCoderStreamIndex); + + { + UInt32 coderIndex, coderStreamIndex; + _bi.GetCoder_for_Stream(bond.PackIndex, coderIndex, coderStreamIndex); + + inCoderIndex = EncodeMode ? bond.UnpackIndex : coderIndex; + outCoderIndex = EncodeMode ? coderIndex : bond.UnpackIndex; + + inCoderStreamIndex = EncodeMode ? 0 : coderStreamIndex; + outCoderStreamIndex = EncodeMode ? coderStreamIndex : 0; + } _streamBinders[i].CreateStreams( &_coders[inCoderIndex].InStreams[inCoderStreamIndex], @@ -139,23 +167,29 @@ HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStre } } - for (i = 0; i < _bindInfo.InStreams.Size(); i++) { - UInt32 inCoderIndex, inCoderStreamIndex; - _bindInfo.FindInStream(_bindInfo.InStreams[i], inCoderIndex, inCoderStreamIndex); - _coders[inCoderIndex].InStreams[inCoderStreamIndex] = inStreams[i]; + CCoderMT &cod = _coders[_bi.UnpackCoder]; + if (EncodeMode) + cod.InStreams[0] = inStreams[0]; + else + cod.OutStreams[0] = outStreams[0]; } - - for (i = 0; i < _bindInfo.OutStreams.Size(); i++) + + for (i = 0; i < _bi.PackStreams.Size(); i++) { - UInt32 outCoderIndex, outCoderStreamIndex; - _bindInfo.FindOutStream(_bindInfo.OutStreams[i], outCoderIndex, outCoderStreamIndex); - _coders[outCoderIndex].OutStreams[outCoderStreamIndex] = outStreams[i]; + UInt32 coderIndex, coderStreamIndex; + _bi.GetCoder_for_Stream(_bi.PackStreams[i], coderIndex, coderStreamIndex); + CCoderMT &cod = _coders[coderIndex]; + if (EncodeMode) + cod.OutStreams[coderStreamIndex] = outStreams[i]; + else + cod.InStreams[coderStreamIndex] = inStreams[i]; } + return S_OK; } -HRESULT CCoderMixer2MT::ReturnIfError(HRESULT code) +HRESULT CMixerMT::ReturnIfError(HRESULT code) { FOR_VECTOR (i, _coders) if (_coders[i].Result == code) @@ -163,35 +197,28 @@ HRESULT CCoderMixer2MT::ReturnIfError(HRESULT code) return S_OK; } -STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams, - const UInt64 ** /* inSizes */, - UInt32 numInStreams, - ISequentialOutStream **outStreams, - const UInt64 ** /* outSizes */, - UInt32 numOutStreams, - ICompressProgressInfo *progress) +HRESULT CMixerMT::Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, + ICompressProgressInfo *progress) { - if (numInStreams != (UInt32)_bindInfo.InStreams.Size() || - numOutStreams != (UInt32)_bindInfo.OutStreams.Size()) - return E_INVALIDARG; - Init(inStreams, outStreams); unsigned i; for (i = 0; i < _coders.Size(); i++) - if (i != _progressCoderIndex) + if (i != MainCoderIndex) { RINOK(_coders[i].Create()); } for (i = 0; i < _coders.Size(); i++) - if (i != _progressCoderIndex) + if (i != MainCoderIndex) _coders[i].Start(); - _coders[_progressCoderIndex].Code(progress); + _coders[MainCoderIndex].Code(progress); for (i = 0; i < _coders.Size(); i++) - if (i != _progressCoderIndex) + if (i != MainCoderIndex) _coders[i].WaitExecuteFinish(); RINOK(ReturnIfError(E_ABORT)); @@ -200,7 +227,10 @@ STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams, for (i = 0; i < _coders.Size(); i++) { HRESULT result = _coders[i].Result; - if (result != S_OK && result != E_FAIL && result != S_FALSE) + if (result != S_OK + && result != k_My_HRESULT_WritingWasCut + && result != S_FALSE + && result != E_FAIL) return result; } @@ -209,10 +239,16 @@ STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams, for (i = 0; i < _coders.Size(); i++) { HRESULT result = _coders[i].Result; - if (result != S_OK) + if (result != S_OK && result != k_My_HRESULT_WritingWasCut) return result; } + return S_OK; } +UInt64 CMixerMT::GetBondStreamSize(unsigned bondIndex) const +{ + return _streamBinders[bondIndex].ProcessedSize; +} + } diff --git a/CPP/7zip/Archive/Common/CoderMixer2MT.h b/CPP/7zip/Archive/Common/CoderMixer2MT.h index ba475cec..41bb3e1c 100644 --- a/CPP/7zip/Archive/Common/CoderMixer2MT.h +++ b/CPP/7zip/Archive/Common/CoderMixer2MT.h @@ -3,81 +3,75 @@ #ifndef __CODER_MIXER2_MT_H #define __CODER_MIXER2_MT_H -#include "CoderMixer2.h" #include "../../../Common/MyCom.h" + #include "../../Common/StreamBinder.h" #include "../../Common/VirtThread.h" -namespace NCoderMixer { +#include "CoderMixer2.h" + +namespace NCoderMixer2 { -struct CCoder2: public CCoderInfo2, public CVirtThread +class CCoderMT: public CCoder, public CVirtThread { + CLASS_NO_COPY(CCoderMT) CRecordVector<ISequentialInStream*> InStreamPointers; CRecordVector<ISequentialOutStream*> OutStreamPointers; +private: + void Execute(); public: + bool EncodeMode; HRESULT Result; CObjectVector< CMyComPtr<ISequentialInStream> > InStreams; CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams; - CCoder2(UInt32 numInStreams, UInt32 numOutStreams); - ~CCoder2() { CVirtThread::WaitThreadFinish(); } - // void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes); - virtual void Execute(); + CCoderMT(): EncodeMode(false) {} + ~CCoderMT() { CVirtThread::WaitThreadFinish(); } + void Code(ICompressProgressInfo *progress); }; -/* - SetBindInfo() - for each coder - AddCoder[2]() - SetProgressIndex(UInt32 coderIndex); - - for each file - { - ReInit() - for each coder - SetCoderInfo - Code - } -*/ - -class CCoderMixer2MT: - public ICompressCoder2, - public CCoderMixer2, + +class CMixerMT: + public IUnknown, + public CMixer, public CMyUnknownImp { - CBindInfo _bindInfo; CObjectVector<CStreamBinder> _streamBinders; - unsigned _progressCoderIndex; - void AddCoderCommon(); - HRESULT Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams); + HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams); HRESULT ReturnIfError(HRESULT code); + public: - CObjectVector<CCoder2> _coders; + CObjectVector<CCoderMT> _coders; + MY_UNKNOWN_IMP - STDMETHOD(Code)(ISequentialInStream **inStreams, - const UInt64 **inSizes, - UInt32 numInStreams, - ISequentialOutStream **outStreams, - const UInt64 **outSizes, - UInt32 numOutStreams, + virtual HRESULT SetBindInfo(const CBindInfo &bindInfo); + + virtual void AddCoder(ICompressCoder *coder, ICompressCoder2 *coder2, bool isFilter); + + virtual CCoder &GetCoder(unsigned index); + + virtual void SelectMainCoder(bool useFirst); + + virtual void ReInit(); + + virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes) + { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes); } + + virtual HRESULT Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, ICompressProgressInfo *progress); - HRESULT SetBindInfo(const CBindInfo &bindInfo); - void AddCoder(ICompressCoder *coder); - void AddCoder2(ICompressCoder2 *coder); - void SetProgressCoderIndex(unsigned coderIndex) { _progressCoderIndex = coderIndex; } + virtual UInt64 GetBondStreamSize(unsigned bondIndex) const; - void ReInit(); - void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) - { _coders[coderIndex].SetCoderInfo(inSizes, outSizes); } - UInt64 GetWriteProcessedSize(UInt32 binderIndex) const - { return _streamBinders[binderIndex].ProcessedSize; } + CMixerMT(bool encodeMode): CMixer(encodeMode) {} }; } + #endif diff --git a/CPP/7zip/Archive/Common/CoderMixer2ST.cpp b/CPP/7zip/Archive/Common/CoderMixer2ST.cpp index a94ba115..127c1ed4 100644 --- a/CPP/7zip/Archive/Common/CoderMixer2ST.cpp +++ b/CPP/7zip/Archive/Common/CoderMixer2ST.cpp @@ -4,236 +4,559 @@ #include "CoderMixer2ST.h" -namespace NCoderMixer { +STDMETHODIMP CSequentialInStreamCalcSize::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 realProcessed = 0; + HRESULT result = S_OK; + if (_stream) + result = _stream->Read(data, size, &realProcessed); + _size += realProcessed; + if (size != 0 && realProcessed == 0) + _wasFinished = true; + if (processedSize) + *processedSize = realProcessed; + return result; +} -CCoderMixer2ST::CCoderMixer2ST() {} -CCoderMixer2ST::~CCoderMixer2ST(){ } -HRESULT CCoderMixer2ST::SetBindInfo(const CBindInfo &bindInfo) +STDMETHODIMP COutStreamCalcSize::Write(const void *data, UInt32 size, UInt32 *processedSize) { - _bindInfo = bindInfo; - return S_OK; + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + _size += size; + if (processedSize) + *processedSize = size; + return result; } -void CCoderMixer2ST::AddCoderCommon(bool isMain) +STDMETHODIMP COutStreamCalcSize::Flush() { - const CCoderStreamsInfo &csi = _bindInfo.Coders[_coders.Size()]; - _coders.Add(CSTCoderInfo(csi.NumInStreams, csi.NumOutStreams, isMain)); + HRESULT result = S_OK; + if (_stream) + { + CMyComPtr<IOutStreamFlush> outStreamFlush; + _stream.QueryInterface(IID_IOutStreamFlush, &outStreamFlush); + if (outStreamFlush) + result = outStreamFlush->Flush();; + } + return result; } -void CCoderMixer2ST::AddCoder(ICompressCoder *coder, bool isMain) + + +namespace NCoderMixer2 { + +CMixerST::CMixerST(bool encodeMode): + CMixer(encodeMode) + {} + +CMixerST::~CMixerST() {} + +void CMixerST::AddCoder(ICompressCoder *coder, ICompressCoder2 *coder2, bool isFilter) { - AddCoderCommon(isMain); - _coders.Back().Coder = coder; + IsFilter_Vector.Add(isFilter); + const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()]; + CCoderST &c2 = _coders.AddNew(); + c2.NumStreams = c.NumStreams; + c2.Coder = coder; + c2.Coder2 = coder2; + + /* + if (isFilter) + { + c2.CanRead = true; + c2.CanWrite = true; + } + else + */ + { + IUnknown *unk = (coder ? (IUnknown *)coder : (IUnknown *)coder2); + { + CMyComPtr<ISequentialInStream> s; + unk->QueryInterface(IID_ISequentialInStream, (void**)&s); + c2.CanRead = (s != NULL); + } + { + CMyComPtr<ISequentialOutStream> s; + unk->QueryInterface(IID_ISequentialOutStream, (void**)&s); + c2.CanWrite = (s != NULL); + } + } } -void CCoderMixer2ST::AddCoder2(ICompressCoder2 *coder, bool isMain) +CCoder &CMixerST::GetCoder(unsigned index) { - AddCoderCommon(isMain); - _coders.Back().Coder2 = coder; + return _coders[index]; +} + +void CMixerST::ReInit() {} + +HRESULT CMixerST::GetInStream2( + ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ + UInt32 outStreamIndex, ISequentialInStream **inStreamRes) +{ + UInt32 coderIndex = outStreamIndex, coderStreamIndex = 0; + + if (EncodeMode) + { + _bi.GetCoder_for_Stream(outStreamIndex, coderIndex, coderStreamIndex); + if (coderStreamIndex != 0) + return E_NOTIMPL; + } + + const CCoder &coder = _coders[coderIndex]; + + CMyComPtr<ISequentialInStream> seqInStream; + coder.QueryInterface(IID_ISequentialInStream, (void **)&seqInStream); + if (!seqInStream) + return E_NOTIMPL; + + UInt32 numInStreams = EncodeMode ? 1 : coder.NumStreams; + UInt32 startIndex = EncodeMode ? coderIndex : _bi.Coder_to_Stream[coderIndex]; + + bool isSet = false; + + if (numInStreams == 1) + { + CMyComPtr<ICompressSetInStream> setStream; + coder.QueryInterface(IID_ICompressSetInStream, (void **)&setStream); + if (setStream) + { + CMyComPtr<ISequentialInStream> seqInStream2; + RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + 0, &seqInStream2)); + RINOK(setStream->SetInStream(seqInStream2)); + isSet = true; + } + } + + if (!isSet && numInStreams != 0) + { + CMyComPtr<ICompressSetInStream2> setStream2; + coder.QueryInterface(IID_ICompressSetInStream2, (void **)&setStream2); + if (!setStream2) + return E_NOTIMPL; + + for (UInt32 i = 0; i < numInStreams; i++) + { + CMyComPtr<ISequentialInStream> seqInStream2; + RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + i, &seqInStream2)); + RINOK(setStream2->SetInStream2(i, seqInStream2)); + } + } + + *inStreamRes = seqInStream.Detach(); + return S_OK; } -void CCoderMixer2ST::ReInit() { } -HRESULT CCoderMixer2ST::GetInStream( - ISequentialInStream **inStreams, const UInt64 **inSizes, - UInt32 streamIndex, ISequentialInStream **inStreamRes) +HRESULT CMixerST::GetInStream( + ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ + UInt32 inStreamIndex, ISequentialInStream **inStreamRes) { CMyComPtr<ISequentialInStream> seqInStream; - int i; - for (i = 0; i < _bindInfo.InStreams.Size(); i++) - if (_bindInfo.InStreams[i] == streamIndex) + + { + int index = -1; + if (EncodeMode) + { + if (_bi.UnpackCoder == inStreamIndex) + index = 0; + } + else + index = _bi.FindStream_in_PackStreams(inStreamIndex); + + if (index >= 0) { - seqInStream = inStreams[i]; + seqInStream = inStreams[index]; *inStreamRes = seqInStream.Detach(); return S_OK; } - int binderIndex = _bindInfo.FindBinderForInStream(streamIndex); - if (binderIndex < 0) + } + + int bond = FindBond_for_Stream( + true, // forInputStream + inStreamIndex); + if (bond < 0) return E_INVALIDARG; - UInt32 coderIndex, coderStreamIndex; - _bindInfo.FindOutStream(_bindInfo.BindPairs[binderIndex].OutIndex, - coderIndex, coderStreamIndex); - - CCoderInfo2 &coder = _coders[coderIndex]; - if (!coder.Coder) - return E_NOTIMPL; - coder.Coder.QueryInterface(IID_ISequentialInStream, &seqInStream); - if (!seqInStream) - return E_NOTIMPL; + RINOK(GetInStream2(inStreams, /* inSizes, */ + _bi.Bonds[bond].Get_OutIndex(EncodeMode), &seqInStream)); - UInt32 startIndex = _bindInfo.GetCoderInStreamIndex(coderIndex); + while (_binderStreams.Size() <= (unsigned)bond) + _binderStreams.AddNew(); + CStBinderStream &bs = _binderStreams[bond]; - CMyComPtr<ICompressSetInStream> setInStream; - if (!coder.Coder) - return E_NOTIMPL; - coder.Coder.QueryInterface(IID_ICompressSetInStream, &setInStream); - if (!setInStream) + if (bs.StreamRef || bs.InStreamSpec) return E_NOTIMPL; + + CSequentialInStreamCalcSize *spec = new CSequentialInStreamCalcSize; + bs.StreamRef = spec; + bs.InStreamSpec = spec; + + spec->SetStream(seqInStream); + spec->Init(); + + seqInStream = bs.InStreamSpec; - if (coder.NumInStreams > 1) - return E_NOTIMPL; - for (i = 0; i < (int)coder.NumInStreams; i++) - { - CMyComPtr<ISequentialInStream> seqInStream2; - RINOK(GetInStream(inStreams, inSizes, startIndex + i, &seqInStream2)); - RINOK(setInStream->SetInStream(seqInStream2)); - } *inStreamRes = seqInStream.Detach(); return S_OK; } -HRESULT CCoderMixer2ST::GetOutStream( - ISequentialOutStream **outStreams, const UInt64 **outSizes, - UInt32 streamIndex, ISequentialOutStream **outStreamRes) + +HRESULT CMixerST::GetOutStream( + ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */ + UInt32 outStreamIndex, ISequentialOutStream **outStreamRes) { CMyComPtr<ISequentialOutStream> seqOutStream; - int i; - for (i = 0; i < _bindInfo.OutStreams.Size(); i++) - if (_bindInfo.OutStreams[i] == streamIndex) + + { + int index = -1; + if (!EncodeMode) + { + if (_bi.UnpackCoder == outStreamIndex) + index = 0; + } + else + index = _bi.FindStream_in_PackStreams(outStreamIndex); + + if (index >= 0) { - seqOutStream = outStreams[i]; + seqOutStream = outStreams[index]; *outStreamRes = seqOutStream.Detach(); return S_OK; } - int binderIndex = _bindInfo.FindBinderForOutStream(streamIndex); - if (binderIndex < 0) + } + + int bond = FindBond_for_Stream( + false, // forInputStream + outStreamIndex); + if (bond < 0) return E_INVALIDARG; - UInt32 coderIndex, coderStreamIndex; - _bindInfo.FindInStream(_bindInfo.BindPairs[binderIndex].InIndex, - coderIndex, coderStreamIndex); + UInt32 inStreamIndex = _bi.Bonds[bond].Get_InIndex(EncodeMode); + + UInt32 coderIndex = inStreamIndex; + UInt32 coderStreamIndex = 0; + + if (!EncodeMode) + _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex); + + CCoder &coder = _coders[coderIndex]; - CCoderInfo2 &coder = _coders[coderIndex]; + /* if (!coder.Coder) return E_NOTIMPL; - coder.Coder.QueryInterface(IID_ISequentialOutStream, &seqOutStream); + */ + + coder.QueryInterface(IID_ISequentialOutStream, (void **)&seqOutStream); if (!seqOutStream) return E_NOTIMPL; - UInt32 startIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex); + UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1; + UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex; - CMyComPtr<ICompressSetOutStream> setOutStream; - if (!coder.Coder) - return E_NOTIMPL; - coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream); - if (!setOutStream) - return E_NOTIMPL; + bool isSet = false; - if (coder.NumOutStreams > 1) - return E_NOTIMPL; - for (i = 0; i < (int)coder.NumOutStreams; i++) + if (numOutStreams == 1) { - CMyComPtr<ISequentialOutStream> seqOutStream2; - RINOK(GetOutStream(outStreams, outSizes, startIndex + i, &seqOutStream2)); - RINOK(setOutStream->SetOutStream(seqOutStream2)); + CMyComPtr<ICompressSetOutStream> setOutStream; + coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream); + if (setOutStream) + { + CMyComPtr<ISequentialOutStream> seqOutStream2; + RINOK(GetOutStream(outStreams, /* outSizes, */ startIndex + 0, &seqOutStream2)); + RINOK(setOutStream->SetOutStream(seqOutStream2)); + isSet = true; + } } + + if (!isSet && numOutStreams != 0) + { + // return E_NOTIMPL; + // /* + CMyComPtr<ICompressSetOutStream2> setStream2; + coder.QueryInterface(IID_ICompressSetOutStream2, (void **)&setStream2); + if (!setStream2) + return E_NOTIMPL; + for (UInt32 i = 0; i < numOutStreams; i++) + { + CMyComPtr<ISequentialOutStream> seqOutStream2; + RINOK(GetOutStream(outStreams, startIndex + i, &seqOutStream2)); + RINOK(setStream2->SetOutStream2(i, seqOutStream2)); + } + // */ + } + + while (_binderStreams.Size() <= (unsigned)bond) + _binderStreams.AddNew(); + CStBinderStream &bs = _binderStreams[bond]; + + if (bs.StreamRef || bs.OutStreamSpec) + return E_NOTIMPL; + + COutStreamCalcSize *spec = new COutStreamCalcSize; + bs.StreamRef = (ISequentialOutStream *)spec; + bs.OutStreamSpec = spec; + + spec->SetStream(seqOutStream); + spec->Init(); + + seqOutStream = bs.OutStreamSpec; + *outStreamRes = seqOutStream.Detach(); return S_OK; } - -STDMETHODIMP CCoderMixer2ST::Code(ISequentialInStream **inStreams, - const UInt64 **inSizes, - UInt32 numInStreams, - ISequentialOutStream **outStreams, - const UInt64 **outSizes, - UInt32 numOutStreams, - ICompressProgressInfo *progress) + +static HRESULT GetError(HRESULT res, HRESULT res2) { - if (numInStreams != (UInt32)_bindInfo.InStreams.Size() || - numOutStreams != (UInt32)_bindInfo.OutStreams.Size()) - return E_INVALIDARG; + if (res == res2) + return res; + if (res == S_OK) + return res2; + if (res == k_My_HRESULT_WritingWasCut) + { + if (res2 != S_OK) + return res2; + } + return res; +} - // Find main coder - int _mainCoderIndex = -1; - int i; - for (i = 0; i < _coders.Size(); i++) - if (_coders[i].IsMain) - { - _mainCoderIndex = i; - break; - } - if (_mainCoderIndex < 0) - for (i = 0; i < _coders.Size(); i++) - if (_coders[i].NumInStreams > 1) + +HRESULT CMixerST::FlushStream(UInt32 streamIndex) +{ + { + int index = -1; + if (!EncodeMode) { - if (_mainCoderIndex >= 0) - return E_NOTIMPL; - _mainCoderIndex = i; + if (_bi.UnpackCoder == streamIndex) + index = 0; } - if (_mainCoderIndex < 0) - _mainCoderIndex = 0; + else + index = _bi.FindStream_in_PackStreams(streamIndex); + + if (index >= 0) + return S_OK; + } + + int bond = FindBond_for_Stream( + false, // forInputStream + streamIndex); + if (bond < 0) + return E_INVALIDARG; + + UInt32 inStreamIndex = _bi.Bonds[bond].Get_InIndex(EncodeMode); + + UInt32 coderIndex = inStreamIndex; + UInt32 coderStreamIndex = 0; + if (!EncodeMode) + _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex); + + CCoder &coder = _coders[coderIndex]; + CMyComPtr<IOutStreamFlush> flush; + coder.QueryInterface(IID_IOutStreamFlush, (void **)&flush); + HRESULT res = S_OK; + if (flush) + { + res = flush->Flush(); + } + return GetError(res, FlushCoder(coderIndex)); +} + + +HRESULT CMixerST::FlushCoder(UInt32 coderIndex) +{ + CCoder &coder = _coders[coderIndex]; + + UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1; + UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex; + + HRESULT res = S_OK; + for (unsigned i = 0; i < numOutStreams; i++) + res = GetError(res, FlushStream(startIndex + i)); + return res; +} + + +void CMixerST::SelectMainCoder(bool useFirst) +{ + unsigned ci = _bi.UnpackCoder; + + int firstNonFilter = -1; + int firstAllowed = ci; + + for (;;) + { + const CCoderST &coder = _coders[ci]; + // break; + + if (ci != _bi.UnpackCoder) + if (EncodeMode ? !coder.CanWrite : !coder.CanRead) + { + firstAllowed = ci; + firstNonFilter = -2; + } + + if (coder.NumStreams != 1) + break; + + UInt32 st = _bi.Coder_to_Stream[ci]; + if (_bi.IsStream_in_PackStreams(st)) + break; + int bond = _bi.FindBond_for_PackStream(st); + if (bond < 0) + throw 20150213; + + if (EncodeMode ? !coder.CanRead : !coder.CanWrite) + break; + + if (firstNonFilter == -1 && !IsFilter_Vector[ci]) + firstNonFilter = ci; + + ci = _bi.Bonds[bond].UnpackIndex; + } + + ci = firstNonFilter; + if (firstNonFilter < 0 || useFirst) + ci = firstAllowed; + MainCoderIndex = ci; +} + + +HRESULT CMixerST::Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, + ICompressProgressInfo *progress) +{ + _binderStreams.Clear(); + unsigned ci = MainCoderIndex; - // _mainCoderIndex = 0; - // _mainCoderIndex = _coders.Size() - 1; - CCoderInfo2 &mainCoder = _coders[_mainCoderIndex]; + const CCoder &mainCoder = _coders[MainCoderIndex]; CObjectVector< CMyComPtr<ISequentialInStream> > seqInStreams; CObjectVector< CMyComPtr<ISequentialOutStream> > seqOutStreams; - UInt32 startInIndex = _bindInfo.GetCoderInStreamIndex(_mainCoderIndex); - UInt32 startOutIndex = _bindInfo.GetCoderOutStreamIndex(_mainCoderIndex); - for (i = 0; i < (int)mainCoder.NumInStreams; i++) + + UInt32 numInStreams = EncodeMode ? 1 : mainCoder.NumStreams; + UInt32 numOutStreams = !EncodeMode ? 1 : mainCoder.NumStreams; + + UInt32 startInIndex = EncodeMode ? ci : _bi.Coder_to_Stream[ci]; + UInt32 startOutIndex = !EncodeMode ? ci : _bi.Coder_to_Stream[ci]; + + UInt32 i; + + for (i = 0; i < numInStreams; i++) { CMyComPtr<ISequentialInStream> seqInStream; - RINOK(GetInStream(inStreams, inSizes, startInIndex + i, &seqInStream)); + RINOK(GetInStream(inStreams, /* inSizes, */ startInIndex + i, &seqInStream)); seqInStreams.Add(seqInStream); } - for (i = 0; i < (int)mainCoder.NumOutStreams; i++) + + for (i = 0; i < numOutStreams; i++) { CMyComPtr<ISequentialOutStream> seqOutStream; - RINOK(GetOutStream(outStreams, outSizes, startOutIndex + i, &seqOutStream)); + RINOK(GetOutStream(outStreams, /* outSizes, */ startOutIndex + i, &seqOutStream)); seqOutStreams.Add(seqOutStream); } + CRecordVector< ISequentialInStream * > seqInStreamsSpec; CRecordVector< ISequentialOutStream * > seqOutStreamsSpec; - for (i = 0; i < (int)mainCoder.NumInStreams; i++) + + for (i = 0; i < numInStreams; i++) seqInStreamsSpec.Add(seqInStreams[i]); - for (i = 0; i < (int)mainCoder.NumOutStreams; i++) + for (i = 0; i < numOutStreams; i++) seqOutStreamsSpec.Add(seqOutStreams[i]); for (i = 0; i < _coders.Size(); i++) { - if (i == _mainCoderIndex) + if (i == ci) continue; - CCoderInfo2 &coder = _coders[i]; + + CCoder &coder = _coders[i]; + CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize; - coder.Coder.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize); + coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize); if (setOutStreamSize) { - RINOK(setOutStreamSize->SetOutStreamSize(coder.OutSizePointers[0])); + RINOK(setOutStreamSize->SetOutStreamSize( + EncodeMode ? coder.PackSizePointers[0] : coder.UnpackSizePointer)); } } + + const UInt64 * const *isSizes2 = EncodeMode ? &mainCoder.UnpackSizePointer : &mainCoder.PackSizePointers.Front(); + const UInt64 * const *outSizes2 = EncodeMode ? &mainCoder.PackSizePointers.Front() : &mainCoder.UnpackSizePointer; + + HRESULT res; if (mainCoder.Coder) { - RINOK(mainCoder.Coder->Code( + res = mainCoder.Coder->Code( seqInStreamsSpec[0], seqOutStreamsSpec[0], - mainCoder.InSizePointers[0], mainCoder.OutSizePointers[0], - progress)); + isSizes2[0], outSizes2[0], + progress); } else { - RINOK(mainCoder.Coder2->Code( - &seqInStreamsSpec.Front(), - &mainCoder.InSizePointers.Front(), mainCoder.NumInStreams, - &seqOutStreamsSpec.Front(), - &mainCoder.OutSizePointers.Front(), mainCoder.NumOutStreams, - progress)); + res = mainCoder.Coder2->Code( + &seqInStreamsSpec.Front(), isSizes2, numInStreams, + &seqOutStreamsSpec.Front(), outSizes2, numOutStreams, + progress); } - CMyComPtr<IOutStreamFlush> flush; - seqOutStreams.Front().QueryInterface(IID_IOutStreamFlush, &flush); - if (flush) - return flush->Flush(); + + if (res == k_My_HRESULT_WritingWasCut) + res = S_OK; + + if (res == S_OK || res == S_FALSE) + { + res = GetError(res, FlushCoder(ci)); + } + + for (i = 0; i < _binderStreams.Size(); i++) + { + const CStBinderStream &bs = _binderStreams[i]; + if (bs.InStreamSpec) + bs.InStreamSpec->ReleaseStream(); + else + bs.OutStreamSpec->ReleaseStream(); + } + + if (res == k_My_HRESULT_WritingWasCut) + res = S_OK; + return res; +} + + +HRESULT CMixerST::GetMainUnpackStream( + ISequentialInStream * const *inStreams, + ISequentialInStream **inStreamRes) +{ + CMyComPtr<ISequentialInStream> seqInStream; + + RINOK(GetInStream2(inStreams, /* inSizes, */ + _bi.UnpackCoder, &seqInStream)) + + FOR_VECTOR (i, _coders) + { + CCoder &coder = _coders[i]; + CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize; + coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize); + if (setOutStreamSize) + { + RINOK(setOutStreamSize->SetOutStreamSize(coder.UnpackSizePointer)); + } + } + + *inStreamRes = seqInStream.Detach(); return S_OK; } -/* -UInt64 CCoderMixer2ST::GetWriteProcessedSize(UInt32 binderIndex) const + +UInt64 CMixerST::GetBondStreamSize(unsigned bondIndex) const { - return _streamBinders[binderIndex].ProcessedSize; + const CStBinderStream &bs = _binderStreams[bondIndex]; + if (bs.InStreamSpec) + return bs.InStreamSpec->GetSize(); + return bs.OutStreamSpec->GetSize(); } -*/ } diff --git a/CPP/7zip/Archive/Common/CoderMixer2ST.h b/CPP/7zip/Archive/Common/CoderMixer2ST.h index d35655ba..f2f7c4cb 100644 --- a/CPP/7zip/Archive/Common/CoderMixer2ST.h +++ b/CPP/7zip/Archive/Common/CoderMixer2ST.h @@ -3,84 +3,125 @@ #ifndef __CODER_MIXER2_ST_H #define __CODER_MIXER2_ST_H -#include "CoderMixer2.h" #include "../../../Common/MyCom.h" + #include "../../ICoder.h" -namespace NCoderMixer { - -// SetBindInfo() -// for each coder -// { -// AddCoder[2]() -// } -// -// for each file -// { -// ReInit() -// for each coder -// { -// SetCoderInfo -// } -// SetProgressIndex(UInt32 coderIndex); -// Code -// } - -struct CSTCoderInfo: public CCoderInfo2 +#include "CoderMixer2.h" + +class CSequentialInStreamCalcSize: + public ISequentialInStream, + public CMyUnknownImp { - bool IsMain; - CSTCoderInfo(UInt32 numInStreams, UInt32 numOutStreams, bool isMain): - CCoderInfo2(numInStreams, numOutStreams), IsMain(isMain) {} +public: + MY_UNKNOWN_IMP1(ISequentialInStream) + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +private: + CMyComPtr<ISequentialInStream> _stream; + UInt64 _size; + bool _wasFinished; +public: + void SetStream(ISequentialInStream *stream) { _stream = stream; } + void Init() + { + _size = 0; + _wasFinished = false; + } + void ReleaseStream() { _stream.Release(); } + UInt64 GetSize() const { return _size; } + bool WasFinished() const { return _wasFinished; } }; -class CCoderMixer2ST: - public ICompressCoder2, - public CCoderMixer2, + +class COutStreamCalcSize: + public ISequentialOutStream, + public IOutStreamFlush, public CMyUnknownImp { - MY_UNKNOWN_IMP - - HRESULT GetInStream( - ISequentialInStream **inStreams, const UInt64 **inSizes, - UInt32 streamIndex, ISequentialInStream **inStreamRes); - HRESULT GetOutStream( - ISequentialOutStream **outStreams, const UInt64 **outSizes, - UInt32 streamIndex, ISequentialOutStream **outStreamRes); + CMyComPtr<ISequentialOutStream> _stream; + UInt64 _size; public: - STDMETHOD(Code)(ISequentialInStream **inStreams, - const UInt64 **inSizes, - UInt32 numInStreams, - ISequentialOutStream **outStreams, - const UInt64 **outSizes, - UInt32 numOutStreams, - ICompressProgressInfo *progress); + MY_UNKNOWN_IMP2(ISequentialOutStream, IOutStreamFlush) + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Flush)(); + + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init() { _size = 0; } + UInt64 GetSize() const { return _size; } +}; - CCoderMixer2ST(); - ~CCoderMixer2ST(); - void AddCoderCommon(bool isMain); - void AddCoder(ICompressCoder *coder, bool isMain); - void AddCoder2(ICompressCoder2 *coder, bool isMain); - void ReInit(); - void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) - { - { _coders[coderIndex].SetCoderInfo(inSizes, outSizes); } - } - void SetProgressCoderIndex(UInt32 /*coderIndex*/) - { - // _progressCoderIndex = coderIndex; - } +namespace NCoderMixer2 { - // UInt64 GetWriteProcessedSize(UInt32 binderIndex) const; +struct CCoderST: public CCoder +{ + bool CanRead; + bool CanWrite; + + CCoderST(): CanRead(false), CanWrite(false) {} +}; + + +struct CStBinderStream +{ + CSequentialInStreamCalcSize *InStreamSpec; + COutStreamCalcSize *OutStreamSpec; + CMyComPtr<IUnknown> StreamRef; + + CStBinderStream(): InStreamSpec(NULL), OutStreamSpec(NULL) {} +}; + + +class CMixerST: + public IUnknown, + public CMixer, + public CMyUnknownImp +{ + HRESULT GetInStream2(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ + UInt32 outStreamIndex, ISequentialInStream **inStreamRes); + HRESULT GetInStream(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ + UInt32 inStreamIndex, ISequentialInStream **inStreamRes); + HRESULT GetOutStream(ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */ + UInt32 outStreamIndex, ISequentialOutStream **outStreamRes); + + HRESULT FlushStream(UInt32 streamIndex); + HRESULT FlushCoder(UInt32 coderIndex); -private: - CBindInfo _bindInfo; - CObjectVector<CSTCoderInfo> _coders; - int _mainCoderIndex; public: - HRESULT SetBindInfo(const CBindInfo &bindInfo); + CObjectVector<CCoderST> _coders; + + CObjectVector<CStBinderStream> _binderStreams; + + MY_UNKNOWN_IMP + + CMixerST(bool encodeMode); + ~CMixerST(); + + virtual void AddCoder(ICompressCoder *coder, ICompressCoder2 *coder2, bool isFilter); + + virtual CCoder &GetCoder(unsigned index); + + virtual void SelectMainCoder(bool useFirst); + + virtual void ReInit(); + + virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes) + { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes); } + + virtual HRESULT Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, + ICompressProgressInfo *progress); + + virtual UInt64 GetBondStreamSize(unsigned bondIndex) const; + HRESULT GetMainUnpackStream( + ISequentialInStream * const *inStreams, + ISequentialInStream **inStreamRes); }; } diff --git a/CPP/7zip/Archive/Common/CoderMixerMT.h b/CPP/7zip/Archive/Common/CoderMixerMT.h index 9491a965..d2891b26 100644 --- a/CPP/7zip/Archive/Common/CoderMixerMT.h +++ b/CPP/7zip/Archive/Common/CoderMixerMT.h @@ -18,7 +18,7 @@ struct CCoder: public CCoderInfo, public CVirtThread virtual void Execute(); void Code(ICompressProgressInfo *progress); - ~CCoder() { CVirtThread::WaitThreadFinish(); } + virtual ~CCoder() { CVirtThread::WaitThreadFinish(); } }; /* diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp index 18ad5580..9c11b31d 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.cpp +++ b/CPP/7zip/Archive/Common/HandlerOut.cpp @@ -29,6 +29,7 @@ void CMultiMethodProps::SetGlobalLevelAndThreads(COneMethodInfo &oneMethodInfo UInt32 level = _level; if (level != (UInt32)(Int32)-1) SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level); + #ifndef _7ZIP_ST SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); #endif @@ -41,6 +42,8 @@ void CMultiMethodProps::Init() #endif _level = (UInt32)(Int32)-1; + _analysisLevel = -1; + _autoFilter = true; _crcSize = 4; _filterMethod.Clear(); @@ -60,8 +63,17 @@ HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIAN _level = 9; return ParsePropToUInt32(name, value, _level); } + + if (name.IsPrefixedBy_Ascii_NoCase("yx")) + { + name.Delete(0, 2); + UInt32 v = 9; + RINOK(ParsePropToUInt32(name, value, v)); + _analysisLevel = (int)v; + return S_OK; + } - if (name == L"crc") + if (name.IsEqualTo("crc")) { name.Delete(0, 3); _crcSize = 4; @@ -73,11 +85,12 @@ HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIAN UString realName = name.Ptr(index); if (index == 0) { - if (name.IsPrefixedBy(L"mt")) + if (name.IsPrefixedBy_Ascii_NoCase("mt")) { #ifndef _7ZIP_ST RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads)); #endif + return S_OK; } if (name.IsEqualTo("f")) @@ -87,7 +100,7 @@ HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIAN return res; if (value.vt != VT_BSTR) return E_INVALIDARG; - return _filterMethod.ParseMethodFromPROPVARIANT(L"", value); + return _filterMethod.ParseMethodFromPROPVARIANT(UString(), value); } number = 0; } @@ -101,14 +114,15 @@ HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIAN void CSingleMethodProps::Init() { Clear(); + _level = (UInt32)(Int32)-1; + #ifndef _7ZIP_ST _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors(); - AddNumThreadsProp(_numThreads); + AddProp_NumThreads(_numThreads); #endif - _level = (UInt32)(Int32)-1; } -HRESULT CSingleMethodProps::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { Init(); for (UInt32 i = 0; i < numProps; i++) @@ -123,13 +137,13 @@ HRESULT CSingleMethodProps::SetProperties(const wchar_t **names, const PROPVARIA UInt32 a = 9; RINOK(ParsePropToUInt32(name.Ptr(1), value, a)); _level = a; - AddLevelProp(a); + AddProp_Level(a); } - else if (name.IsPrefixedBy(L"mt")) + else if (name.IsPrefixedBy_Ascii_NoCase("mt")) { #ifndef _7ZIP_ST RINOK(ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads)); - AddNumThreadsProp(_numThreads); + AddProp_NumThreads(_numThreads); #endif } else diff --git a/CPP/7zip/Archive/Common/HandlerOut.h b/CPP/7zip/Archive/Common/HandlerOut.h index 40a4a698..5a18d980 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.h +++ b/CPP/7zip/Archive/Common/HandlerOut.h @@ -10,6 +10,7 @@ namespace NArchive { class CMultiMethodProps { UInt32 _level; + int _analysisLevel; public: #ifndef _7ZIP_ST UInt32 _numThreads; @@ -37,6 +38,7 @@ public: } int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } + int GetAnalysisLevel() const { return _analysisLevel; } void Init(); @@ -57,7 +59,7 @@ public: void Init(); CSingleMethodProps() { Init(); } int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } - HRESULT SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); + HRESULT SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); }; } diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp index 0526c1b1..77252938 100644 --- a/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp +++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp @@ -10,9 +10,9 @@ STDMETHODIMP COutStreamWithSha1::Write(const void *data, UInt32 size, UInt32 *pr if (_stream) result = _stream->Write(data, size, &size); if (_calculate) - _sha.Update((const Byte *)data, size); + Sha1_Update(&_sha, (const Byte *)data, size); _size += size; - if (processedSize != NULL) + if (processedSize) *processedSize = size; return result; } diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.h b/CPP/7zip/Archive/Common/OutStreamWithSha1.h index 3bbfbbe1..41a84cd6 100644 --- a/CPP/7zip/Archive/Common/OutStreamWithSha1.h +++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.h @@ -3,7 +3,7 @@ #ifndef __OUT_STREAM_WITH_SHA1_H #define __OUT_STREAM_WITH_SHA1_H -#include "../../Crypto/Sha1.h" +#include "../../../../C/Sha1.h" #include "../../../Common/MyCom.h" @@ -15,7 +15,7 @@ class COutStreamWithSha1: { CMyComPtr<ISequentialOutStream> _stream; UInt64 _size; - NCrypto::NSha1::CContext _sha; + CSha1 _sha; bool _calculate; public: MY_UNKNOWN_IMP @@ -26,11 +26,11 @@ public: { _size = 0; _calculate = calculate; - _sha.Init(); + Sha1_Init(&_sha); } - void InitSha1() { _sha.Init(); } + void InitSha1() { Sha1_Init(&_sha); } UInt64 GetSize() const { return _size; } - void Final(Byte *digest) { _sha.Final(digest); } + void Final(Byte *digest) { Sha1_Final(&_sha, digest); } }; #endif diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp index 431d315d..2436fb5e 100644 --- a/CPP/7zip/Archive/CpioHandler.cpp +++ b/CPP/7zip/Archive/CpioHandler.cpp @@ -87,7 +87,7 @@ enum EType k_Type_HexCrc }; -static const char *k_Types[] = +static const char * const k_Types[] = { "Binary LE" , "Binary BE" @@ -396,11 +396,10 @@ HRESULT CInArchive::GetNextItem(CItem &item, EErrorType &errorType) return S_FALSE; if (nameSize == 0 || nameSize >= kNameSizeMax) return S_OK; - char *s = item.Name.GetBuffer(nameSize); + char *s = item.Name.GetBuf(nameSize); size_t processedSize = nameSize; RINOK(Read(s, &processedSize)); - s[nameSize] = 0; - item.Name.ReleaseBuffer(); + item.Name.ReleaseBuf_CalcLen(nameSize); if (processedSize != nameSize) { errorType = k_ErrorType_UnexpectedEnd; @@ -451,7 +450,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) NCOM::CPropVariant prop; switch (propID) { - case kpidSubType: prop = k_Types[_Type]; break; + case kpidSubType: prop = k_Types[(unsigned)_Type]; break; case kpidPhySize: prop = _phySize; break; case kpidErrorFlags: { @@ -780,20 +779,16 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -IMP_CreateArcIn - -static CArcInfo g_ArcInfo = - { "Cpio", "cpio", 0, 0xED, - 3 + 5 + 2 + 2, - { +static const Byte k_Signature[] = { 5, '0', '7', '0', '7', '0', 2, kMagicBin0, kMagicBin1, - 2, kMagicBin1, kMagicBin0, - }, + 2, kMagicBin1, kMagicBin0 }; + +REGISTER_ARC_I( + "Cpio", "cpio", 0, 0xED, + k_Signature, 0, NArcInfoFlags::kMultiSignature, - CreateArc, NULL, IsArc_Cpio }; - -REGISTER_ARC(Cpio) + IsArc_Cpio) }} diff --git a/CPP/7zip/Archive/CramfsHandler.cpp b/CPP/7zip/Archive/CramfsHandler.cpp index 3764f1af..e776b3c7 100644 --- a/CPP/7zip/Archive/CramfsHandler.cpp +++ b/CPP/7zip/Archive/CramfsHandler.cpp @@ -26,8 +26,7 @@ namespace NCramfs { #define SIGNATURE { 'C','o','m','p','r','e','s','s','e','d',' ','R','O','M','F','S' } -static const UInt32 kSignatureSize = 16; -static const char kSignature[kSignatureSize] = SIGNATURE; +static const Byte kSignature[] = SIGNATURE; static const UInt32 kArcSizeMax = (256 + 16) << 20; static const UInt32 kNumFilesMax = (1 << 19); @@ -55,7 +54,7 @@ static const unsigned k_Flags_Method_Mask = 3; #define k_Flags_Method_ZLIB 1 #define k_Flags_Method_LZMA 2 -static const char *k_Methods[] = +static const char * const k_Methods[] = { "Copy" , "ZLIB" @@ -145,7 +144,7 @@ struct CHeader bool Parse(const Byte *p) { - if (memcmp(p + 16, kSignature, kSignatureSize) != 0) + if (memcmp(p + 16, kSignature, ARRAY_SIZE(kSignature)) != 0) return false; switch(GetUi32(p)) { @@ -408,7 +407,7 @@ AString CHandler::GetPath(int index) const len--; AString path; - char *dest = path.GetBuffer(len) + len; + char *dest = path.GetBuf_SetEnd(len) + len; index = indexMem; for (;;) { @@ -425,7 +424,6 @@ AString CHandler::GetPath(int index) const break; *(--dest) = CHAR_PATH_SEPARATOR; } - path.ReleaseBuffer(len); return path; } @@ -565,10 +563,6 @@ 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 (_method == k_Flags_Method_ZLIB) @@ -789,15 +783,11 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -IMP_CreateArcIn - -static CArcInfo g_ArcInfo = - { "CramFS", "cramfs", 0, 0xD3, - kSignatureSize, SIGNATURE, +REGISTER_ARC_I( + "CramFS", "cramfs", 0, 0xD3, + kSignature, 16, 0, - CreateArc }; - -REGISTER_ARC(Cramfs) + NULL) }} diff --git a/CPP/7zip/Archive/DllExports.cpp b/CPP/7zip/Archive/DllExports.cpp index 37f53cd7..7aee235e 100644 --- a/CPP/7zip/Archive/DllExports.cpp +++ b/CPP/7zip/Archive/DllExports.cpp @@ -13,10 +13,13 @@ #include "../../Windows/NtCheck.h" #include "../../Windows/PropVariant.h" -#include "IArchive.h" #include "../ICoder.h" #include "../IPassword.h" +#include "../Common/CreateCoder.h" + +#include "IArchive.h" + HINSTANCE g_hInstance; #define NT_CHECK_FAIL_ACTION return FALSE; @@ -33,7 +36,10 @@ BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) } DEFINE_GUID(CLSID_CArchiveHandler, -0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00); + k_7zip_GUID_Data1, + k_7zip_GUID_Data2, + k_7zip_GUID_Data3_Common, + 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00); STDAPI CreateArchiver(const GUID *classID, const GUID *iid, void **outObject); @@ -49,3 +55,40 @@ STDAPI SetLargePageMode() #endif return S_OK; } + +extern bool g_CaseSensitive; + +STDAPI SetCaseSensitive(Int32 caseSensitive) +{ + g_CaseSensitive = (caseSensitive != 0); + return S_OK; +} + +#ifdef EXTERNAL_CODECS + +CExternalCodecs g_ExternalCodecs; + +STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo) +{ + COM_TRY_BEGIN + + // OutputDebugStringA(compressCodecsInfo ? "SetCodecs" : "SetCodecs NULL"); + if (compressCodecsInfo) + { + g_ExternalCodecs.GetCodecs = compressCodecsInfo; + return g_ExternalCodecs.Load(); + } + g_ExternalCodecs.ClearAndRelease(); + return S_OK; + + COM_TRY_END +} + +#else + +STDAPI SetCodecs(ICompressCodecsInfo *) +{ + return S_OK; +} + +#endif diff --git a/CPP/7zip/Archive/DllExports2.cpp b/CPP/7zip/Archive/DllExports2.cpp index aa023524..2b196abe 100644 --- a/CPP/7zip/Archive/DllExports2.cpp +++ b/CPP/7zip/Archive/DllExports2.cpp @@ -16,6 +16,8 @@ #include "../ICoder.h" #include "../IPassword.h" +#include "../Common/CreateCoder.h" + #include "IArchive.h" HINSTANCE g_hInstance; @@ -33,23 +35,28 @@ BOOL WINAPI DllMain( { if (dwReason == DLL_PROCESS_ATTACH) { + // OutputDebugStringA("7z.dll DLL_PROCESS_ATTACH"); g_hInstance = (HINSTANCE)hInstance; NT_CHECK; } + /* + if (dwReason == DLL_PROCESS_DETACH) + { + OutputDebugStringA("7z.dll DLL_PROCESS_DETACH"); + } + */ return TRUE; } DEFINE_GUID(CLSID_CArchiveHandler, -0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00); - -static const UInt16 kDecodeId = 0x2790; - -DEFINE_GUID(CLSID_CCodec, -0x23170F69, 0x40C1, kDecodeId, 0, 0, 0, 0, 0, 0, 0, 0); + k_7zip_GUID_Data1, + k_7zip_GUID_Data2, + k_7zip_GUID_Data3_Common, + 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00); 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 CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject); STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject) { @@ -80,3 +87,32 @@ STDAPI SetCaseSensitive(Int32 caseSensitive) g_CaseSensitive = (caseSensitive != 0); return S_OK; } + +#ifdef EXTERNAL_CODECS + +CExternalCodecs g_ExternalCodecs; + +STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo) +{ + COM_TRY_BEGIN + + // OutputDebugStringA(compressCodecsInfo ? "SetCodecs" : "SetCodecs NULL"); + if (compressCodecsInfo) + { + g_ExternalCodecs.GetCodecs = compressCodecsInfo; + return g_ExternalCodecs.Load(); + } + g_ExternalCodecs.ClearAndRelease(); + return S_OK; + + COM_TRY_END +} + +#else + +STDAPI SetCodecs(ICompressCodecsInfo *) +{ + return S_OK; +} + +#endif diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp index 7166f2ce..208f2a82 100644 --- a/CPP/7zip/Archive/DmgHandler.cpp +++ b/CPP/7zip/Archive/DmgHandler.cpp @@ -48,6 +48,7 @@ static Byte *Base64ToBin(Byte *dest, const char *src) { UInt32 val = 1; UInt32 c = k_Base64Table[(Byte)(*src++)]; + for (;;) { /* @@ -88,12 +89,14 @@ static Byte *Base64ToBin(Byte *dest, const char *src) break; c = k_Base64Table[(Byte)(*src++)]; } + if (val >= ((UInt32)1 << 12)) { if (val >= ((UInt32)1 << 18)) *dest++ = (Byte)(val >> 16); *dest++ = (Byte)(val); } + return dest; } @@ -195,7 +198,8 @@ public: STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; -const UInt32 kXmlSizeMax = ((UInt32)1 << 31) - (1 << 14); +// that limit can be increased, if there are such dmg files +static const size_t kXmlSizeMax = 0xFFFF0000; // 4 GB - 64 KB; struct CMethods { @@ -216,7 +220,9 @@ void CMethods::Update(const CFile &file) void CMethods::GetString(AString &res) const { res.Empty(); + unsigned i; + for (i = 0; i < Types.Size(); i++) { UInt32 type = Types[i]; @@ -234,10 +240,10 @@ void CMethods::GetString(AString &res) const case METHOD_BZIP2: s = "BZip2"; break; default: ConvertUInt32ToString(type, buf); s = buf; } - if (!res.IsEmpty()) - res += ' '; + res.Add_Space_if_NotEmpty(); res += s; } + for (i = 0; i < ChecksumTypes.Size(); i++) { UInt32 type = ChecksumTypes[i]; @@ -250,8 +256,7 @@ void CMethods::GetString(AString &res) const ConvertUInt32ToString(type, MyStpCpy(buf, "Check")); s = buf; } - if (!res.IsEmpty()) - res += ' '; + res.Add_Space_if_NotEmpty(); res += s; } } @@ -325,8 +330,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidMainSubfile: { int mainIndex = -1; - int numFS = 0; - int numUnknown = 0; + unsigned numFS = 0; + unsigned numUnknown = 0; FOR_VECTOR (i, _files) { const AString &name = _files[i].Name; @@ -334,7 +339,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) for (n = 0; n < kNumAppleNames; n++) { const CAppleName &appleName = k_Names[n]; - if (name.Find(appleName.AppleName) >= 0) + // if (name.Find(appleName.AppleName) >= 0) + if (strstr(name, appleName.AppleName)) { if (appleName.IsFs) { @@ -404,6 +410,7 @@ HRESULT CFile::Parse(const Byte *p, UInt32 size) p += kHeadSize; UInt32 i; + for (i = 0; i < numBlocks; i++, p += kRecordSize) { CBlock b; @@ -426,6 +433,7 @@ HRESULT CFile::Parse(const Byte *p, UInt32 size) if (b.Type == METHOD_END) break; PackSize += b.PackSize; + if (b.UnpSize != 0) { if (b.Type == METHOD_ZERO_2) @@ -433,12 +441,14 @@ HRESULT CFile::Parse(const Byte *p, UInt32 size) 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; } @@ -463,8 +473,12 @@ static const AString *GetStringFromKeyPair(const CXmlItem &item, const AString & static const unsigned HEADER_SIZE = 0x200; -static bool IsKoly(const Byte *p) +static const Byte k_Signature[] = { 'k','o','l','y', 0, 0, 0, 4, 0, 0, 2, 0 }; + +static inline bool IsKoly(const Byte *p) { + return memcmp(p, k_Signature, ARRAY_SIZE(k_Signature)) == 0; + /* if (Get32(p) != 0x6B6F6C79) // "koly" signature return false; if (Get32(p + 4) != 4) // version @@ -472,6 +486,7 @@ static bool IsKoly(const Byte *p) if (Get32(p + 8) != HEADER_SIZE) return false; return true; + */ } HRESULT CHandler::Open2(IInStream *stream) @@ -510,6 +525,14 @@ HRESULT CHandler::Open2(IInStream *stream) UInt64 xmlOffset = Get64(buf + 0xD8); UInt64 xmlLen = Get64(buf + 0xE0); + if ( headerPos < dataForkOffset + || headerPos - dataForkOffset < dataForkLen + || headerPos < rsrcOffset + || headerPos - rsrcOffset < rsrcLen + || headerPos < xmlOffset + || headerPos - xmlOffset < xmlLen) + return S_FALSE; + UInt64 totalLen = dataForkLen + rsrcLen + xmlLen; if (totalLen > headerPos) return S_FALSE; @@ -517,14 +540,6 @@ HRESULT CHandler::Open2(IInStream *stream) _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; - // Byte reserved[0x78] CChecksum masterChecksum; @@ -620,9 +635,7 @@ HRESULT CHandler::Open2(IInStream *stream) ConvertUInt32ToString(_files.Size(), extraName); extra.Name = extraName; } - CByteBuffer &rawBuf = extra.Data; - rawBuf.SetCapacity(blockSize); - memcpy(rawBuf, pBlock + 4, blockSize); + extra.Data.CopyFrom(pBlock + 4, blockSize); } #endif @@ -638,10 +651,10 @@ HRESULT CHandler::Open2(IInStream *stream) return S_FALSE; for (UInt32 r = 1; r <= nameLen; r++) { - char c = namePtr[r]; + Byte c = namePtr[r]; if (c < 0x20 || c >= 0x80) break; - file.Name += c; + file.Name += (char)c; } } RINOK(file.Parse(pBlock + 4, blockSize)); @@ -652,36 +665,28 @@ HRESULT CHandler::Open2(IInStream *stream) { if (xmlLen >= kXmlSizeMax || xmlLen == 0) return S_FALSE; - RINOK(stream->Seek(_startPos + dataForkLen, STREAM_SEEK_SET, NULL)); size_t size = (size_t)xmlLen; + if (size != xmlLen) + return S_FALSE; + + RINOK(stream->Seek(_startPos + dataForkLen, STREAM_SEEK_SET, NULL)); CXml xml; { - AString xmlStr; - char *ss = xmlStr.GetBuffer((int)size + 1); - RINOK(ReadStream_FALSE(stream, ss, size)); - ss[size] = 0; - { - 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)); - } + CObjArray<char> xmlStr(size + 1); + RINOK(ReadStream_FALSE(stream, xmlStr, size)); + xmlStr[size] = 0; + // if (strlen(xmlStr) != size) return S_FALSE; 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); + extra.Data.CopyFrom((const Byte *)(const char *)xmlStr, size); #endif } + if (xml.Root.Name != "plist") return S_FALSE; @@ -708,14 +713,14 @@ HRESULT CHandler::Open2(IInStream *stream) continue; CByteBuffer rawBuf; - int destLen = 0; + unsigned 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); + destLen = (unsigned)(Base64ToBin(rawBuf, *dataString) - rawBuf); #ifdef DMG_SHOW_RAW CExtraFile &extra = _extras.AddNew(); { @@ -723,8 +728,7 @@ HRESULT CHandler::Open2(IInStream *stream) ConvertUInt32ToString(_files.Size(), extraName); extra.Name = extraName; } - extra.Data.SetCapacity(destLen); - memcpy(extra.Data, rawBuf, destLen); + extra.Data.CopyFrom(rawBuf, destLen); #endif } CFile &file = _files.AddNew(); @@ -805,7 +809,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val NWindows::NCOM::CPropVariant prop; #ifdef DMG_SHOW_RAW - if ((int)index >= _files.Size()) + if (index >= _files.Size()) { const CExtraFile &extra = _extras[index - _files.Size()]; switch (propID) @@ -897,7 +901,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val UString name2; ConvertUTF8ToUnicode(item.Name, name2); if (!name2.IsEmpty()) - name += L" - "; + name.AddAscii(" - "); name += name2; } prop = name; @@ -1060,9 +1064,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, return S_OK; UInt64 totalSize = 0; UInt32 i; + for (i = 0; i < numItems; i++) { - int index = (int)(allFilesMode ? i : indices[i]); + UInt32 index = (allFilesMode ? i : indices[i]); #ifdef DMG_SHOW_RAW if (index >= _files.Size()) totalSize += _extras[index - _files.Size()].Data.Size(); @@ -1112,7 +1117,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 (!testMode && !realOutStream) @@ -1225,6 +1230,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, opRes = NExtract::NOperationResult::kUnsupportedMethod; break; } + if (res != S_OK) { if (res != S_FALSE) @@ -1232,7 +1238,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (opRes == NExtract::NOperationResult::kOK) opRes = NExtract::NOperationResult::kDataError; } + unpPos += block.UnpSize; + if (!outStreamSpec->IsFinishedOK()) { if (realMethod && opRes == NExtract::NOperationResult::kOK) @@ -1247,6 +1255,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } } } + if (needCrc && opRes == NExtract::NOperationResult::kOK) { if (outCrcStreamSpec->GetCRC() != item.Checksum.GetCrc32()) @@ -1256,6 +1265,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, outStream.Release(); RINOK(extractCallback->SetOperationResult(opRes)); } + return S_OK; COM_TRY_END } @@ -1322,12 +1332,12 @@ public: }; -int FindBlock(const CRecordVector<CBlock> &blocks, UInt64 pos) +unsigned FindBlock(const CRecordVector<CBlock> &blocks, UInt64 pos) { - int left = 0, right = blocks.Size(); + unsigned left = 0, right = blocks.Size(); for (;;) { - int mid = (left + right) / 2; + unsigned mid = (left + right) / 2; if (mid == left) return left; if (pos < blocks[mid].UnpPos) @@ -1359,23 +1369,27 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) if (_virtPos < block.UnpPos || (_virtPos - block.UnpPos) >= block.UnpSize) _latestBlock = -1; } + if (_latestBlock < 0) { _latestChunk = -1; - int blockIndex = FindBlock(File->Blocks, _virtPos); + unsigned 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) + if (_chunks[i].BlockIndex == (int)blockIndex) break; + if (i != _chunks.Size()) _latestChunk = i; else { - const int kNumChunksMax = 128; - int chunkIndex; + const unsigned kNumChunksMax = 128; + unsigned chunkIndex; + if (_chunks.Size() != kNumChunksMax) chunkIndex = _chunks.Add(CChunk()); else @@ -1385,9 +1399,11 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 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(); @@ -1395,12 +1411,14 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 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: @@ -1443,6 +1461,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) default: return E_FAIL; } + if (res != S_OK) return res; if (block.Type != METHOD_COPY && outStreamSpec->GetPos() != block.UnpSize) @@ -1450,8 +1469,10 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) chunk.BlockIndex = blockIndex; _latestChunk = chunkIndex; } + _chunks[_latestChunk].AccessMark = _accessMark++; } + _latestBlock = blockIndex; } @@ -1462,6 +1483,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) 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)); @@ -1469,11 +1491,13 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) } else if (block.IsZeroMethod()) memset(data, 0, size); - else + else if (size != 0) memcpy(data, _chunks[_latestChunk].Buf + offset, size); + _virtPos += size; if (processedSize) *processedSize = size; + return res; COM_TRY_END } @@ -1498,14 +1522,17 @@ STDMETHODIMP CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPositio 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]; @@ -1523,24 +1550,22 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) 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 = - { "Dmg", "dmg", 0, 0xE4, - 12, { 'k','o','l','y', 0, 0, 0, 4, 0, 0, 2, 0 }, +REGISTER_ARC_I( + "Dmg", "dmg", 0, 0xE4, + k_Signature, 0, NArcInfoFlags::kBackwardOpen | NArcInfoFlags::kUseGlobalOffset, - CreateArc }; - -REGISTER_ARC(Dmg) + NULL) }} diff --git a/CPP/7zip/Archive/ElfHandler.cpp b/CPP/7zip/Archive/ElfHandler.cpp index 5e378ba8..089d1023 100644 --- a/CPP/7zip/Archive/ElfHandler.cpp +++ b/CPP/7zip/Archive/ElfHandler.cpp @@ -963,15 +963,13 @@ STDMETHODIMP CHandler::AllowTail(Int32 allowTail) return S_OK; } -IMP_CreateArcIn +static const Byte k_Signature[] = { 0x7F, 'E', 'L', 'F' }; -static CArcInfo g_ArcInfo = - { "ELF", "elf", 0, 0xDE, - 4, { 0x7F, 'E', 'L', 'F' }, +REGISTER_ARC_I( + "ELF", "elf", 0, 0xDE, + k_Signature, 0, NArcInfoFlags::kPreArc, - CreateArc }; - -REGISTER_ARC(Elf) + NULL) }} diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp index 970330cc..649d54bd 100644 --- a/CPP/7zip/Archive/FatHandler.cpp +++ b/CPP/7zip/Archive/FatHandler.cpp @@ -272,19 +272,27 @@ struct CItem UString GetVolName() const; }; -static int CopyAndTrim(char *dest, const char *src, int size, bool toLower) +static unsigned CopyAndTrim(char *dest, const char *src, unsigned size, bool toLower) { - int i; memcpy(dest, src, size); if (toLower) - for (i = 0; i < size; i++) + { + for (unsigned i = 0; i < size; i++) { char c = dest[i]; if (c >= 'A' && c <= 'Z') dest[i] = (char)(c + 0x20); } - for (i = size - 1; i >= 0 && dest[i] == ' '; i--); - return i + 1; + } + + for (unsigned i = size;;) + { + if (i == 0) + return 0; + if (dest[i - 1] != ' ') + return i; + i--; + } } static UString FatStringToUnicode(const char *s) @@ -295,11 +303,11 @@ static UString FatStringToUnicode(const char *s) UString CItem::GetShortName() const { char s[16]; - int i = CopyAndTrim(s, DosName, 8, NameIsLow()); + unsigned i = CopyAndTrim(s, DosName, 8, NameIsLow()); s[i++] = '.'; - int j = CopyAndTrim(s + i, DosName + 8, 3, ExtIsLow()); + unsigned j = CopyAndTrim(s + i, DosName + 8, 3, ExtIsLow()); if (j == 0) - j--; + i--; s[i + j] = 0; return FatStringToUnicode(s); } @@ -316,7 +324,7 @@ UString CItem::GetVolName() const if (!UName.IsEmpty()) return UName; char s[12]; - int i = CopyAndTrim(s, DosName, 11, false); + unsigned i = CopyAndTrim(s, DosName, 11, false); s[i] = 0; return FatStringToUnicode(s); } @@ -348,7 +356,7 @@ struct CDatabase UString GetItemPath(Int32 index) const; HRESULT Open(); - HRESULT ReadDir(Int32 parent, UInt32 cluster, int level); + HRESULT ReadDir(Int32 parent, UInt32 cluster, unsigned level); UInt64 GetHeadersSize() const { @@ -420,9 +428,9 @@ UString CDatabase::GetItemPath(Int32 index) const } } -static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, int numChars) +static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, unsigned numChars) { - for (int i = 0; i < numChars; i++) + for (unsigned i = 0; i < numChars; i++) { wchar_t c = Get16(p + i * 2); if (c != 0 && c != 0xFFFF) @@ -432,9 +440,9 @@ static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, int numChars) return dest; } -HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level) +HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level) { - int startIndex = Items.Size(); + unsigned startIndex = Items.Size(); if (startIndex >= (1 << 30) || level > 256) return S_FALSE; @@ -451,6 +459,7 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level) UString curName; int checkSum = -1; int numLongRecords = -1; + for (UInt32 pos = blockSize;; pos += 32) { if (pos == blockSize) @@ -483,7 +492,9 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level) RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize)); } + const Byte *p = ByteBuf + pos; + if (p[0] == 0) { /* @@ -493,6 +504,7 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level) */ break; } + if (p[0] == 0xE5) { if (numLongRecords > 0) @@ -545,7 +557,7 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level) if (checkSum >= 0) { Byte sum = 0; - for (int i = 0; i < 11; i++) + for (unsigned i = 0; i < 11; i++) sum = (Byte)(((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i]); if (sum == checkSum) item.UName = curName; @@ -590,8 +602,8 @@ HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, int level) } } - int finishIndex = Items.Size(); - for (int i = startIndex; i < finishIndex; i++) + unsigned finishIndex = Items.Size(); + for (unsigned i = startIndex; i < finishIndex; i++) { const CItem &item = Items[i]; if (item.IsDir()) @@ -831,7 +843,7 @@ static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVari } /* -static void StringToProp(const Byte *src, int size, NWindows::NCOM::CPropVariant &prop) +static void StringToProp(const Byte *src, unsigned size, NWindows::NCOM::CPropVariant &prop) { char dest[32]; memcpy(dest, src, size); @@ -1021,15 +1033,13 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -IMP_CreateArcIn +static const Byte k_Signature[] = { 0x55, 0xAA }; -static CArcInfo g_ArcInfo = - { "FAT", "fat img", 0, 0xDA, - 2, { 0x55, 0xAA }, +REGISTER_ARC_I( + "FAT", "fat img", 0, 0xDA, + k_Signature, 0x1FE, 0, - CreateArc, NULL, IsArc_Fat }; - -REGISTER_ARC(Fat) + IsArc_Fat) }} diff --git a/CPP/7zip/Archive/FlvHandler.cpp b/CPP/7zip/Archive/FlvHandler.cpp index 577224b2..dafb250b 100644 --- a/CPP/7zip/Archive/FlvHandler.cpp +++ b/CPP/7zip/Archive/FlvHandler.cpp @@ -2,6 +2,8 @@ #include "StdAfx.h" +// #include <stdio.h> + #include "../../../C/CpuArch.h" #include "../../Common/ComTry.h" @@ -69,12 +71,12 @@ class CHandler: { CMyComPtr<IInStream> _stream; CObjectVector<CItem2> _items2; - // CByteBuffer _metadata; + CByteBuffer _metadata; bool _isRaw; UInt64 _phySize; HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); - AString GetComment(); + // AString GetComment(); public: MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) @@ -195,10 +197,7 @@ AString CHandler::GetComment() break; { AString temp; - char *sz = temp.GetBuffer(len); - memcpy(sz, p, len); - sz[len] = 0; - temp.ReleaseBuffer(); + temp.SetFrom_CalcLen((const char *)p, len); if (!res.IsEmpty()) res += '\n'; res += temp; @@ -251,7 +250,6 @@ AString CHandler::GetComment() } return res; } - */ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) @@ -413,8 +411,11 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) src += kTagHeaderSize + 1; size -= (kTagHeaderSize + 4 + 1); } - memcpy(item2.BufSpec->Buf + item2.Size, src, size); - item2.Size += size; + if (size != 0) + { + memcpy(item2.BufSpec->Buf + item2.Size, src, size); + item2.Size += size; + } } return S_OK; } @@ -513,15 +514,13 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -IMP_CreateArcIn +static const Byte k_Signature[] = { 'F', 'L', 'V', 1, }; -static CArcInfo g_ArcInfo = - { "FLV", "flv", 0, 0xD6, - 4, { 'F', 'L', 'V', 1, }, +REGISTER_ARC_I( + "FLV", "flv", 0, 0xD6, + k_Signature, 0, 0, - CreateArc }; - -REGISTER_ARC(Flv) + NULL) }} diff --git a/CPP/7zip/Archive/GzHandler.cpp b/CPP/7zip/Archive/GzHandler.cpp index 766cefbf..d8979ada 100644 --- a/CPP/7zip/Archive/GzHandler.cpp +++ b/CPP/7zip/Archive/GzHandler.cpp @@ -44,10 +44,10 @@ namespace NGz { namespace NFlags { - const Byte kIsText = 1 << 0; - const Byte kCrc = 1 << 1; - const Byte kExtra = 1 << 2; - const Byte kName = 1 << 3; + const Byte kIsText = 1 << 0; + const Byte kCrc = 1 << 1; + const Byte kExtra = 1 << 2; + const Byte kName = 1 << 3; const Byte kComment = 1 << 4; const Byte kReserved = 0xE0; } @@ -85,7 +85,7 @@ namespace NGz { }; } -static const char *kHostOSes[] = +static const char * const kHostOSes[] = { "FAT" , "AMIGA" @@ -126,19 +126,44 @@ public: AString Comment; // CByteBuffer Extra; - // 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; } + CItem(): + Flags(0), + ExtraFlags(0), + HostOS(0), + Time(0), + Crc(0), + Size32(0) {} void Clear() { Name.Empty(); Comment.Empty(); - // Extra.SetCapacity(0); + // Extra.Free(); + } + + void CopyMetaPropsFrom(const CItem &a) + { + Flags = a.Flags; + HostOS = a.HostOS; + Time = a.Time; + Name = a.Name; + Comment = a.Comment; + // Extra = a.Extra; + } + + void CopyDataPropsFrom(const CItem &a) + { + ExtraFlags = a.ExtraFlags; + Crc = a.Crc; + Size32 = a.Size32; } + + // 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; } HRESULT ReadHeader(NDecoder::CCOMCoder *stream); HRESULT ReadFooter1(NDecoder::CCOMCoder *stream); @@ -459,7 +484,7 @@ public: INTERFACE_IInArchive(;) INTERFACE_IOutArchive(;) STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); CHandler() { @@ -510,7 +535,11 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) } case kpidName: if (_item.NameIsPresent()) - prop = MultiByteToUnicodeString(_item.Name, CP_ACP) + L".gz"; + { + UString s = MultiByteToUnicodeString(_item.Name, CP_ACP); + s.AddAscii(".gz"); + prop = s; + } break; } prop.Detach(value); @@ -656,7 +685,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; - // if (_stream) extractCallback->SetTotal(_packSize); + if (_packSize_Defined) + extractCallback->SetTotal(_packSize); // UInt64 currentTotalPacked = 0; // RINOK(extractCallback->SetCompleted(¤tTotalPacked)); CMyComPtr<ISequentialOutStream> realOutStream; @@ -794,6 +824,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, result = S_FALSE; break; } + + // break; // we can use break, if we need only first stream } } catch(const CInBufferException &e) { return e.ErrorCode; } @@ -844,7 +876,7 @@ static const Byte kHostOS = static HRESULT UpdateArchive( ISequentialOutStream *outStream, UInt64 unpackSize, - const CItem &newItem, + CItem &item, const CSingleMethodProps &props, IArchiveUpdateCallback *updateCallback) { @@ -865,7 +897,6 @@ static HRESULT UpdateArchive( CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(updateCallback, true); - CItem item = newItem; item.ExtraFlags = props.GetLevel() >= 7 ? NExtraFlags::kMaximum : NExtraFlags::kFastest; @@ -894,6 +925,8 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) { + COM_TRY_BEGIN + if (numItems != 1) return E_INVALIDARG; @@ -903,11 +936,15 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return E_FAIL; RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); - CItem newItem = _item; - newItem.ExtraFlags = 0; - newItem.Flags = 0; - if (IntToBool(newProps)) + CItem newItem; + + if (!IntToBool(newProps)) + { + newItem.CopyMetaPropsFrom(_item); + } + else { + newItem.HostOS = kHostOS; { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(0, kpidMTime, &prop)); @@ -924,9 +961,9 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (prop.vt == VT_BSTR) { UString name = prop.bstrVal; - int dirDelimiterPos = name.ReverseFind(WCHAR_PATH_SEPARATOR); - if (dirDelimiterPos >= 0) - name = name.Ptr(dirDelimiterPos + 1); + int slashPos = name.ReverseFind_PathSepar(); + if (slashPos >= 0) + name.DeleteFrontal(slashPos + 1); newItem.Name = UnicodeStringToMultiByte(name, CP_ACP); if (!newItem.Name.IsEmpty()) newItem.Flags |= NFlags::kName; @@ -937,13 +974,9 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)); - if (prop.vt == VT_BOOL) - { - if (prop.boolVal != VARIANT_FALSE) + if (prop.vt != VT_EMPTY) + if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE) return E_INVALIDARG; - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; } } @@ -959,13 +992,28 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt } return UpdateArchive(outStream, size, newItem, _props, updateCallback); } - + if (indexInArchive != 0) return E_INVALIDARG; if (!_stream) return E_NOTIMPL; + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(updateCallback, true); + + CMyComPtr<IArchiveUpdateCallbackFile> opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, 0, + NUpdateNotifyOp::kReplicate)) + } + + newItem.CopyDataPropsFrom(_item); + UInt64 offset = 0; if (IntToBool(newProps)) { @@ -973,24 +1021,24 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt offset += _headerSize; } RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); - return NCompress::CopyStream(_stream, outStream, NULL); + + return NCompress::CopyStream(_stream, outStream, progress); + + COM_TRY_END } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { return _props.SetProperties(names, values, numProps); } -IMP_CreateArcIn -IMP_CreateArcOut +static const Byte k_Signature[] = { kSignature_0, kSignature_1, kSignature_2 }; -static CArcInfo g_ArcInfo = - { "gzip", "gz gzip tgz tpz", "* * .tar .tar", 0xEF, - 3, { kSignature_0, kSignature_1, kSignature_2 }, +REGISTER_ARC_IO( + "gzip", "gz gzip tgz tpz", "* * .tar .tar", 0xEF, + k_Signature, 0, NArcInfoFlags::kKeepName, - REF_CreateArc_Pair, IsArc_Gz }; - -REGISTER_ARC(GZip) + IsArc_Gz) }} diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp index ca1370d8..8459280d 100644 --- a/CPP/7zip/Archive/HfsHandler.cpp +++ b/CPP/7zip/Archive/HfsHandler.cpp @@ -28,7 +28,7 @@ namespace NArchive { namespace NHfs { -static const wchar_t *kResFileName = L"rsrc"; // L"com.apple.ResourceFork"; +static const char *kResFileName = "rsrc"; // "com.apple.ResourceFork"; struct CExtent { @@ -655,12 +655,17 @@ HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjec static void LoadName(const Byte *data, unsigned len, UString &dest) { - wchar_t *p = dest.GetBuffer(len); + wchar_t *p = dest.GetBuf(len); unsigned i; for (i = 0; i < len; i++) - p[i] = Get16(data + i * 2); + { + wchar_t c = Get16(data + i * 2); + if (c == 0) + break; + p[i] = c; + } p[i] = 0; - dest.ReleaseBuffer(); + dest.ReleaseBuf_SetLen(i); } static bool IsNameEqualTo(const Byte *data, const char *name) @@ -805,7 +810,7 @@ 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") + if (!attr.Name.IsEqualTo("com.apple.decmpfs")) return true; if (item.UseAttr || !item.DataFork.IsEmpty()) return false; @@ -961,13 +966,13 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents IsNameEqualTo(name + 8, "HFS+ Private Data")) { // it's folder for "Hard Links" files - item.Name = L"[HFS+ Private Data]"; + item.Name.SetFromAscii("[HFS+ Private Data]"); } } // Some dmg files have ' ' folder item. if (item.Name.IsEmpty() || item.Name[0] == L' ') - item.Name = L"[]"; + item.Name.SetFromAscii("[]"); } } @@ -1221,7 +1226,7 @@ HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress) return S_FALSE; */ - ResFileName = kResFileName; + ResFileName.SetFromAscii(kResFileName); CFork extentsFork, catalogFork, attrFork; // allocationFork.Parse(p + 0x70 + 0x50 * 0); @@ -1856,19 +1861,15 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) return GetForkStream(item.GetFork(ref.IsResource), stream); } -IMP_CreateArcIn - -static CArcInfo g_ArcInfo = - { "HFS", "hfs hfsx", 0, 0xE3, - 2 * (4 + 1), - { +static const Byte k_Signature[] = { 4, 'H', '+', 0, 4, - 4, 'H', 'X', 0, 5, - }, + 4, 'H', 'X', 0, 5 }; + +REGISTER_ARC_I( + "HFS", "hfs hfsx", 0, 0xE3, + k_Signature, kHeaderPadSize, NArcInfoFlags::kMultiSignature, - CreateArc }; - -REGISTER_ARC(Hfs) + NULL) }} diff --git a/CPP/7zip/Archive/IArchive.h b/CPP/7zip/Archive/IArchive.h index a57a9b8f..84a4cc4b 100644 --- a/CPP/7zip/Archive/IArchive.h +++ b/CPP/7zip/Archive/IArchive.h @@ -82,10 +82,22 @@ namespace NArchive kUnexpectedEnd, kDataAfterEnd, kIsNotArc, - kHeadersError + kHeadersError, + kWrongPassword }; } } + + namespace NEventIndexType + { + enum + { + kNoIndex = 0, + kInArcIndex, + kBlockIndex, + kOutArcIndex + }; + } namespace NUpdate { @@ -110,17 +122,59 @@ ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10) }; /* -IArchiveExtractCallback::GetStream - Result: +IArchiveExtractCallback:: + +7-Zip doesn't call IArchiveExtractCallback functions + GetStream() + PrepareOperation() + SetOperationResult() +from different threads simultaneously. +But 7-Zip can call functions for IProgress or ICompressProgressInfo functions +from another threads simultaneously with calls for IArchiveExtractCallback interface. + +IArchiveExtractCallback::GetStream() + UInt32 index - index of item in Archive + Int32 askExtractMode (Extract::NAskMode) + if (askMode != NExtract::NAskMode::kExtract) + { + then the callee can not real stream: (*inStream == NULL) + } + + Out: (*inStream == NULL) - for directories (*inStream == NULL) - if link (hard link or symbolic link) was created + if (*inStream == NULL && askMode == NExtract::NAskMode::kExtract) + { + then the caller must skip extracting of that file. + } + + returns: + S_OK : OK + S_FALSE : data error (for decoders) + +if (IProgress::SetTotal() was called) +{ + IProgress::SetCompleted(completeValue) uses + packSize - for some stream formats (xz, gz, bz2, lzma, z, ppmd). + unpackSize - for another formats. +} +else +{ + IProgress::SetCompleted(completeValue) uses packSize. +} + +SetOperationResult() + 7-Zip calls SetOperationResult at the end of extracting, + so the callee can close the file, set attributes, timestamps and security information. + + Int32 opRes (NExtract::NOperationResult) */ #define INTERFACE_IArchiveExtractCallback(x) \ INTERFACE_IProgress(x) \ STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \ STDMETHOD(PrepareOperation)(Int32 askExtractMode) x; \ - STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) x; \ + STDMETHOD(SetOperationResult)(Int32 opRes) x; \ ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20) { @@ -128,6 +182,25 @@ ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20) }; + +/* +IArchiveExtractCallbackMessage can be requested from IArchiveExtractCallback object + by Extract() or UpdateItems() functions to report about extracting errors +ReportExtractResult() + UInt32 indexType (NEventIndexType) + UInt32 index + Int32 opRes (NExtract::NOperationResult) +*/ + +#define INTERFACE_IArchiveExtractCallbackMessage(x) \ + STDMETHOD(ReportExtractResult)(UInt32 indexType, UInt32 index, Int32 opRes) x; \ + +ARCHIVE_INTERFACE_SUB(IArchiveExtractCallbackMessage, IProgress, 0x21) +{ + INTERFACE_IArchiveExtractCallbackMessage(PURE) +}; + + #define INTERFACE_IArchiveOpenVolumeCallback(x) \ STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) x; \ STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream) x; \ @@ -183,9 +256,6 @@ Notes: Some IInArchive handlers will work incorrectly in that case. */ -/* MSVC allows the code where there is throw() in declaration of function, - but there is no throw() in definition of function. */ - #ifdef _MSC_VER #define MY_NO_THROW_DECL_ONLY throw() #else @@ -202,7 +272,7 @@ Notes: STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \ STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \ - STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; + STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \ ARCHIVE_INTERFACE(IInArchive, 0x60) { @@ -324,6 +394,8 @@ The order of calling for hard links: - GetStream() - GetProperty(kpidHardLink) +SetOperationResult() + Int32 opRes (NExtract::NOperationResult::kOK) */ #define INTERFACE_IArchiveUpdateCallback(x) \ @@ -348,6 +420,40 @@ ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82) INTERFACE_IArchiveUpdateCallback2(PURE); }; +namespace NUpdateNotifyOp +{ + enum + { + kAdd = 0, + kUpdate, + kAnalyze, + kReplicate, + kRepack, + kSkip, + kDelete, + kHeader + + // kNumDefined + }; +}; + +/* +IArchiveUpdateCallbackFile::ReportOperation + UInt32 indexType (NEventIndexType) + UInt32 index + UInt32 notifyOp (NUpdateNotifyOp) +*/ + +#define INTERFACE_IArchiveUpdateCallbackFile(x) \ + STDMETHOD(GetStream2)(UInt32 index, ISequentialInStream **inStream, UInt32 notifyOp) x; \ + STDMETHOD(ReportOperation)(UInt32 indexType, UInt32 index, UInt32 notifyOp) x; \ + +ARCHIVE_INTERFACE(IArchiveUpdateCallbackFile, 0x83) +{ + INTERFACE_IArchiveUpdateCallbackFile(PURE); +}; + + /* UpdateItems() ------------- @@ -382,7 +488,7 @@ ARCHIVE_INTERFACE(IOutArchive, 0xA0) ARCHIVE_INTERFACE(ISetProperties, 0x03) { - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) PURE; + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) PURE; }; ARCHIVE_INTERFACE(IArchiveKeepModeForNextOpen, 0x04) diff --git a/CPP/7zip/Archive/IhexHandler.cpp b/CPP/7zip/Archive/IhexHandler.cpp index 00816f0c..00ff80a7 100644 --- a/CPP/7zip/Archive/IhexHandler.cpp +++ b/CPP/7zip/Archive/IhexHandler.cpp @@ -85,7 +85,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val const CBlock &block = _blocks[index]; switch (propID) { - case kpidSize: prop = block.Data.GetPos(); break; + case kpidSize: prop = (UInt64)block.Data.GetPos(); break; case kpidVa: prop = block.Offset; break; case kpidPath: { @@ -103,7 +103,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val COM_TRY_END } -static inline int HexToByte(char c) +static inline int HexToByte(unsigned c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'F') return c - 'A' + 10; @@ -138,9 +138,9 @@ API_FUNC_static_IsArc IsArc_Ihex(const Byte *p, size_t size) p++; size--; - const int kNumLinesToCheck = 3; // 1 line is OK also, but we don't want false detection + const unsigned kNumLinesToCheck = 3; // 1 line is OK also, but we don't want false detection - for (int j = 0; j < kNumLinesToCheck; j++) + for (unsigned j = 0; j < kNumLinesToCheck; j++) { if (size < 4 * 2) return k_IsArc_Res_NEED_MORE; @@ -279,7 +279,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb } { - size_t numPairs = (num + 4); + size_t numPairs = ((unsigned)num + 4); size_t numBytes = numPairs * 2; if (s.ReadBytes(temp, numBytes) != numBytes) { @@ -287,7 +287,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb return S_FALSE; } - int sum = num; + unsigned sum = num; for (size_t i = 0; i < numPairs; i++) { int a = Parse(temp + i * 2); @@ -339,7 +339,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb block = &_blocks.AddNew(); block->Offset = offs; } - memcpy(block->Data.GetCurPtrAndGrow(num), temp + 3, num); + block->Data.AddData(temp + 3, (unsigned)num); } } else if (type == kType_Eof) @@ -486,16 +486,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -IMP_CreateArcIn +// k_Signature: { ':', '1' } -static CArcInfo g_ArcInfo = - { "IHex", "ihex", 0, 0xCD, - 0, { 0 }, - // 2, { ':', '1' }, +REGISTER_ARC_I_NO_SIG( + "IHex", "ihex", 0, 0xCD, 0, NArcInfoFlags::kStartOpen, - CreateArc, NULL, IsArc_Ihex }; - -REGISTER_ARC(Z) + IsArc_Ihex) }} diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp index aef920b0..713764d9 100644 --- a/CPP/7zip/Archive/Iso/IsoHandler.cpp +++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp @@ -79,8 +79,7 @@ static void AddString(AString &s, const char *name, const Byte *p, unsigned size if (i != 0) { AString d; - memcpy(d.GetBuffer(i), p, i); - d.ReleaseBuffer(i); + d.SetFrom((const char *)p, i); s += '\n'; s += name; s += ": "; @@ -170,11 +169,14 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { case kpidPath: { - // char name[16]; - // ConvertUInt32ToString(index + 1, name); AString s = "[BOOT]" STRING_PATH_SEPARATOR; - // s += name; - // s += '-'; + if (_archive.BootEntries.Size() != 1) + { + char temp[16]; + ConvertUInt32ToString(index + 1, temp); + s += temp; + s += '-'; + } s += be.GetName(); prop = s; break; @@ -197,18 +199,18 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { UString s; if (_archive.IsJoliet()) - s = item.GetPathU(); + item.GetPathU(s); else s = MultiByteToUnicodeString(item.GetPath(_archive.IsSusp, _archive.SuspSkipSize), CP_OEMCP); - int pos = s.ReverseFind(L';'); - if (pos >= 0 && pos == (int)s.Len() - 2) - if (s.Back() == L'1') - s.DeleteFrom(pos); - if (!s.IsEmpty()) - if (s.Back() == L'.') - s.DeleteBack(); - prop = (const wchar_t *)NItemName::GetOSName2(s); + if (s.Len() >= 2 && s[s.Len() - 2] == ';' && s.Back() == '1') + s.DeleteFrom(s.Len() - 2); + + if (!s.IsEmpty() && s.Back() == L'.') + s.DeleteBack(); + + NItemName::ConvertToOSName2(s); + prop = s; } break; case kpidIsDir: prop = item.IsDir(); break; @@ -319,8 +321,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt64 offset = 0; for (UInt32 e = 0; e < ref.NumExtents; e++) { - if (e != 0) - lps->InSize = lps->OutSize = currentTotalSize + offset; + lps->InSize = lps->OutSize = currentTotalSize + offset; const CDir &item2 = ref.Dir->_subItems[ref.Index + e]; RINOK(_stream->Seek((UInt64)item2.ExtentLocation * _archive.BlockSize, STREAM_SEEK_SET, NULL)); streamSpec->Init(item2.Size); @@ -356,6 +357,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) *stream = 0; UInt64 blockIndex; UInt64 currentItemSize; + if (index < (UInt32)_archive.Refs.Size()) { const CRef &ref = _archive.Refs[index]; @@ -402,6 +404,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) currentItemSize = _archive.GetBootItemSize(bootIndex); blockIndex = be.LoadRBA; } + return CreateLimitedInStream(_stream, blockIndex * _archive.BlockSize, currentItemSize, stream); COM_TRY_END } diff --git a/CPP/7zip/Archive/Iso/IsoHeader.cpp b/CPP/7zip/Archive/Iso/IsoHeader.cpp index 1cd2516c..59c283c1 100644 --- a/CPP/7zip/Archive/Iso/IsoHeader.cpp +++ b/CPP/7zip/Archive/Iso/IsoHeader.cpp @@ -9,13 +9,4 @@ namespace NIso { const char *kElToritoSpec = "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0"; -const char *kMediaTypes[5] = -{ - "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 ce21b0ff..db0b1df9 100644 --- a/CPP/7zip/Archive/Iso/IsoHeader.h +++ b/CPP/7zip/Archive/Iso/IsoHeader.h @@ -34,6 +34,11 @@ namespace NBootEntryId const Byte kValidationEntry = 1; const Byte kInitialEntryNotBootable = 0; const Byte kInitialEntryBootable = 0x88; + + const Byte kMoreHeaders = 0x90; + const Byte kFinalHeader = 0x91; + + const Byte kExtensionIndicator = 0x44; } namespace NBootPlatformId @@ -54,9 +59,6 @@ namespace NBootMediaType const Byte kHardDisk = 4; } -const unsigned kNumBootMediaTypes = 5; -extern const char *kMediaTypes[]; - }} #endif diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp index ba12acae..b72e8687 100644 --- a/CPP/7zip/Archive/Iso/IsoIn.cpp +++ b/CPP/7zip/Archive/Iso/IsoIn.cpp @@ -2,6 +2,8 @@ #include "StdAfx.h" +#include "../../../../C/CpuArch.h" + #include "../../../Common/MyException.h" #include "../../Common/StreamUtils.h" @@ -10,11 +12,78 @@ namespace NArchive { namespace NIso { - + struct CUnexpectedEndException {}; struct CHeaderErrorException {}; struct CEndianErrorException {}; +static const char * const kMediaTypes[] = +{ + "NoEmul" + , "1.2M" + , "1.44M" + , "2.88M" + , "HardDisk" +}; + +bool CBootInitialEntry::Parse(const Byte *p) +{ + Bootable = (p[0] == NBootEntryId::kInitialEntryBootable); + BootMediaType = p[1]; + LoadSegment = GetUi16(p + 2); + SystemType = p[4]; + SectorCount = GetUi16(p + 6); + LoadRBA = GetUi32(p + 8); + memcpy(VendorSpec, p + 12, 20); + if (p[5] != 0) + return false; + if (p[0] != NBootEntryId::kInitialEntryBootable + && p[0] != NBootEntryId::kInitialEntryNotBootable) + return false; + return true; +} + +AString CBootInitialEntry::GetName() const +{ + AString s = (Bootable ? "Boot" : "NotBoot"); + s += '-'; + + if (BootMediaType < ARRAY_SIZE(kMediaTypes)) + s += kMediaTypes[BootMediaType]; + else + { + char name[16]; + ConvertUInt32ToString(BootMediaType, name); + s += name; + } + + if (VendorSpec[0] == 1) + { + // "Language and Version Information (IBM)" + + unsigned i; + for (i = 1; i < sizeof(VendorSpec); i++) + if (VendorSpec[i] > 0x7F) + break; + if (i == sizeof(VendorSpec)) + { + s += '-'; + for (i = 1; i < sizeof(VendorSpec); i++) + { + char c = VendorSpec[i]; + if (c == 0) + break; + if (c == '\\' || c == '/') + c = '_'; + s += c; + } + } + } + + s += ".img"; + return s; +} + Byte CInArchive::ReadByte() { if (m_BufferPos >= BlockSize) @@ -58,15 +127,6 @@ void CInArchive::SkipZeros(size_t size) } } -UInt16 CInArchive::ReadUInt16Spec() -{ - UInt16 val = 0; - for (int i = 0; i < 2; i++) - val |= ((UInt16)(ReadByte()) << (8 * i)); - return val; -} - - UInt16 CInArchive::ReadUInt16() { Byte b[4]; @@ -179,15 +239,15 @@ void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len) Byte idLen = ReadByte(); r.FileId.Alloc(idLen); ReadBytes((Byte *)r.FileId, idLen); - int padSize = 1 - (idLen & 1); + unsigned padSize = 1 - (idLen & 1); - // SkipZeros(1 - (idLen & 1)); - Skip(1 - (idLen & 1)); // it's bug in some cd's. Must be zeros + // SkipZeros(padSize); + Skip(padSize); // it's bug in some cd's. Must be zeros - int curPos = 33 + idLen + padSize; + unsigned curPos = 33 + idLen + padSize; if (curPos > len) throw CHeaderErrorException(); - int rem = len - curPos; + unsigned rem = len - curPos; r.SystemUse.Alloc(rem); ReadBytes((Byte *)r.SystemUse, rem); } @@ -349,45 +409,94 @@ void CInArchive::ReadBootInfo() { if (!_bootIsDefined) return; + HeadersError = true; + if (memcmp(_bootDesc.BootSystemId, kElToritoSpec, sizeof(_bootDesc.BootSystemId)) != 0) return; - const Byte *p = (const Byte *)_bootDesc.BootSystemUse; - UInt32 blockIndex = p[0] | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16) | ((UInt32)p[3] << 24); + UInt32 blockIndex = GetUi32(_bootDesc.BootSystemUse); SeekToBlock(blockIndex); - Byte b = ReadByte(); - if (b != NBootEntryId::kValidationEntry) + + Byte buf[32]; + ReadBytes(buf, 32); + + if (buf[0] != NBootEntryId::kValidationEntry + || buf[2] != 0 + || buf[3] != 0 + || buf[30] != 0x55 + || buf[31] != 0xAA) return; + { + UInt32 sum = 0; + for (unsigned i = 0; i < 32; i += 2) + sum += GetUi16(buf + i); + if ((sum & 0xFFFF) != 0) + return; + /* CBootValidationEntry e; - e.PlatformId = ReadByte(); - if (ReadUInt16Spec() != 0) - throw CHeaderErrorException(); - ReadBytes(e.Id, sizeof(e.Id)); - /* UInt16 checkSum = */ ReadUInt16Spec(); - if (ReadByte() != 0x55) - throw CHeaderErrorException(); - if (ReadByte() != 0xAA) - throw CHeaderErrorException(); + e.PlatformId = buf[1]; + memcpy(e.Id, buf + 4, sizeof(e.Id)); + // UInt16 checkSum = GetUi16(p + 28); + */ } - b = ReadByte(); - if (b == NBootEntryId::kInitialEntryBootable || b == NBootEntryId::kInitialEntryNotBootable) + + ReadBytes(buf, 32); { CBootInitialEntry e; - e.Bootable = (b == NBootEntryId::kInitialEntryBootable); - e.BootMediaType = ReadByte(); - e.LoadSegment = ReadUInt16Spec(); - e.SystemType = ReadByte(); - if (ReadByte() != 0) - throw CHeaderErrorException(); - e.SectorCount = ReadUInt16Spec(); - e.LoadRBA = ReadUInt32Le(); - if (ReadByte() != 0) - throw CHeaderErrorException(); + if (!e.Parse(buf)) + return; BootEntries.Add(e); } - else - return; + + bool error = false; + + for (;;) + { + ReadBytes(buf, 32); + Byte headerIndicator = buf[0]; + if (headerIndicator != NBootEntryId::kMoreHeaders + && headerIndicator != NBootEntryId::kFinalHeader) + break; + + // Section Header + // Byte platform = p[1]; + unsigned numEntries = GetUi16(buf + 2); + // id[28] + + for (unsigned i = 0; i < numEntries; i++) + { + ReadBytes(buf, 32); + CBootInitialEntry e; + if (!e.Parse(buf)) + { + error = true; + break; + } + if (e.BootMediaType & (1 << 5)) + { + // Section entry extension + for (unsigned j = 0;; j++) + { + ReadBytes(buf, 32); + if (j > 32 || buf[0] != NBootEntryId::kExtensionIndicator) + { + error = true; + break; + } + if ((buf[1] & (1 << 5)) == 0) + break; + // info += (buf + 2, 30) + } + } + BootEntries.Add(e); + } + + if (headerIndicator != NBootEntryId::kMoreHeaders) + break; + } + + HeadersError = error; } HRESULT CInArchive::Open2() diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h index 614b3744..c2007bce 100644 --- a/CPP/7zip/Archive/Iso/IsoIn.h +++ b/CPP/7zip/Archive/Iso/IsoIn.h @@ -25,77 +25,92 @@ struct CDir: public CDirRecord _subItems.Clear(); } - unsigned GetLen(bool checkSusp, unsigned skipSize) const - { - unsigned len = GetLenCur(checkSusp, skipSize); - if (Parent != 0) - if (Parent->Parent != 0) - len += 1 + Parent->GetLen(checkSusp, skipSize); - return len; - } - - unsigned GetLenU() const - { - unsigned len = (unsigned)(FileId.Size() / 2); - if (Parent != 0) - if (Parent->Parent != 0) - len += 1 + Parent->GetLenU(); - return len; - } - AString GetPath(bool checkSusp, unsigned skipSize) const { AString s; - unsigned len = GetLen(checkSusp, skipSize); - char *p = s.GetBuffer(len); - p += len; - *p = 0; + + unsigned len = 0; const CDir *cur = this; + for (;;) { - unsigned curLen = cur->GetLenCur(checkSusp, skipSize); - p -= curLen; - memcpy(p, (const char *)(const Byte *)cur->GetNameCur(checkSusp, skipSize), curLen); + unsigned curLen; + cur->GetNameCur(checkSusp, skipSize, curLen); + len += curLen; cur = cur->Parent; - if (cur == 0) + if (!cur || !cur->Parent) break; - if (cur->Parent == 0) + len++; + } + + char *p = s.GetBuf_SetEnd(len) + len; + + cur = this; + + for (;;) + { + unsigned curLen; + const Byte *name = cur->GetNameCur(checkSusp, skipSize, curLen); + p -= curLen; + if (curLen != 0) + memcpy(p, name, curLen); + cur = cur->Parent; + if (!cur || !cur->Parent) break; p--; *p = CHAR_PATH_SEPARATOR; } - s.ReleaseBuffer(); + return s; } - UString GetPathU() const + void GetPathU(UString &s) const { - UString s; - unsigned len = GetLenU(); - wchar_t *p = s.GetBuffer(len); - p += len; - *p = 0; + s.Empty(); + + unsigned len = 0; const CDir *cur = this; + for (;;) { unsigned curLen = (unsigned)(cur->FileId.Size() / 2); - p -= curLen; - for (unsigned i = 0; i < curLen; i++) - { - Byte b0 = ((const Byte *)cur->FileId)[i * 2]; - Byte b1 = ((const Byte *)cur->FileId)[i * 2 + 1]; - p[i] = (wchar_t)(((wchar_t)b0 << 8) | b1); - } + const Byte *fid = cur->FileId; + + unsigned i; + for (i = 0; i < curLen; i++) + if (fid[i * 2] == 0 && fid[i * 2 + 1] == 0) + break; + len += i; cur = cur->Parent; - if (cur == 0) + if (!cur || !cur->Parent) break; - if (cur->Parent == 0) + len++; + } + + wchar_t *p = s.GetBuf_SetEnd(len) + len; + + cur = this; + + for (;;) + { + unsigned curLen = (unsigned)(cur->FileId.Size() / 2); + const Byte *fid = cur->FileId; + + unsigned i; + for (i = 0; i < curLen; i++) + if (fid[i * 2] == 0 && fid[i * 2 + 1] == 0) + break; + curLen = i; + + p -= curLen; + for (i = 0; i < curLen; i++) + p[i] = (wchar_t)(((wchar_t)fid[i * 2] << 8) | fid[i * 2 + 1]); + cur = cur->Parent; + if (!cur || !cur->Parent) break; p--; *p = WCHAR_PATH_SEPARATOR; } - s.ReleaseBuffer(); - return s; } }; @@ -109,6 +124,7 @@ struct CDateTime Byte Second; Byte Hundredths; signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded. + bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 && Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; } @@ -118,7 +134,7 @@ struct CDateTime bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value); if (res) { - value -= (UInt64)((Int64)GmtOffset * 15 * 60); + value -= (Int64)((Int32)GmtOffset * 15 * 60); value *= 10000000; } ft.dwLowDateTime = (DWORD)value; @@ -157,27 +173,16 @@ struct CBootInitialEntry UInt32 LoadRBA; // This is the start address of the virtual disk. CDs use // Relative/Logical block addressing. - UInt64 GetSize() const + Byte VendorSpec[20]; + + UInt32 GetSize() const { // if (BootMediaType == NBootMediaType::k1d44Floppy) (1440 << 10); - return SectorCount * 512; + return (UInt32)SectorCount * 512; } - AString GetName() const - { - AString s = (Bootable ? "Bootable" : "NotBootable"); - s += '_'; - if (BootMediaType < kNumBootMediaTypes) - s += kMediaTypes[BootMediaType]; - else - { - char name[16]; - ConvertUInt32ToString(BootMediaType, name); - s += name; - } - s += ".img"; - return s; - } + bool Parse(const Byte *p); + AString GetName() const; }; struct CVolumeDescriptor @@ -247,7 +252,6 @@ class CInArchive void SkipZeros(size_t size); Byte ReadByte(); void ReadBytes(Byte *data, UInt32 size); - UInt16 ReadUInt16Spec(); UInt16 ReadUInt16(); UInt32 ReadUInt32Le(); UInt32 ReadUInt32Be(); diff --git a/CPP/7zip/Archive/Iso/IsoItem.h b/CPP/7zip/Archive/Iso/IsoItem.h index b6ae21b7..2603afdb 100644 --- a/CPP/7zip/Archive/Iso/IsoItem.h +++ b/CPP/7zip/Archive/Iso/IsoItem.h @@ -29,7 +29,7 @@ struct CRecordingDateTime bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, value); if (res) { - value -= (UInt64)((Int64)GmtOffset * 15 * 60); + value -= (Int64)((Int32)GmtOffset * 15 * 60); value *= 10000000; } ft.dwLowDateTime = (DWORD)value; @@ -94,28 +94,23 @@ struct CDirRecord return 0; } - unsigned GetLenCur(bool checkSusp, int skipSize) const + const Byte* GetNameCur(bool checkSusp, int skipSize, unsigned &nameLenRes) const { + const Byte *res = NULL; + unsigned len = 0; if (checkSusp) + res = FindSuspName(skipSize, len); + if (!res) { - unsigned len; - const Byte *res = FindSuspName(skipSize, len); - if (res != 0) - return len; + res = (const Byte *)FileId; + len = (unsigned)FileId.Size(); } - return (unsigned)FileId.Size(); - } - - const Byte* GetNameCur(bool checkSusp, int skipSize) const - { - if (checkSusp) - { - unsigned len; - const Byte *res = FindSuspName(skipSize, len); - if (res != 0) - return res; - } - return (const Byte *)FileId; + unsigned i; + for (i = 0; i < len; i++) + if (res[i] == 0) + break; + nameLenRes = i; + return res; } diff --git a/CPP/7zip/Archive/Iso/IsoRegister.cpp b/CPP/7zip/Archive/Iso/IsoRegister.cpp index c6f4a521..0205238d 100644 --- a/CPP/7zip/Archive/Iso/IsoRegister.cpp +++ b/CPP/7zip/Archive/Iso/IsoRegister.cpp @@ -9,15 +9,13 @@ namespace NArchive { namespace NIso { -IMP_CreateArcIn +static const Byte k_Signature[] = { 'C', 'D', '0', '0', '1' }; -static CArcInfo g_ArcInfo = - { "Iso", "iso img", 0, 0xE7, - 5, { 'C', 'D', '0', '0', '1' }, +REGISTER_ARC_I( + "Iso", "iso img", 0, 0xE7, + k_Signature, NArchive::NIso::kStartPos + 1, 0, - CreateArc }; - -REGISTER_ARC(Iso) + NULL) }} diff --git a/CPP/7zip/Archive/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp index ef4b4196..c8d3ff6d 100644 --- a/CPP/7zip/Archive/LzhHandler.cpp +++ b/CPP/7zip/Archive/LzhHandler.cpp @@ -660,8 +660,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = 0; CMyComPtr<ICompressCoder> lzhDecoder; - CMyComPtr<ICompressCoder> lzh1Decoder; - CMyComPtr<ICompressCoder> arj2Decoder; + // CMyComPtr<ICompressCoder> lzh1Decoder; + // CMyComPtr<ICompressCoder> arj2Decoder; NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; @@ -736,8 +736,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder; lzhDecoder = lzhDecoderSpec; } - lzhDecoderSpec->SetDictionary(item.GetNumDictBits()); + lzhDecoderSpec->FinishMode = true; + lzhDecoderSpec->SetDictSize(1 << item.GetNumDictBits()); result = lzhDecoder->Code(inStream, outStream, NULL, ¤tItemUnPacked, progress); + if (result == S_OK && lzhDecoderSpec->GetInputProcessedSize() != item.PackSize) + result = S_FALSE; } /* else if (item.IsLh1GroupMethod()) @@ -773,15 +776,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -IMP_CreateArcIn +static const Byte k_Signature[] = { '-', 'l', 'h' }; -static CArcInfo g_ArcInfo = - { "Lzh", "lzh lha", 0, 6, - 3, { '-', 'l', 'h' }, +REGISTER_ARC_I( + "Lzh", "lzh lha", 0, 6, + k_Signature, 2, 0, - CreateArc, NULL, IsArc_Lzh }; - -REGISTER_ARC(Lzh) + IsArc_Lzh) }} diff --git a/CPP/7zip/Archive/LzmaHandler.cpp b/CPP/7zip/Archive/LzmaHandler.cpp index 04aa4685..e4ac2a42 100644 --- a/CPP/7zip/Archive/LzmaHandler.cpp +++ b/CPP/7zip/Archive/LzmaHandler.cpp @@ -9,11 +9,12 @@ #include "../../Windows/PropVariant.h" -#include "../Common/CreateCoder.h" +#include "../Common/FilterCoder.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" #include "../Common/StreamUtils.h" +#include "../Compress/BcjCoder.h" #include "../Compress/LzmaDecoder.h" #include "Common/DummyOutStream.h" @@ -75,14 +76,14 @@ bool CHeader::Parse(const Byte *buf, bool isThereFilter) class CDecoder { - CMyComPtr<ICompressCoder> _lzmaDecoder; CMyComPtr<ISequentialOutStream> _bcjStream; + CFilterCoder *_filterCoder; + CMyComPtr<ICompressCoder> _lzmaDecoder; public: NCompress::NLzma::CDecoder *_lzmaDecoderSpec; ~CDecoder(); - HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS - bool filtered, ISequentialInStream *inStream); + HRESULT Create(bool filtered, ISequentialInStream *inStream); HRESULT Code(const CHeader &header, ISequentialOutStream *outStream, ICompressProgressInfo *progress); @@ -94,11 +95,7 @@ public: { return _lzmaDecoderSpec->ReadFromInputStream(data, size, processedSize); } }; -static const UInt32 k_BCJ = 0x03030103; - -HRESULT CDecoder::Create( - DECL_EXTERNAL_CODECS_LOC_VARS - bool filteredMode, ISequentialInStream *inStream) +HRESULT CDecoder::Create(bool filteredMode, ISequentialInStream *inStream) { if (!_lzmaDecoder) { @@ -111,13 +108,10 @@ HRESULT CDecoder::Create( { if (!_bcjStream) { - CMyComPtr<ICompressCoder> coder; - RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS k_BCJ, coder, false)); - if (!coder) - return E_NOTIMPL; - coder.QueryInterface(IID_ISequentialOutStream, &_bcjStream); - if (!_bcjStream) - return E_NOTIMPL; + _filterCoder = new CFilterCoder(false); + CMyComPtr<ICompressCoder> coder = _filterCoder; + _filterCoder->Filter = new CBcjCoder(false); + _bcjStream = _filterCoder; } } @@ -143,17 +137,13 @@ HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream, RINOK(setDecoderProperties->SetDecoderProperties2(header.LzmaProps, 5)); } - CMyComPtr<ICompressSetOutStream> setOutStream; - bool filteredMode = (header.FilterID == 1); if (filteredMode) { - _bcjStream.QueryInterface(IID_ICompressSetOutStream, &setOutStream); - if (!setOutStream) - return E_NOTIMPL; - RINOK(setOutStream->SetOutStream(outStream)); + RINOK(_filterCoder->SetOutStream(outStream)); outStream = _bcjStream; + RINOK(_filterCoder->SetOutStreamSize(NULL)); } const UInt64 *Size = header.HasSize() ? &header.Size : NULL; @@ -161,18 +151,16 @@ HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream, if (filteredMode) { - CMyComPtr<IOutStreamFlush> flush; - _bcjStream.QueryInterface(IID_IOutStreamFlush, &flush); - if (flush) { - HRESULT res2 = flush->Flush(); + HRESULT res2 = _filterCoder->OutStreamFinish(); if (res == S_OK) res = res2; } - HRESULT res2 = setOutStream->ReleaseOutStream(); + HRESULT res2 = _filterCoder->ReleaseOutStream(); if (res == S_OK) res = res2; } + RINOK(res); if (header.HasSize()) @@ -186,7 +174,6 @@ HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream, class CHandler: public IInArchive, public IArchiveOpenSeq, - PUBLIC_ISetCompressCodecsInfo public CMyUnknownImp { CHeader _header; @@ -210,15 +197,8 @@ class CHandler: UInt64 _unpackSize; UInt64 _numStreams; - DECL_EXTERNAL_CODECS_VARS - DECL_ISetCompressCodecsInfo - public: - MY_QUERYINTERFACE_BEGIN2(IInArchive) - MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq) - QUERY_ENTRY_ISetCompressCodecsInfo - MY_QUERYINTERFACE_END - MY_ADDREF_RELEASE + MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq) INTERFACE_IInArchive(;) STDMETHOD(OpenSeq)(ISequentialInStream *stream); @@ -427,6 +407,7 @@ 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)) @@ -466,9 +447,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, _needSeekToStart = true; CDecoder decoder; - HRESULT result = decoder.Create( - EXTERNAL_CODECS_VARS - _lzma86, _seqStream); + HRESULT result = decoder.Create(_lzma86, _seqStream); RINOK(result); bool firstItem = true; @@ -562,43 +541,33 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, outStream.Release(); return extractCallback->SetOperationResult(opResult); + COM_TRY_END } -IMPL_ISetCompressCodecsInfo - namespace NLzmaAr { -IMP_CreateArcIn_2(CHandler(false)) +// 2, { 0x5D, 0x00 }, -static CArcInfo g_ArcInfo = - { "lzma", "lzma", 0, 0xA, - 0, { 0 }, - // 2, { 0x5D, 0x00 }, +REGISTER_ARC_I_CLS_NO_SIG( + CHandler(false), + "lzma", "lzma", 0, 0xA, 0, NArcInfoFlags::kStartOpen | NArcInfoFlags::kKeepName, - CreateArc, NULL, - IsArc_Lzma }; - -REGISTER_ARC(Lzma) - + IsArc_Lzma) + } namespace NLzma86Ar { -IMP_CreateArcIn_2(CHandler(true)) - -static CArcInfo g_ArcInfo = - { "lzma86", "lzma86", 0, 0xB, - 0, { 0 }, +REGISTER_ARC_I_CLS_NO_SIG( + CHandler(true), + "lzma86", "lzma86", 0, 0xB, 0, NArcInfoFlags::kKeepName, - CreateArc, NULL, - IsArc_Lzma86 }; - -REGISTER_ARC(Lzma86) - + IsArc_Lzma86) + } }} diff --git a/CPP/7zip/Archive/MachoHandler.cpp b/CPP/7zip/Archive/MachoHandler.cpp index 11ff9703..00dc571b 100644 --- a/CPP/7zip/Archive/MachoHandler.cpp +++ b/CPP/7zip/Archive/MachoHandler.cpp @@ -42,7 +42,7 @@ namespace NMacho { #define CPU_SUBTYPE_POWERPC_970 100 -static const char *k_PowerPc_SubTypes[] = +static const char * const k_PowerPc_SubTypes[] = { NULL , "601" @@ -297,7 +297,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) ConvertUInt32ToString(t, temp); n = temp; } - s += ' '; + s.Add_Space(); s += n; } prop = s; @@ -310,7 +310,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) AString s = FlagsToString(g_ArcFlags, ARRAY_SIZE(g_ArcFlags), _flags); if (!s.IsEmpty()) { - res += ' '; + res.Add_Space(); res += s; } prop = res; @@ -354,7 +354,7 @@ static AString SectFlagsToString(UInt32 flags) AString s = FlagsToString(g_Flags, ARRAY_SIZE(g_Flags), flags & SECT_ATTR_MASK); if (!s.IsEmpty()) { - res += ' '; + res.Add_Space(); res += s; } return res; @@ -643,22 +643,18 @@ STDMETHODIMP CHandler::AllowTail(Int32 allowTail) return S_OK; } -IMP_CreateArcIn +static const Byte k_Signature[] = { + 4, 0xCE, 0xFA, 0xED, 0xFE, + 4, 0xCF, 0xFA, 0xED, 0xFE, + 4, 0xFE, 0xED, 0xFA, 0xCE, + 4, 0xFE, 0xED, 0xFA, 0xCF }; -#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 = - { "MachO", "macho", 0, 0xDF, - 4 * 5, k_Signature, +REGISTER_ARC_I( + "MachO", "macho", 0, 0xDF, + k_Signature, 0, NArcInfoFlags::kMultiSignature | NArcInfoFlags::kPreArc, - CreateArc }; - -REGISTER_ARC(Macho) + NULL) }} diff --git a/CPP/7zip/Archive/MbrHandler.cpp b/CPP/7zip/Archive/MbrHandler.cpp index abc981f3..c4e4cc60 100644 --- a/CPP/7zip/Archive/MbrHandler.cpp +++ b/CPP/7zip/Archive/MbrHandler.cpp @@ -169,7 +169,7 @@ static const CPartType kPartTypes[] = static int FindPartType(UInt32 type) { - for (int i = 0; i < ARRAY_SIZE(kPartTypes); i++) + for (unsigned i = 0; i < ARRAY_SIZE(kPartTypes); i++) if (kPartTypes[i].Id == type) return i; return -1; @@ -193,19 +193,19 @@ class CHandler: UInt64 _totalSize; CByteBuffer _buffer; - HRESULT ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, int level); + HRESULT ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level); public: MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); }; -HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, int level) +HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level) { if (level >= 128 || _items.Size() >= 128) return S_FALSE; - const int kNumHeaderParts = 4; + const unsigned kNumHeaderParts = 4; CPartition parts[kNumHeaderParts]; { @@ -221,7 +221,7 @@ HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, int if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA) return S_FALSE; - for (int i = 0; i < kNumHeaderParts; i++) + for (unsigned i = 0; i < kNumHeaderParts; i++) if (!parts[i].Parse(buf + 0x1BE + 16 * i)) return S_FALSE; } @@ -232,13 +232,13 @@ HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, int if (limLba == 0) return S_FALSE; - for (int i = 0; i < kNumHeaderParts; i++) + for (unsigned i = 0; i < kNumHeaderParts; i++) { CPartition &part = parts[i]; if (part.IsEmpty()) continue; - PRF(printf("\n %2d ", (int)level)); + PRF(printf("\n %2d ", (unsigned)level)); #ifdef SHOW_DEBUG_INFO part.Print(); #endif @@ -402,8 +402,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val int typeIndex = FindPartType(part.Type); s += '.'; const char *ext = "img"; - if (typeIndex >= 0 && kPartTypes[typeIndex].Ext != 0) - ext = kPartTypes[typeIndex].Ext; + if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Ext) + ext = kPartTypes[(unsigned)typeIndex].Ext; s += ext; } prop = s; @@ -416,8 +416,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val ConvertUInt32ToString(part.Type, s); const char *res = s; int typeIndex = FindPartType(part.Type); - if (typeIndex >= 0 && kPartTypes[typeIndex].Name) - res = kPartTypes[typeIndex].Name; + if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Name) + res = kPartTypes[(unsigned)typeIndex].Name; prop = res; } break; @@ -499,17 +499,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -IMP_CreateArcIn -static CArcInfo g_ArcInfo = - { "MBR", "mbr", 0, 0xDB, // 3, { 1, 1, 0 }, // 2, { 0x55, 0x1FF }, - 0, { 0 }, + +REGISTER_ARC_I_NO_SIG( + "MBR", "mbr", 0, 0xDB, 0, NArcInfoFlags::kPureStartOpen, - CreateArc }; - -REGISTER_ARC(Mbr) + NULL) }} diff --git a/CPP/7zip/Archive/MslzHandler.cpp b/CPP/7zip/Archive/MslzHandler.cpp index cb124c40..ec375733 100644 --- a/CPP/7zip/Archive/MslzHandler.cpp +++ b/CPP/7zip/Archive/MslzHandler.cpp @@ -111,11 +111,13 @@ static const unsigned kHeaderSize = kSignatureSize + 1 + 4; static const Byte kSignature[kSignatureSize] = MSLZ_SIGNATURE; // we support only 3 chars strings here -static const char *g_Exts[] = +static const char * const g_Exts[] = { - "dll" + "bin" + , "dll" , "exe" , "kmd" + , "pdf" , "sys" }; @@ -147,14 +149,15 @@ void CHandler::ParseName(Byte replaceByte, IArchiveOpenCallback *callback) 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]) + if (s[s.Len() - 2] == (Byte)ext[0] && + s[s.Len() - 1] == (Byte)ext[1]) { replaceByte = ext[2]; break; } } } + if (replaceByte >= 0x20 && replaceByte < 0x80) _name += (wchar_t)replaceByte; } @@ -225,6 +228,7 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn Byte buf[kBufSize]; UInt32 dest = 0; memset(buf, ' ', kBufSize); + while (dest < unpackSize) { Byte b; @@ -233,6 +237,7 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn needMoreData = true; return S_FALSE; } + for (unsigned mask = (unsigned)b | 0x100; mask > 1 && dest < unpackSize; mask >>= 1) { if (!inStream.ReadByte(b)) @@ -240,6 +245,7 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn needMoreData = true; return S_FALSE; } + if (mask & 1) { buf[dest++ & kMask] = b; @@ -258,6 +264,7 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn unsigned len = (b1 & 0xF) + 3; if (len > kMaxLen || dest + len > unpackSize) return S_FALSE; + do { buf[dest++ & kMask] = buf[src++ & kMask]; @@ -267,6 +274,7 @@ static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UIn } } } + if (outStream) RINOK(WriteStream(outStream, buf, dest & kMask)); return S_OK; @@ -379,15 +387,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -IMP_CreateArcIn - -static CArcInfo g_ArcInfo = - { "MsLZ", "mslz", 0, 0xD5, - kSignatureSize, MSLZ_SIGNATURE, +REGISTER_ARC_I( + "MsLZ", "mslz", 0, 0xD5, + kSignature, 0, 0, - CreateArc }; - -REGISTER_ARC(Mslz) + NULL) }} diff --git a/CPP/7zip/Archive/MubHandler.cpp b/CPP/7zip/Archive/MubHandler.cpp index 39f8de27..a84c3120 100644 --- a/CPP/7zip/Archive/MubHandler.cpp +++ b/CPP/7zip/Archive/MubHandler.cpp @@ -292,22 +292,18 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -IMP_CreateArcIn - namespace NBe { -static CArcInfo g_ArcInfo = - { "Mub", "mub", 0, 0xE2, - 2 + 7 + 4, - { +static const Byte k_Signature[] = { 7, 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0, - 4, 0xB9, 0xFA, 0xF1, 0x0E - }, + 4, 0xB9, 0xFA, 0xF1, 0x0E }; + +REGISTER_ARC_I( + "Mub", "mub", 0, 0xE2, + k_Signature, 0, NArcInfoFlags::kMultiSignature, - CreateArc }; - -REGISTER_ARC(Mub) + NULL) } diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.cpp b/CPP/7zip/Archive/Nsis/NsisDecode.cpp index bb73d273..68243129 100644 --- a/CPP/7zip/Archive/Nsis/NsisDecode.cpp +++ b/CPP/7zip/Archive/Nsis/NsisDecode.cpp @@ -7,7 +7,6 @@ #include "NsisDecode.h" #include "../../Common/CreateCoder.h" -#include "../../Common/FilterCoder.h" #include "../../Common/LimitedStreams.h" #include "../../Common/MethodId.h" @@ -58,18 +57,11 @@ HRESULT CDecoder::Init(ISequentialInStream *inStream, bool &useFilter) { if (!_filterInStream) { - CFilterCoder *coderSpec = new CFilterCoder; - CMyComPtr<ICompressCoder> coder = coderSpec; - coderSpec->Filter = new CBCJ_x86_Decoder(); - coder.QueryInterface(IID_ISequentialInStream, &_filterInStream); - if (!_filterInStream) - return E_NOTIMPL; + _filter = new CFilterCoder(false); + _filterInStream = _filter; + _filter->Filter = new CBcjCoder(false); } - CMyComPtr<ICompressSetInStream> setInStream; - _filterInStream.QueryInterface(IID_ICompressSetInStream, &setInStream); - if (!setInStream) - return E_NOTIMPL; - RINOK(setInStream->SetInStream(_codecInStream)); + RINOK(_filter->SetInStream(_codecInStream)); _decoderInStream = _filterInStream; } @@ -99,13 +91,7 @@ HRESULT CDecoder::Init(ISequentialInStream *inStream, bool &useFilter) if (useFilter) { - /* - CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize; - _filterInStream.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize); - if (!setOutStreamSize) - return E_NOTIMPL; - RINOK(setOutStreamSize->SetOutStreamSize(NULL)); - */ + RINOK(_filter->SetOutStreamSize(NULL)); } return S_OK; diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.h b/CPP/7zip/Archive/Nsis/NsisDecode.h index 0b95d4b2..7b22181e 100644 --- a/CPP/7zip/Archive/Nsis/NsisDecode.h +++ b/CPP/7zip/Archive/Nsis/NsisDecode.h @@ -5,6 +5,7 @@ #include "../../../Common/MyBuffer.h" +#include "../../Common/FilterCoder.h" #include "../../Common/StreamUtils.h" #include "../../Compress/LzmaDecoder.h" @@ -31,6 +32,7 @@ class CDecoder { NMethodType::EEnum _curMethod; // method of created decoder + CFilterCoder *_filter; CMyComPtr<ISequentialInStream> _filterInStream; CMyComPtr<ISequentialInStream> _codecInStream; CMyComPtr<ISequentialInStream> _decoderInStream; diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.cpp b/CPP/7zip/Archive/Nsis/NsisHandler.cpp index 233edd52..971c8464 100644 --- a/CPP/7zip/Archive/Nsis/NsisHandler.cpp +++ b/CPP/7zip/Archive/Nsis/NsisHandler.cpp @@ -26,7 +26,7 @@ namespace NNsis { static const char *kBcjMethod = "BCJ"; static const char *kUnknownMethod = "Unknown"; -static const char *kMethods[] = +static const char * const kMethods[] = { "Copy" , "Deflate" @@ -84,9 +84,9 @@ static AString GetMethod(bool useFilter, NMethodType::EEnum method, UInt32 dict) if (useFilter) { s += kBcjMethod; - s += ' '; + s.Add_Space(); } - s += (method < ARRAY_SIZE(kMethods)) ? kMethods[method] : kUnknownMethod; + s += ((unsigned)method < ARRAY_SIZE(kMethods)) ? kMethods[(unsigned)method] : kUnknownMethod; if (method == NMethodType::kLZMA) { s += ':'; @@ -102,7 +102,7 @@ AString CHandler::GetMethod(NMethodType::EEnum method, bool useItemFilter, UInt3 if (_archive.IsSolid && _archive.UseFilter || !_archive.IsSolid && useItemFilter) { s += kBcjMethod; - s += ' '; + s.Add_Space(); } s += (method < ARRAY_SIZE(kMethods)) ? kMethods[method] : kUnknownMethod; if (method == NMethodType::kLZMA) @@ -126,8 +126,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) AString s = _archive.GetFormatDescription(); if (!_archive.IsInstaller) { - if (!s.IsEmpty()) - s += ' '; + s.Add_Space_if_NotEmpty(); s += "(Uninstall)"; } if (!s.IsEmpty()) @@ -138,8 +137,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) 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 kpidPhySize: prop = (UInt64)((UInt64)_archive.ExeStub.Size() + _archive.FirstHeader.ArcSize); break; + case kpidEmbeddedStubSize: prop = (UInt64)_archive.ExeStub.Size(); break; case kpidHeadersSize: prop = _archive.FirstHeader.HeaderSize; break; case kpidErrorFlags: @@ -611,7 +610,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, HRESULT res = _archive.Decoder.Decode( writeToTemp1 ? &tempBuf : NULL, item.IsUninstaller, item.PatchSize, - item.IsUninstaller ? NULL : realOutStream, + item.IsUninstaller ? NULL : (ISequentialOutStream *)realOutStream, progress, curPacked, curUnpacked32); curUnpacked = curUnpacked32; diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp index dc570ec2..6ca87df4 100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.cpp +++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp @@ -20,7 +20,7 @@ namespace NNsis { static const size_t kInputBufSize = 1 << 20; -static const Byte kSignature[kSignatureSize] = NSIS_SIGNATURE; +const Byte kSignature[kSignatureSize] = NSIS_SIGNATURE; static const UInt32 kMask_IsCompressed = (UInt32)1 << 31; static const unsigned kNumCommandParams = 6; @@ -30,7 +30,7 @@ static const unsigned kCmdSize = 4 + kNumCommandParams * 4; #define CR_LF "\x0D\x0A" #endif -static const char *kErrorStr = "$_ERROR_STR_"; +static const char * const kErrorStr = "$_ERROR_STR_"; #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } @@ -244,7 +244,7 @@ static const CCommandInfo k_Commands[kNumCmds] = #ifdef NSIS_SCRIPT -static const char *k_CommandNames[kNumCmds] = +static const char * const k_CommandNames[kNumCmds] = { "Invalid" , NULL // Return @@ -331,7 +331,7 @@ static const char *k_CommandNames[kNumCmds] = 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[] = +static const char * const kShellStrings[] = { "DESKTOP" // + , "INTERNET" // + @@ -526,7 +526,7 @@ void CInArchive::AddLicense(UInt32 param, Int32 langID) #define kVar_Spec_OUTDIR 31 // NSIS 2.26+ -static const char *kVarStrings[] = +static const char * const kVarStrings[] = { "CMDLINE" , "INSTDIR" @@ -963,8 +963,7 @@ void CInArchive::GetNsisString_Unicode_Raw(const Byte *p) 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; + Raw_UString.AddAscii(Raw_AString); continue; } c = n; @@ -1010,8 +1009,7 @@ void CInArchive::GetNsisString_Unicode_Raw(const Byte *p) 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; + Raw_UString.AddAscii(Raw_AString); } } @@ -1147,8 +1145,7 @@ void CInArchive::ReadString2_Raw(UInt32 pos) GetNsisString_Raw(_data + _stringsPos + pos); return; } - for (const char *s = (const char *)Raw_AString; *s != 0; s++) - Raw_UString += *s; + Raw_UString.SetFromAscii(Raw_AString); } bool CInArchive::IsGoodString(UInt32 param) const @@ -1417,7 +1414,7 @@ static const char *g_WinAttrib[] = #define FLAGS_DELIMITER '|' -static void FlagsToString2(CDynLimBuf &s, const char **table, unsigned num, UInt32 flags) +static void FlagsToString2(CDynLimBuf &s, const char * const *table, unsigned num, UInt32 flags) { bool filled = false; for (unsigned i = 0; i < num; i++) @@ -1536,7 +1533,7 @@ inline bool IsProbablyEndOfFunc(UInt32 flag) return (flag != 0 && flag != CMD_REF_Goto); } -static const char *kOnFunc[] = +static const char * const kOnFunc[] = { "Init" , "InstSuccess" @@ -1622,12 +1619,12 @@ static bool NoLabels(const UInt32 *labels, UInt32 num) return true; } -static const char *k_REBOOTOK = " /REBOOTOK"; +static const char * const k_REBOOTOK = " /REBOOTOK"; #define MY__MB_ABORTRETRYIGNORE 2 #define MY__MB_RETRYCANCEL 5 -static const char *k_MB_Buttons[] = +static const char * const k_MB_Buttons[] = { "OK" , "OKCANCEL" @@ -1640,7 +1637,7 @@ static const char *k_MB_Buttons[] = #define MY__MB_ICONSTOP (1 << 4) -static const char *k_MB_Icons[] = +static const char * const k_MB_Icons[] = { NULL , "ICONSTOP" @@ -1649,7 +1646,7 @@ static const char *k_MB_Icons[] = , "ICONINFORMATION" }; -static const char *k_MB_Flags[] = +static const char * const k_MB_Flags[] = { "HELP" , "NOFOCUS" @@ -1664,7 +1661,7 @@ static const char *k_MB_Flags[] = #define MY__IDCANCEL 2 #define MY__IDIGNORE 5 -static const char *k_Button_IDs[] = +static const char * const k_Button_IDs[] = { "0" , "IDOK" @@ -1702,31 +1699,6 @@ bool CInArchive::IsDirectString_Equal(UInt32 offset, const char *s) const 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; @@ -1816,7 +1788,7 @@ void CInArchive::Add_Color(UInt32 v) #define MY__SW_SHOWMINNOACTIVE 7 #define MY__SW_SHOWNA 8 -static const char *kShowWindow_Commands[] = +static const char * const kShowWindow_Commands[] = { "HIDE" , "SHOWNORMAL" // "NORMAL" @@ -1854,7 +1826,7 @@ void CInArchive::Add_ShowWindow_Cmd(UInt32 cmd) Add_UInt(cmd); } -void CInArchive::Add_TypeFromList(const char **table, unsigned tableSize, UInt32 type) +void CInArchive::Add_TypeFromList(const char * const *table, unsigned tableSize, UInt32 type) { if (type < tableSize) Script += table[type]; @@ -1886,7 +1858,7 @@ enum }; // Names for NSIS exec_flags_t structure vars -static const char *kExecFlags_VarsNames[] = +static const char * const kExecFlags_VarsNames[] = { "AutoClose" // autoclose; , "ShellVarContext" // all_user_var; @@ -1940,7 +1912,7 @@ enum PWP_CUSTOM }; -static const char *kPageTypes[] = +static const char * const kPageTypes[] = { "license" , "components" @@ -2062,7 +2034,7 @@ void CInArchive::AddStringLF(const char *s) // ---------- Section ---------- -static const char *kSection_VarsNames[] = +static const char * const kSection_VarsNames[] = { "Text" , "InstTypes" @@ -2240,7 +2212,7 @@ void CInArchive::NewLine() static const UInt32 kPageSize = 16 * 4; -static const char *k_SetOverwrite_Modes[] = +static const char * const k_SetOverwrite_Modes[] = { "on" , "off" @@ -2294,7 +2266,7 @@ void CInArchive::MessageBox_MB_Part(UInt32 param) 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++) + for (unsigned i = 0; i < ARRAY_SIZE(k_MB_Flags); i++) if ((flags & (1 << i)) != 0) { Script += "|MB_"; @@ -2327,8 +2299,7 @@ static const UInt32 kSectionSize_16bit_Big = kSectionSize_base + 8196 * 2; static void AddString(AString &dest, const char *src) { - if (!dest.IsEmpty()) - dest += ' '; + dest.Add_Space_if_NotEmpty(); dest += src; } @@ -3133,7 +3104,7 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) } default: continue; } - for (int i = 0; mask != 0; i++, mask >>= 1) + for (unsigned i = 0; mask != 0; i++, mask >>= 1) if (mask & 1) { UInt32 param = Get32(p + 4 + 4 * i); @@ -3535,17 +3506,11 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) 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; - } + item.Prefix = -1; + item.NameA.Empty(); + item.NameU.Empty(); + SetItemName(item, pars[1]); + // maybe here we can restore original item name, if new name is empty } } } @@ -5011,7 +4976,7 @@ HRESULT CInArchive::SortItems() #define CH_FLAGS_COMP_ONLY_ON_CUSTOM 256 #define CH_FLAGS_NO_CUSTOM 512 -static const char *k_PostStrings[] = +static const char * const k_PostStrings[] = { "install_directory_auto_append" , "uninstchild" // NSIS 2.25+, used by uninstaller: @@ -5242,7 +5207,7 @@ HRESULT CInArchive::Parse() AddRegRoot(rootKey); AddParam(subKey); AddParam(value); - NewLine(); + AddLF(); } } @@ -5296,6 +5261,9 @@ HRESULT CInArchive::Parse() UInt32 langtable_size = Get32(p2 + 32); if (bhLangTables.Num > 0) { + if (langtable_size == (UInt32)(Int32)-1) + return E_NOTIMPL; // maybe it's old NSIS archive() + UInt32 numStrings = (langtable_size - 10) / 4; _numLangStrings = numStrings; AddLF(); @@ -5310,7 +5278,7 @@ HRESULT CInArchive::Parse() { const Byte *p = _data + bhLangTables.Offset + langtable_size * i; LANGID langID = Get16(p); - UInt32 val = Get32(p + 10 + licenseLangIndex * 4); + UInt32 val = Get32(p + 10 + (UInt32)licenseLangIndex * 4); if (val != 0) { Script += "LicenseLangString "; @@ -5902,6 +5870,7 @@ void CInArchive::Clear2() Script.Empty(); LicenseFiles.Clear(); _numRootLicenses = 0; + _numLangStrings = 0; langStrIDs.Clear(); LangComment.Empty(); noParseStringIndexes.Clear(); diff --git a/CPP/7zip/Archive/Nsis/NsisIn.h b/CPP/7zip/Archive/Nsis/NsisIn.h index 3acd9ee5..2bab5299 100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.h +++ b/CPP/7zip/Archive/Nsis/NsisIn.h @@ -24,6 +24,7 @@ namespace NNsis { const size_t kScriptSizeLimit = 1 << 27; const unsigned kSignatureSize = 16; +extern const Byte kSignature[kSignatureSize]; #define NSIS_SIGNATURE { 0xEF, 0xBE, 0xAD, 0xDE, 'N', 'u', 'l', 'l', 's', 'o', 'f', 't', 'I', 'n', 's', 't' } const UInt32 kFlagsMask = 0xF; @@ -261,7 +262,7 @@ private: void Add_ButtonID(UInt32 buttonID); void Add_ShowWindow_Cmd(UInt32 cmd); - void Add_TypeFromList(const char **table, unsigned tableSize, UInt32 type); + void Add_TypeFromList(const char * const *table, unsigned tableSize, UInt32 type); void Add_ExecFlags(UInt32 flagsType); void Add_SectOp(UInt32 opType); diff --git a/CPP/7zip/Archive/Nsis/NsisRegister.cpp b/CPP/7zip/Archive/Nsis/NsisRegister.cpp index b363bdec..7230c3c2 100644 --- a/CPP/7zip/Archive/Nsis/NsisRegister.cpp +++ b/CPP/7zip/Archive/Nsis/NsisRegister.cpp @@ -9,16 +9,12 @@ namespace NArchive { namespace NNsis { -IMP_CreateArcIn - -static CArcInfo g_ArcInfo = - { "Nsis", "nsis", 0, 0x9, - NArchive::NNsis::kSignatureSize, NSIS_SIGNATURE, +REGISTER_ARC_I( + "Nsis", "nsis", 0, 0x9, + kSignature, 4, NArcInfoFlags::kFindSignature | NArcInfoFlags::kUseGlobalOffset, - CreateArc }; - -REGISTER_ARC(Nsis) + NULL) }} diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp index 6661492f..ee630a66 100644 --- a/CPP/7zip/Archive/NtfsHandler.cpp +++ b/CPP/7zip/Archive/NtfsHandler.cpp @@ -22,6 +22,7 @@ #include "../Common/MethodProps.h" #include "../Common/ProgressUtils.h" #include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" #include "../Common/StreamUtils.h" #include "../Compress/CopyCoder.h" @@ -62,6 +63,7 @@ static const wchar_t *kVirtualFolder_Lost_Deleted = L"[UNKNOWN]"; static const unsigned kNumSysRecs = 16; static const unsigned kRecIndex_Volume = 3; +static const unsigned kRecIndex_RootDir = 5; static const unsigned kRecIndex_BadClus = 8; static const unsigned kRecIndex_Security = 9; @@ -198,10 +200,18 @@ 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; + +/* WinXP-64: + Probably only one short name (dos name) per record is allowed. + There are no short names for hard links. + The pair (Win32,Dos) can be in any order. + Posix name can be after or before Win32 name +*/ + +static const Byte kFileNameType_Posix = 0; // for hard links +static const Byte kFileNameType_Win32 = 1; // after Dos name +static const Byte kFileNameType_Dos = 2; // short name +static const Byte kFileNameType_Win32Dos = 3; // short and full name are same struct CFileNameAttr { @@ -215,21 +225,31 @@ struct CFileNameAttr // UInt64 AllocatedSize; // UInt64 DataSize; // UInt16 PackedEaSize; - UString Name; + UString2 Name; UInt32 Attrib; Byte NameType; bool IsDos() const { return NameType == kFileNameType_Dos; } + bool IsWin32() const { return (NameType == kFileNameType_Win32); } + bool Parse(const Byte *p, unsigned size); }; -static void GetString(const Byte *p, unsigned len, UString &res) +static void GetString(const Byte *p, unsigned len, UString2 &res) { - wchar_t *s = res.GetBuffer(len); - for (unsigned i = 0; i < len; i++) - s[i] = Get16(p + i * 2); - s[len] = 0; - res.ReleaseBuffer(); + if (len == 0 && res.IsEmpty()) + return; + wchar_t *s = res.GetBuf(len); + unsigned i; + for (i = 0; i < len; i++) + { + wchar_t c = Get16(p + i * 2); + if (c == 0) + break; + s[i] = c; + } + s[i] = 0; + res.ReleaseBuf_SetLen(i); } bool CFileNameAttr::Parse(const Byte *p, unsigned size) @@ -249,7 +269,8 @@ bool CFileNameAttr::Parse(const Byte *p, unsigned size) unsigned len = p[0x40]; if (0x42 + len > size) return false; - GetString(p + 0x42, len, Name); + if (len != 0) + GetString(p + 0x42, len, Name); return true; } @@ -321,7 +342,7 @@ struct CAttr { UInt32 Type; // UInt32 Len; - UString Name; + UString2 Name; // UInt16 Flags; // UInt16 Instance; CByteBuffer Data; @@ -364,7 +385,17 @@ 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(wcscmp(a1.Name, a2.Name)); + if (a1.Name.IsEmpty()) + { + if (!a2.Name.IsEmpty()) + return -1; + } + else if (a2.Name.IsEmpty()) + return 1; + else + { + RINOZ(wcscmp(a1.Name.GetRawPtr(), a2.Name.GetRawPtr())); + } return MyCompare(a1.LowVcn, a2.LowVcn); } @@ -387,13 +418,13 @@ UInt32 CAttr::Parse(const Byte *p, unsigned size) return 0; NonResident = p[0x08]; { - unsigned nameLength = p[9]; + unsigned nameLen = p[9]; UInt32 nameOffset = Get16(p + 0x0A); - if (nameLength != 0) + if (nameLen != 0) { - if (nameOffset + nameLength * 2 > len) + if (nameOffset + nameLen * 2 > len) return 0; - GetString(p + nameOffset, nameLength, Name); + GetString(p + nameOffset, nameLen, Name); PRF(printf(" N=")); PRF_UTF16(Name); } @@ -485,10 +516,11 @@ bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, if (num == 0 || num > 8 || num > size) return false; - int i; - UInt64 vSize = p[num - 1]; - for (i = (int)num - 2; i >= 0; i--) - vSize = (vSize << 8) | p[i]; + UInt64 vSize = 0; + { + unsigned i = num; + do vSize = (vSize << 8) | p[--i]; while(i); + } if (vSize == 0) return false; p += num; @@ -510,8 +542,10 @@ bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, else { Int64 v = (signed char)p[num - 1]; - for (i = (int)num - 2; i >= 0; i--) - v = (v << 8) | p[i]; + { + for (unsigned i = num - 1; i != 0;) + v = (v << 8) | p[--i]; + } p += num; size -= num; lcn += v; @@ -617,7 +651,7 @@ static size_t Lznt1Dec(Byte *dest, size_t outBufLim, size_t destLen, const Byte { if (destSize + (1 << 12) > outBufLim || (src[0] & 1) != 0) return 0; - int numDistBits = 4; + unsigned numDistBits = 4; UInt32 sbOffset = 0; UInt32 pos = 0; @@ -669,7 +703,7 @@ static size_t Lznt1Dec(Byte *dest, size_t outBufLim, size_t destLen, const Byte STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { - if (processedSize != NULL) + if (processedSize) *processedSize = 0; if (_virtPos >= Size) return (Size == _virtPos) ? S_OK: E_FAIL; @@ -830,7 +864,7 @@ STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize) res = Stream->Read(data, size, &size); _physPos += size; } - if (processedSize != NULL) + if (processedSize) *processedSize = size; _virtPos += size; _curRem -= size; @@ -858,54 +892,6 @@ STDMETHODIMP CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPositio return S_OK; } -class CByteBufStream: - public IInStream, - public CMyUnknownImp -{ - UInt64 _virtPos; -public: - CByteBuffer Buf; - void Init() { _virtPos = 0; } - - MY_UNKNOWN_IMP1(IInStream) - - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); -}; - -STDMETHODIMP CByteBufStream::Read(void *data, UInt32 size, UInt32 *processedSize) -{ - if (processedSize != NULL) - *processedSize = 0; - 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); - if (processedSize != NULL) - *processedSize = size; - _virtPos += size; - return S_OK; -} - -STDMETHODIMP CByteBufStream::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 += Buf.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; -} - static HRESULT DataParseExtents(unsigned clusterSizeLog, const CObjectVector<CAttr> &attrs, unsigned attrIndex, unsigned attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &Extents) { @@ -966,7 +952,9 @@ struct CMftRec // UInt16 NextAttrInstance; CMftRef BaseMftRef; // UInt32 ThisRecNumber; + UInt32 MyNumNameLinks; + int MyItemIndex; // index in Items[] of main item for that record, or -1 if there is no item for that record CObjectVector<CAttr> DataAttrs; CObjectVector<CFileNameAttr> FileNames; @@ -977,12 +965,40 @@ struct CMftRec CByteBuffer ReparseData; + int FindWin32Name_for_DosName(unsigned dosNameIndex) const + { + const CFileNameAttr &cur = FileNames[dosNameIndex]; + if (cur.IsDos()) + for (unsigned i = 0; i < FileNames.Size(); i++) + { + const CFileNameAttr &next = FileNames[i]; + if (next.IsWin32() && cur.ParentDirRef.Val == next.ParentDirRef.Val) + return i; + } + return -1; + } + + int FindDosName(unsigned nameIndex) const + { + const CFileNameAttr &cur = FileNames[nameIndex]; + if (cur.IsWin32()) + for (unsigned i = 0; i < FileNames.Size(); i++) + { + const CFileNameAttr &next = FileNames[i]; + if (next.IsDos() && cur.ParentDirRef.Val == next.ParentDirRef.Val) + return i; + } + return -1; + } + + /* bool IsAltStream(int dataIndex) const { return dataIndex >= 0 && ( (IsDir() || !DataAttrs[DataRefs[dataIndex].Start].Name.IsEmpty())); } + */ void MoveAttrsFrom(CMftRec &src) { @@ -1016,7 +1032,7 @@ struct CMftRec UInt64 GetSize(unsigned dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); } - CMftRec(): MyNumNameLinks(0) {} + CMftRec(): MyNumNameLinks(0), MyItemIndex(-1) {} }; void CMftRec::ParseDataNames() @@ -1040,12 +1056,10 @@ HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex, unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **destStream) const { *destStream = 0; - CByteBufStream *streamSpec = new CByteBufStream; + CBufferInStream *streamSpec = new CBufferInStream; CMyComPtr<IInStream> streamTemp = streamSpec; - if (dataIndex < 0) - return E_FAIL; - + if (dataIndex >= 0) if ((unsigned)dataIndex < DataRefs.Size()) { const CDataRef &ref = DataRefs[dataIndex]; @@ -1231,26 +1245,42 @@ bool CMftRec::Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 r return true; } +/* + NTFS probably creates empty DATA_ATTRIBUTE for empty file, + But it doesn't do it for + $Secure (:$SDS), + $Extend\$Quota + $Extend\$ObjId + $Extend\$Reparse +*/ + +static const int k_Item_DataIndex_IsEmptyFile = -1; // file without unnamed data stream +static const int k_Item_DataIndex_IsDir = -2; + +// static const int k_ParentFolderIndex_Root = -1; +static const int k_ParentFolderIndex_Lost = -2; +static const int k_ParentFolderIndex_Deleted = -3; + struct CItem { 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 */ + -1: file without unnamed data stream + -2: for directories */ 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 */ + -1: if it's not AltStream */ - CItem(): DataIndex(-1), ParentFolder(-1), ParentHost(-1) {} + CItem(): DataIndex(k_Item_DataIndex_IsDir), ParentFolder(-1), ParentHost(-1) {} - bool IsDir() const { return DataIndex < 0; } + bool IsAltStream() const { return ParentHost != -1; } + bool IsDir() const { return DataIndex == k_Item_DataIndex_IsDir; } // check it !!! // probably NTFS for empty file still creates empty DATA_ATTRIBUTE // But it doesn't do it for $Secure:$SDS @@ -1276,7 +1306,9 @@ struct CDatabase bool _showSystemFiles; bool _showDeletedFiles; - UStringVector VirtFolderNames; + CObjectVector<UString2> VirtFolderNames; + UString EmptyString; + int _systemFolderIndex; int _lostFolderIndex_Normal; int _lostFolderIndex_Deleted; @@ -1311,6 +1343,8 @@ struct CDatabase const CMftRec &rec = Recs[(unsigned)recIndex]; if (!rec.IsDir()) return -1; + return rec.MyItemIndex; + /* unsigned left = 0, right = Items.Size(); while (left != right) { @@ -1319,9 +1353,9 @@ struct CDatabase UInt64 midValue = item.RecIndex; if (recIndex == midValue) { - // if (!item.IsAltStream) - // if (!rec.IsAltStream(item.DataIndex)) - if (item.DataIndex < 0) + // if item is not dir (file or alt stream we don't return it) + // if (item.DataIndex < 0) + if (item.IsDir()) return mid; right = mid; } @@ -1331,6 +1365,7 @@ struct CDatabase left = mid + 1; } return -1; + */ } bool FindSecurityDescritor(UInt32 id, UInt64 &offset, UInt32 &size) const; @@ -1374,8 +1409,6 @@ void CDatabase::ClearAndClose() InStream.Release(); } -#define MY_DIR_PREFIX(x) L"[" x L"]" WSTRING_PATH_SEPARATOR - void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const { const CItem *item = &Items[index]; @@ -1383,22 +1416,24 @@ void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const const CMftRec &rec = Recs[item->RecIndex]; size += rec.FileNames[item->NameIndex].Name.Len(); - bool isAltStream = rec.IsAltStream(item->DataIndex); + bool isAltStream = item->IsAltStream(); + if (isAltStream) { const CAttr &data = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start]; + if (item->RecIndex == kRecIndex_RootDir) + { + wchar_t *s = path.AllocBstr(data.Name.Len() + 1); + s[0] = L':'; + if (!data.Name.IsEmpty()) + MyStringCopy(s + 1, data.Name.GetRawPtr()); + return; + } + 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) @@ -1407,7 +1442,8 @@ void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const return; } const wchar_t *servName; - if (item->RecIndex < kNumSysRecs) + if (item->RecIndex < kNumSysRecs + /* && item->RecIndex != kRecIndex_RootDir */) servName = kVirtualFolder_System; else { @@ -1420,7 +1456,7 @@ void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const } if (index2 == -1) break; - servName = (index2 == -2) ? + servName = (index2 == k_ParentFolderIndex_Lost) ? kVirtualFolder_Lost_Normal : kVirtualFolder_Lost_Deleted; } @@ -1435,47 +1471,31 @@ void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const 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); + const UString2 &name = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start].Name; + if (!name.IsEmpty()) + { + size -= name.Len(); + MyStringCopy(s + size, name.GetRawPtr()); + } s[--size] = ':'; needColon = true; } { - const UString &name = rec.FileNames[item->NameIndex].Name; + const UString2 &name = rec.FileNames[item->NameIndex].Name; unsigned len = name.Len(); - MyStringCopy(s + size - len, (const wchar_t *)name); + if (len != 0) + MyStringCopy(s + size - len, name.GetRawPtr()); 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) + if (item->RecIndex < kNumSysRecs + /* && && item->RecIndex != kRecIndex_RootDir */) servName = kVirtualFolder_System; else { @@ -1483,17 +1503,20 @@ void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const if (index2 >= 0) { item = &Items[index2]; - const UString &name = Recs[item->RecIndex].FileNames[item->NameIndex].Name; + const UString2 &name = Recs[item->RecIndex].FileNames[item->NameIndex].Name; unsigned len = name.Len(); size--; - size -= len; - MyStringCopy(s + size, (const wchar_t *)name); + if (len != 0) + { + size -= len; + MyStringCopy(s + size, name.GetRawPtr()); + } s[size + len] = WCHAR_PATH_SEPARATOR; continue; } if (index2 == -1) break; - servName = (index2 == -2) ? + servName = (index2 == k_ParentFolderIndex_Lost) ? kVirtualFolder_Lost_Normal : kVirtualFolder_Lost_Deleted; } @@ -1800,120 +1823,110 @@ HRESULT CDatabase::Open() if (!rec.InUse() && !_showDeletedFiles) continue; - unsigned numNames = 0; + rec.MyNumNameLinks = rec.FileNames.Size(); + // printf("\n%4d: ", i); - FOR_VECTOR (t, rec.FileNames) - { - const CFileNameAttr &fna = rec.FileNames[t]; - // PRF(printf("%4d ", (int)fna.NameType)); - // PRF_UTF16(fna.Name) - // PRF(printf(" | ")); - if (fna.IsDos()) - continue; - unsigned numDatas = rec.DataRefs.Size(); - - /* - // 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; - */ + + /* Actually DataAttrs / DataRefs are sorted by name. + It can not be more than one unnamed stream in DataRefs + And indexOfUnnamedStream <= 0. + */ - numNames++; + int indexOfUnnamedStream = -1; + if (!rec.IsDir()) + { + FOR_VECTOR(di, rec.DataRefs) + if (rec.DataAttrs[rec.DataRefs[di].Start].Name.IsEmpty()) + { + indexOfUnnamedStream = di; + break; + } + } - // here we suppose that first stream is main stream (unnamed stream). - // IS IT SO ???? - int hostIndex = -1; - if (rec.IsDir()) + if (rec.FileNames.IsEmpty()) + { + bool needShow = true; + if (i < kNumSysRecs) { - CItem item; - item.NameIndex = t; - item.RecIndex = i; - // item.ParentRef = fna.ParentDirRef; - // item.Attrib = rec.SiAttr.Attrib | 0x10; - // item.Attrib = fna.Attrib; - hostIndex = Items.Add(item); + needShow = false; + FOR_VECTOR(di, rec.DataRefs) + if (rec.GetSize(di) != 0) + { + needShow = true; + break; + } } - else + if (needShow) { - - // 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); - } + CFileNameAttr &fna = rec.FileNames.AddNew(); + // we set incorrect ParentDirRef, that will place item to [LOST] folder + fna.ParentDirRef.Val = (UInt64)(Int64)-1; + char s[16 + 16]; + ConvertUInt32ToString(i, MyStpCpy(s, "[NONAME]-")); + fna.Name.SetFromAscii(s); + fna.NameType = kFileNameType_Win32Dos; + fna.Attrib = 0; } + } + + // bool isMainName = true; + + FOR_VECTOR (t, rec.FileNames) + { + #ifdef SHOW_DEBUG_INFO + const CFileNameAttr &fna = rec.FileNames[t]; + #endif + PRF(printf("\n %4d ", (int)fna.NameType)); + PRF_UTF16(fna.Name); + // PRF(printf(" | ")); + if (rec.FindWin32Name_for_DosName(t) >= 0) { - 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; - } + rec.MyNumNameLinks--; + continue; } + + CItem item; + item.NameIndex = t; + item.RecIndex = i; + item.DataIndex = rec.IsDir() ? + k_Item_DataIndex_IsDir : + (indexOfUnnamedStream < 0 ? + k_Item_DataIndex_IsEmptyFile : + indexOfUnnamedStream); + + if (rec.MyItemIndex < 0) + rec.MyItemIndex = Items.Size(); + item.ParentHost = Items.Add(item); + + /* we can use that code to reduce the number of alt streams: + it will not show how alt streams for hard links. */ + // if (!isMainName) continue; isMainName = false; + + unsigned numAltStreams = 0; - for (unsigned di = 0; di < numDatas; di++) + FOR_VECTOR(di, rec.DataRefs) { - CItem item; - 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 (hostIndex >= 0) - continue; - hostIndex = Items.Size(); - } - else + if (!rec.IsDir() && (int)di == indexOfUnnamedStream) + continue; + + const UString2 &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name; + + PRF(printf("\n alt stream: ")); + PRF_UTF16(subName); + { // $BadClus:$Bad is sparse file for all clusters. So we skip it. if (i == kRecIndex_BadClus && subName == L"$Bad") continue; - 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_UTF16(item.Name); - - item.RecIndex = i; - item.DataIndex = di; - // item.ParentRef = fna.ParentDirRef; + numAltStreams++; + ThereAreAltStreams = true; + item.DataIndex = di; Items.Add(item); - rec.MyNumNameLinks++; } } - // rec.FileNames.ClearAndFree(); } if (Recs.Size() > kRecIndex_Security) @@ -1959,7 +1972,7 @@ HRESULT CDatabase::Open() const CFileNameAttr &fn = rec.FileNames[item.NameIndex]; const CMftRef &parentDirRef = fn.ParentDirRef; UInt64 refIndex = parentDirRef.GetIndex(); - if (refIndex == 5) + if (refIndex == kRecIndex_RootDir) item.ParentFolder = -1; else { @@ -1970,12 +1983,12 @@ HRESULT CDatabase::Open() if (Recs[item.RecIndex].InUse()) { thereAreUnknownFolders_Normal = true; - index = -2; + index = k_ParentFolderIndex_Lost; } else { thereAreUnknownFolders_Deleted = true; - index = -3; + index = k_ParentFolderIndex_Deleted; } } item.ParentFolder = index; @@ -2019,7 +2032,7 @@ public: INTERFACE_IInArchive(;) INTERFACE_IArchiveGetRawProps(;) STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); }; STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) @@ -2038,29 +2051,30 @@ STDMETHODIMP CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType) { *parentType = NParentType::kDir; - *parent = (UInt32)(Int32)-1; + int par = -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 (index < Items.Size()) { - 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; + const CItem &item = Items[index]; + + if (item.ParentHost >= 0) + { + *parentType = NParentType::kAltStream; + par = (item.RecIndex == kRecIndex_RootDir ? -1 : item.ParentHost); + } + else if (item.RecIndex < kNumSysRecs) + { + if (_showSystemFiles) + par = _systemFolderIndex; + } + else if (item.ParentFolder >= 0) + par = item.ParentFolder; + else if (item.ParentFolder == k_ParentFolderIndex_Lost) + par = _lostFolderIndex_Normal; + else if (item.ParentFolder == k_ParentFolderIndex_Deleted) + par = _lostFolderIndex_Deleted; + } + *parent = (UInt32)(Int32)par; return S_OK; } @@ -2073,30 +2087,22 @@ STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data if (propID == kpidName) { #ifdef MY_CPU_LE - const UString *s; + const UString2 *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; - } + if (item.IsAltStream()) + s = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start].Name; else - { s = &rec.FileNames[item.NameIndex].Name; - } - // s = &item.Name; } - *data = (const wchar_t *)*s; + if (s->IsEmpty()) + *data = (const wchar_t *)EmptyString; + else + *data = s->GetRawPtr(); *dataSize = (s->Len() + 1) * sizeof(wchar_t); *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE; #endif @@ -2209,6 +2215,9 @@ static const Byte kProps[] = kpidLinks, kpidINode, kpidNumBlocks, + kpidNumAltStreams, + kpidIsAltStream, + kpidShortName, kpidIsDeleted }; @@ -2293,9 +2302,10 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) const CAttr &attr = VolAttrs[i]; if (attr.Type == ATTR_TYPE_VOLUME_NAME) { - UString name; + UString2 name; GetString(attr.Data, (unsigned)attr.Data.Size() / 2, name); - prop = name; + if (!name.IsEmpty()) + prop = name.GetRawPtr(); break; } } @@ -2312,7 +2322,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) CVolInfo vi; if (attr.ParseVolInfo(vi)) { - s += ' '; + s.Add_Space(); char temp[16]; ConvertUInt32ToString(vi.MajorVer, temp); s += temp; @@ -2339,6 +2349,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidWarning: if (_lostFolderIndex_Normal >= 0) prop = "There are lost files"; + break; /* case kpidWarningFlags: @@ -2372,7 +2383,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { case kpidName: case kpidPath: - prop = VirtFolderNames[index - Items.Size()]; + prop = VirtFolderNames[index - Items.Size()].GetRawPtr(); break; case kpidIsDir: prop = true; break; case kpidIsAux: prop = true; break; @@ -2433,35 +2444,46 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = item.RecIndex; break; } + case kpidStreamId: + { + if (item.DataIndex >= 0) + prop = ((UInt64)item.RecIndex << 32) | (unsigned)item.DataIndex; + break; + } case kpidName: { - // prop = item.Name; - const UString *s; - if (rec.IsAltStream(item.DataIndex)) + const UString2 *s; + if (item.IsAltStream()) + s = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start].Name; + else + s = &rec.FileNames[item.NameIndex].Name; + if (s->IsEmpty()) + prop = (const wchar_t *)EmptyString; + else + prop = s->GetRawPtr(); + break; + } + + case kpidShortName: + { + if (!item.IsAltStream()) { - const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start]; - s = &data.Name; - if (item.ParentHost < 0) + int dosNameIndex = rec.FindDosName(item.NameIndex); + if (dosNameIndex >= 0) { - UString s2 = rec.FileNames[item.NameIndex].Name; - s2 += L':'; - s2 += *s; - prop = s2; - break; + const UString2 &s = rec.FileNames[dosNameIndex].Name; + if (s.IsEmpty()) + prop = (const wchar_t *)EmptyString; + else + prop = s.GetRawPtr(); } } - 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 kpidIsAltStream: prop = item.IsAltStream(); break; case kpidIsDeleted: prop = !rec.InUse(); break; case kpidIsAux: prop = false; break; @@ -2491,12 +2513,35 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (item.IsDir()) attrib |= FILE_ATTRIBUTE_DIRECTORY; + /* some system entries can contain extra flags (Index View). + // 0x10000000 (Directory) + // 0x20000000 FILE_ATTR_VIEW_INDEX_PRESENT MFT_RECORD_IS_VIEW_INDEX (Index View) + But we don't need them */ + attrib &= 0xFFFF; + 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; + case kpidLinks: if (rec.MyNumNameLinks != 1) prop = rec.MyNumNameLinks; break; + + case kpidNumAltStreams: + { + if (!item.IsAltStream()) + { + unsigned num = rec.DataRefs.Size(); + if (num > 0) + { + if (!rec.IsDir() && rec.DataAttrs[rec.DataRefs[0].Start].Name.IsEmpty()) + num--; + if (num > 0) + prop = num; + } + } + break; + } + + case kpidSize: if (data) prop = data->GetSize(); else if (!item.IsDir()) prop = (UInt64)0; break; + case kpidPackSize: if (data) prop = data->GetPackSize(); else if (!item.IsDir()) prop = (UInt64)0; break; case kpidNumBlocks: if (data) prop = (UInt32)rec.GetNumExtents(item.DataIndex, Header.ClusterSizeLog, Header.NumClusters); break; } prop.Detach(value); @@ -2603,7 +2648,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, outStreamSpec->Init(); const CMftRec &rec = Recs[item.RecIndex]; - const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start]; int res = NExtract::NOperationResult::kDataError; { @@ -2626,8 +2670,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } } } - totalPackSize += data.GetPackSize(); - totalSize += data.GetSize(); + if (item.DataIndex >= 0) + { + const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start]; + totalPackSize += data.GetPackSize(); + totalSize += data.GetSize(); + } outStreamSpec->ReleaseStream(); RINOK(extractCallback->SetOperationResult(res)); } @@ -2641,7 +2689,7 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) return S_OK; } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { InitProps(); @@ -2668,15 +2716,13 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v return S_OK; } -IMP_CreateArcIn +static const Byte k_Signature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 }; -static CArcInfo g_ArcInfo = - { "NTFS", "ntfs img", 0, 0xD9, - 9, { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 }, +REGISTER_ARC_I( + "NTFS", "ntfs img", 0, 0xD9, + k_Signature, 3, 0, - CreateArc }; - -REGISTER_ARC(Ntfs) + NULL) }} diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp index ae7553df..43450e80 100644 --- a/CPP/7zip/Archive/PeHandler.cpp +++ b/CPP/7zip/Archive/PeHandler.cpp @@ -37,7 +37,7 @@ using namespace NWindows; namespace NArchive { namespace NPe { -static const UInt32 k_Signature = 0x00004550; +static const UInt32 k_Signature32 = 0x00004550; static HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 excludePos, UInt32 &res) { @@ -137,7 +137,7 @@ struct CHeader bool CHeader::Parse(const Byte *p) { - if (Get32(p) != k_Signature) + if (Get32(p) != k_Signature32) return false; p += 4; G16( 0, Machine); @@ -364,19 +364,14 @@ struct CSection static const unsigned kNameSize = 8; -static AString GetName(const Byte *name) +static void GetName(const Byte *name, AString &res) { - AString res; - char *p = res.GetBuffer(kNameSize); - memcpy(p, name, kNameSize); - p[kNameSize] = 0; - res.ReleaseBuffer(); - return res; + res.SetFrom_CalcLen((const char *)name, kNameSize); } void CSection::Parse(const Byte *p) { - Name = GetName(p); + GetName(p, Name); G32( 8, VSize); G32(12, Va); G32(16, PSize); @@ -484,33 +479,33 @@ static const CUInt32PCharPair g_SubSystems[] = { 14, "XBOX" } }; -static const wchar_t *g_ResTypes[] = +static const char * const 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" + , "CURSOR" + , "BITMAP" + , "ICON" + , "MENU" + , "DIALOG" + , "STRING" + , "FONTDIR" + , "FONT" + , "ACCELERATOR" + , "RCDATA" + , "MESSAGETABLE" + , "GROUP_CURSOR" , NULL - , L"GROUP_ICON" + , "GROUP_ICON" , NULL - , L"VERSION" - , L"DLGINCLUDE" + , "VERSION" + , "DLGINCLUDE" , NULL - , L"PLUGPLAY" - , L"VXD" - , L"ANICURSOR" - , L"ANIICON" - , L"HTML" - , L"MANIFEST" + , "PLUGPLAY" + , "VXD" + , "ANICURSOR" + , "ANIICON" + , "HTML" + , "MANIFEST" }; static const UInt32 kFlag = (UInt32)1 << 31; @@ -561,7 +556,10 @@ struct CTextFile void NewLine(); void AddString(const char *s); void AddSpaces(int num); - void AddBytes(const Byte *p, size_t len); + void AddBytes(const Byte *p, size_t size) + { + Buf.AddData(p, size); + } void OpenBlock(int num) { @@ -623,12 +621,6 @@ void CTextFile::AddSpaces(int num) 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; @@ -648,7 +640,7 @@ struct CMixItem int VersionIndex; CMixItem(): SectionIndex(-1), ResourceIndex(-1), StringIndex(-1), VersionIndex(-1) {} - bool IsSectionItem() const { return ResourceIndex < 0 && StringIndex < 0 && VersionIndex < 0; }; + bool IsSectionItem() const { return ResourceIndex < 0 && StringIndex < 0 && VersionIndex < 0; } }; struct CUsedBitmap @@ -802,6 +794,7 @@ static const STATPROPSTG kArcProps[] = { (LPOLESTR)L"Heap Commit", kpidHeapCommit, VT_UI8}, { (LPOLESTR)L"Image Base", kpidImageBase, VT_UI8}, { NULL, kpidComment, VT_BSTR}, + // { (LPOLESTR)L"Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8}, // { (LPOLESTR)L"Base Of Code", kpidBaseOfCode, VT_UI8}, // { (LPOLESTR)L"Base Of Data", kpidBaseOfData32, VT_UI8}, @@ -913,7 +906,7 @@ HRESULT CHandler::ReadString(UInt32 offset, UString &dest) const if ((rem - 2) / 2 < len) return S_FALSE; dest.Empty(); - wchar_t *destBuf = dest.GetBuffer(len); + wchar_t *destBuf = dest.GetBuf(len); offset += 2; const Byte *src = _buf + offset; unsigned i; @@ -924,7 +917,8 @@ HRESULT CHandler::ReadString(UInt32 offset, UString &dest) const break; destBuf[i] = c; } - dest.ReleaseBuffer(i); + destBuf[i] = 0; + dest.ReleaseBuf_SetLen(i); return S_OK; } @@ -960,7 +954,7 @@ void CHandler::AddLangPrefix(UString &s, UInt32 lang) const if (!_oneLang) { AddResNameToString(s, lang); - s += WCHAR_PATH_SEPARATOR; + s.Add_PathSepar(); } } @@ -978,7 +972,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { UString s = _resourcesPrefix; AddLangPrefix(s, item.Lang); - s += L"string.txt"; + s.AddAscii("string.txt"); prop = s; break; } @@ -996,7 +990,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { UString s = _resourcesPrefix; AddLangPrefix(s, item.Lang); - s += L"version.txt"; + s.AddAscii("version.txt"); prop = s; break; } @@ -1015,22 +1009,22 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val UString s = _resourcesPrefix; AddLangPrefix(s, item.Lang); { - const wchar_t *p = NULL; + const char *p = NULL; if (item.Type < ARRAY_SIZE(g_ResTypes)) p = g_ResTypes[item.Type]; if (p) - s += p; + s.AddAscii(p); else AddResNameToString(s, item.Type); } - s += WCHAR_PATH_SEPARATOR; + s.Add_PathSepar(); AddResNameToString(s, item.ID); if (item.HeaderSize != 0) { if (item.IsBmp()) - s += L".bmp"; + s.AddAscii(".bmp"); else if (item.IsIcon()) - s += L".ico"; + s.AddAscii(".ico"); } prop = s; break; @@ -1199,11 +1193,14 @@ static UInt32 SetBitmapHeader(Byte *dest, const Byte *src, UInt32 size) return 0; if (h.YSize < 0) h.YSize = -h.YSize; - if (h.XSize > (1 << 26) || h.YSize > (1 << 26) || h.Planes != 1 || h.BitCount > 32 || - h.Compression != 0) // BI_RGB + if (h.XSize > (1 << 26) || h.YSize > (1 << 26) || h.Planes != 1 || h.BitCount > 32) return 0; if (h.SizeImage == 0) + { + if (h.Compression != 0) // BI_RGB + return 0; h.SizeImage = GetImageSize(h.XSize, h.YSize, h.BitCount); + } UInt32 totalSize = kBmpHeaderSize + size; UInt32 offBits = totalSize - h.SizeImage; // BITMAPFILEHEADER @@ -1413,7 +1410,7 @@ static void PrintVersion(UString &s, UInt32 ms, UInt32 ls) PrintUInt32(s, LOWORD(ls)); } -static const char *k_VS_FileFlags[] = +static const char * const k_VS_FileFlags[] = { "DEBUG" , "PRERELEASE" @@ -1432,7 +1429,7 @@ static const CUInt32PCharPair k_VS_FileOS[] = { 0x40004, "VOS_NT_WINDOWS32" } }; -static const char *k_VS_FileOS_High[] = +static const char * const k_VS_FileOS_High[] = { "VOS_UNKNOWN" , "VOS_DOS" @@ -1445,7 +1442,7 @@ static const char *k_VS_FileOS_High[] = static const UInt32 kMY_VFT_DRV = 3; static const UInt32 kMY_VFT_FONT = 4; -static const char *k_VS_FileOS_Low[] = +static const char * const k_VS_FileOS_Low[] = { "VOS__BASE" , "VOS__WINDOWS16" @@ -1454,7 +1451,7 @@ static const char *k_VS_FileOS_Low[] = , "VOS__WINDOWS32" }; -static const char *k_VS_FileType[] = +static const char * const k_VS_FileType[] = { "VFT_UNKNOWN" , "VFT_APP" @@ -1467,7 +1464,7 @@ static const char *k_VS_FileType[] = }; // Subtype for VFT_DRV Type -static const char *k_VS_FileSubType_DRV[] = +static const char * const k_VS_FileSubType_DRV[] = { "0" , "PRINTER" @@ -1485,7 +1482,7 @@ static const char *k_VS_FileSubType_DRV[] = }; // Subtype for VFT_FONT Type -static const char *k_VS_FileSubType_FONT[] = +static const char * const k_VS_FileSubType_FONT[] = { "0" , "VFT2_FONT_RASTER" @@ -1493,10 +1490,10 @@ static const char *k_VS_FileSubType_FONT[] = , "VFT2_FONT_TRUETYPE" }; -static int FindKey(CObjectVector<CStringKeyValue> &v, const UString &key) +static int FindKey(CObjectVector<CStringKeyValue> &v, const char *key) { FOR_VECTOR (i, v) - if (v[i].Key == key) + if (v[i].Key.IsEqualTo(key)) return i; return -1; } @@ -1665,7 +1662,7 @@ struct CVersionBlock UInt32 TotalLen; UInt32 ValueLen; bool IsTextValue; - int StrSize; + unsigned StrSize; bool Parse(const Byte *p, UInt32 size); }; @@ -1691,7 +1688,7 @@ bool CVersionBlock::Parse(const Byte *p, UInt32 size) return false; TotalLen = Get16(p); ValueLen = Get16(p + 2); - if (TotalLen > size) + if (TotalLen == 0 || TotalLen > size) return false; switch (Get16(p + 4)) { @@ -1699,8 +1696,12 @@ bool CVersionBlock::Parse(const Byte *p, UInt32 size) case 1: IsTextValue = true; break; default: return false; } - StrSize = Get_Utf16Str_Len_InBytes(p + k_ResoureBlockHeader_Size, TotalLen - k_ResoureBlockHeader_Size); - return StrSize >= 0; + StrSize = 0; + int t = Get_Utf16Str_Len_InBytes(p + k_ResoureBlockHeader_Size, TotalLen - k_ResoureBlockHeader_Size); + if (t < 0) + return false; + StrSize = t; + return true; } static void AddParamString(CTextFile &f, const Byte *p, size_t sLen) @@ -1868,7 +1869,7 @@ static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector int sLen = Get_Utf16Str_Len_InBytes(p + pos, endPos3 - pos); if (sLen < 0) return false; - AddParamString(f, p + pos, sLen); + AddParamString(f, p + pos, (unsigned)sLen); CopyToUString(p + pos, value); pos += sLen + 2; } @@ -2276,6 +2277,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) // _parseResources = false; UInt64 mainSize = 0, mainSize2 = 0; + for (i = 0; i < _sections.Size(); i++) { const CSection § = _sections[i]; @@ -2287,7 +2289,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) if (res == S_OK) { _resourcesPrefix.SetFromAscii(sect.Name); - _resourcesPrefix += WCHAR_PATH_SEPARATOR; + _resourcesPrefix.Add_PathSepar(); FOR_VECTOR (j, _items) { const CResItem &item = _items[j]; @@ -2348,7 +2350,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) mainSize = sect.PSize; _mainSubfile = _mixItems.Size(); } - else + else if (sect.PSize >= mainSize2) mainSize2 = sect.PSize; } _mixItems.Add(mixItem); @@ -2370,7 +2372,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) for (i = 0; i < _versionKeys.Size(); i++) { if (i != 0) - _versionFullString += L'\n'; + _versionFullString.Add_LF(); const CStringKeyValue &k = _versionKeys[i]; _versionFullString += k.Key; _versionFullString += L": "; @@ -2378,20 +2380,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) } { - int keyIndex = FindKey(_versionKeys, L"OriginalFilename"); + int keyIndex = FindKey(_versionKeys, "OriginalFilename"); if (keyIndex >= 0) _originalFilename = _versionKeys[keyIndex].Value; } { - int keyIndex = FindKey(_versionKeys, L"FileDescription"); + int keyIndex = FindKey(_versionKeys, "FileDescription"); if (keyIndex >= 0) _versionShortString = _versionKeys[keyIndex].Value; } { - int keyIndex = FindKey(_versionKeys, L"FileVersion"); + int keyIndex = FindKey(_versionKeys, "FileVersion"); if (keyIndex >= 0) { - _versionShortString += L' '; + _versionShortString.Add_Space(); _versionShortString += _versionKeys[keyIndex].Value; } } @@ -2597,7 +2599,8 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) } referenceBuf->Buf.Alloc(item.HeaderSize + item.Size); memcpy(referenceBuf->Buf, item.Header, item.HeaderSize); - memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size); + if (item.Size != 0) + memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size); } inStreamSpec->Init(referenceBuf); @@ -2612,17 +2615,15 @@ STDMETHODIMP CHandler::AllowTail(Int32 allowTail) return S_OK; } -IMP_CreateArcIn +static const Byte k_Signature[] = { 'M', 'Z' }; -static CArcInfo g_ArcInfo = - { "PE", "exe dll sys", 0, 0xDD, - 2, { 'M', 'Z' }, +REGISTER_ARC_I( + "PE", "exe dll sys", 0, 0xDD, + k_Signature, 0, NArcInfoFlags::kPreArc, - CreateArc, NULL, IsArc_Pe }; - -REGISTER_ARC(Pe) - + IsArc_Pe) + } @@ -2836,7 +2837,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val const CSection &item = _items[index]; switch (propID) { - case kpidPath: prop = MultiByteToUnicodeString(NPe::GetName(item.Name)); break; + case kpidPath: + { + AString name; + NPe::GetName(item.Name, name); + prop = MultiByteToUnicodeString(name); + break; + } case kpidSize: case kpidPackSize: prop = (UInt64)item.PSize; break; case kpidVirtualSize: prop = (UInt64)item.VSize; break; @@ -2995,16 +3002,14 @@ STDMETHODIMP CHandler::AllowTail(Int32 allowTail) return S_OK; } -IMP_CreateArcIn +static const Byte k_Signature[] = { 'V', 'Z' }; -static CArcInfo g_ArcInfo = - { "TE", "te", 0, 0xCF, - 2, { 'V', 'Z' }, +REGISTER_ARC_I( + "TE", "te", 0, 0xCF, + k_Signature, 0, NArcInfoFlags::kPreArc, - CreateArc, NULL, IsArc_Te }; - -REGISTER_ARC(TE) + IsArc_Te) } } diff --git a/CPP/7zip/Archive/PpmdHandler.cpp b/CPP/7zip/Archive/PpmdHandler.cpp index 70e9ffac..86927f8f 100644 --- a/CPP/7zip/Archive/PpmdHandler.cpp +++ b/CPP/7zip/Archive/PpmdHandler.cpp @@ -28,10 +28,6 @@ using namespace NWindows; namespace NArchive { namespace NPpmd { -static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); } -static void SzBigFree(void *, void *address) { BigFree(address); } -static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; - static const UInt32 kBufSize = (1 << 20); struct CBuf @@ -90,11 +86,10 @@ HRESULT CItem::ReadHeader(ISequentialInStream *s, UInt32 &headerSize) nameLen &= 0x3FFF; if (nameLen > (1 << 9)) return S_FALSE; - char *name = Name.GetBuffer(nameLen + 1); + char *name = Name.GetBuf(nameLen); HRESULT res = ReadStream_FALSE(s, name, nameLen); - name[nameLen] = 0; + Name.ReleaseBuf_CalcLen(nameLen); headerSize = kHeaderSize + nameLen; - Name.ReleaseBuffer(); return res; } @@ -449,15 +444,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, return extractCallback->SetOperationResult(opRes); } -IMP_CreateArcIn +static const Byte k_Signature[] = { 0x8F, 0xAF, 0xAC, 0x84 }; -static CArcInfo g_ArcInfo = - { "Ppmd", "pmd", 0, 0xD, - 4, { 0x8F, 0xAF, 0xAC, 0x84 }, +REGISTER_ARC_I( + "Ppmd", "pmd", 0, 0xD, + k_Signature, 0, 0, - CreateArc }; - -REGISTER_ARC(Ppmd) + NULL) }} diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp index c26d72f9..516e5d7f 100644 --- a/CPP/7zip/Archive/Rar/RarHandler.cpp +++ b/CPP/7zip/Archive/Rar/RarHandler.cpp @@ -89,7 +89,7 @@ UInt32 CItem::GetWinAttrib() const return a; } -static const char *kHostOS[] = +static const char * const kHostOS[] = { "MS DOS" , "OS/2" @@ -354,7 +354,7 @@ static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime) } #define READ_TIME(_mask_, _ttt_) \ - { int size2 = ReadTime(p, size, _mask_, _ttt_); if (size2 < 0) return false; p += size2, size -= size2; } + { int size2 = ReadTime(p, size, _mask_, _ttt_); if (size2 < 0) return false; p += (unsigned)size2, size -= (unsigned)size2; } #define READ_TIME_2(_mask_, _def_, _ttt_) \ _def_ = ((_mask_ & 8) != 0); if (_def_) \ @@ -421,7 +421,7 @@ bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item) { item.IsAltStream = true; item.Name.Empty(); - item.UnicodeName = L".ACL"; + item.UnicodeName.SetFromAscii(".ACL"); } else if (item.Name == "STM" && size != 0 && (size & 1) == 0) { @@ -517,7 +517,7 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass RINOK(getTextPassword->CryptoGetTextPassword(&password)) unsigned len = 0; if (password) - len = MyStringLen((BSTR)password); + len = MyStringLen(password); CByteBuffer buffer(len * 2); for (unsigned i = 0; i < len; i++) { @@ -645,6 +645,8 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass error = k_ErrorType_Corrupted; ArcInfo.VolNumber = (UInt32)Get16(m_FileHeaderData + offset); } + + ArcInfo.EndOfArchive_was_Read = true; } m_Position += processed; FinishCryptoBlock(); @@ -668,7 +670,7 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass bool okItem = ReadHeaderReal(m_FileHeaderData + 7, m_BlockHeader.HeadSize - 7, item); if (okItem) { - if (!CheckHeaderCrc(m_FileHeaderData, m_BlockHeader.HeadSize - item.CommentSize)) + if (!CheckHeaderCrc(m_FileHeaderData, (unsigned)m_BlockHeader.HeadSize - item.CommentSize)) { error = k_ErrorType_Corrupted; // ThrowExceptionWithCode(CInArchiveException::kFileHeaderCRCError); return S_OK; @@ -802,8 +804,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) // FLAGS_TO_PROP(k_Flags, _arcInfo.Flags, prop); if (_arcInfo.Is_DataCRC_Defined()) { - if (!s.IsEmpty()) - s += ' '; + s.Add_Space_if_NotEmpty(); s += "VolCRC"; } prop = s; @@ -1008,27 +1009,28 @@ public: { _first = true; _newStyle = newStyle; - int dotPos = name.ReverseFind('.'); + int dotPos = name.ReverseFind_Dot(); UString basePart = name; + if (dotPos >= 0) { UString ext = name.Ptr(dotPos + 1); - if (ext.IsEqualToNoCase(L"rar")) + if (ext.IsEqualTo_Ascii_NoCase("rar")) { _afterPart = name.Ptr(dotPos); basePart = name.Left(dotPos); } - else if (ext.IsEqualToNoCase(L"exe")) + else if (ext.IsEqualTo_Ascii_NoCase("exe")) { - _afterPart = L".rar"; + _afterPart.SetFromAscii(".rar"); basePart = name.Left(dotPos); } else if (!_newStyle) { - if (ext.IsEqualToNoCase(L"000") || - ext.IsEqualToNoCase(L"001") || - ext.IsEqualToNoCase(L"r00") || - ext.IsEqualToNoCase(L"r01")) + if (ext.IsEqualTo_Ascii_NoCase("000") || + ext.IsEqualTo_Ascii_NoCase("001") || + ext.IsEqualTo_Ascii_NoCase("r00") || + ext.IsEqualTo_Ascii_NoCase("r01")) { _afterPart.Empty(); _first = false; @@ -1042,18 +1044,21 @@ public: if (!_newStyle) { _afterPart.Empty(); - _unchangedPart = basePart + UString(L"."); - _changedPart = L"r00"; + _unchangedPart = basePart; + _unchangedPart += L'.'; + _changedPart.SetFromAscii("r00"); return true; } if (basePart.IsEmpty()) return false; unsigned i = basePart.Len(); + do if (!IsDigit(basePart[i - 1])) break; while (--i); + _unchangedPart = basePart.Left(i); _changedPart = basePart.Ptr(i); return true; @@ -1071,34 +1076,59 @@ public: UString GetNextName() { - UString newName; if (_newStyle || !_first) { - for (int i = (int)_changedPart.Len() - 1; i >= 0; i--) + unsigned i = _changedPart.Len(); + for (;;) { - wchar_t c = _changedPart[i]; + wchar_t c = _changedPart[--i]; if (c == L'9') { c = L'0'; - newName.InsertAtFront(c); + _changedPart.ReplaceOneCharAtPos(i, c); if (i == 0) - newName.InsertAtFront(L'1'); + { + _changedPart.InsertAtFront(L'1'); + break; + } continue; } c++; - newName = UString(c) + newName; - i--; - for (; i >= 0; i--) - newName.InsertAtFront(_changedPart[i]); + _changedPart.ReplaceOneCharAtPos(i, c); break; } - _changedPart = newName; } + _first = false; return _unchangedPart + _changedPart + _afterPart; } }; +static HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize) +{ + areThereNonZeros = false; + numZeros = 0; + const size_t kBufSize = 1 << 9; + Byte buf[kBufSize]; + for (;;) + { + UInt32 size = 0; + HRESULT(stream->Read(buf, kBufSize, &size)); + if (size == 0) + return S_OK; + for (UInt32 i = 0; i < size; i++) + if (buf[i] != 0) + { + areThereNonZeros = true; + numZeros += i; + return S_OK; + } + numZeros += size; + if (numZeros > maxSize) + return S_OK; + } +} + HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) @@ -1174,6 +1204,7 @@ HRESULT CHandler::Open2(IInStream *stream, RINOK(archive.Open(inStream, maxCheckStartPosition)); _isArc = true; CItem item; + for (;;) { if (archive.m_Position > endPos) @@ -1181,11 +1212,13 @@ HRESULT CHandler::Open2(IInStream *stream, _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; break; } + 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) @@ -1198,16 +1231,33 @@ HRESULT CHandler::Open2(IInStream *stream, // AddErrorMessage(errorMessageLoc); } RINOK(result); + if (!filled) { if (error == k_ErrorType_DecryptionError && _items.IsEmpty()) return S_FALSE; + + if (archive.ArcInfo.ExtraZeroTail_is_Possible()) + { + /* if there is recovery record for multivolume archive, + RAR adds 18 bytes (ZERO bytes) at the end for alignment. + We must skip these bytes to prevent phySize warning. */ + RINOK(inStream->Seek(archive.ArcInfo.EndPos, STREAM_SEEK_SET, NULL)); + bool areThereNonZeros; + UInt64 numZeros; + const UInt64 maxSize = 1 << 12; + RINOK(ReadZeroTail(inStream, areThereNonZeros, numZeros, maxSize)); + if (!areThereNonZeros && numZeros != 0 && numZeros <= maxSize) + archive.ArcInfo.EndPos += numZeros; + } break; } + if (item.IgnoreItem()) continue; bool needAdd = true; + if (item.IsSplitBefore()) { if (!_refItems.IsEmpty()) @@ -1217,6 +1267,7 @@ HRESULT CHandler::Open2(IInStream *stream, needAdd = false; } } + if (needAdd) { CRefItem refItem; @@ -1225,7 +1276,9 @@ HRESULT CHandler::Open2(IInStream *stream, refItem.VolumeIndex = _arcs.Size(); _refItems.Add(refItem); } + _items.Add(item); + if (openCallback && _items.Size() % 100 == 0) { UInt64 numFiles = _items.Size(); @@ -1256,7 +1309,7 @@ HRESULT CHandler::Open2(IInStream *stream, /* int baseFileIndex = -1; - for (int i = 0; i < _refItems.Size(); i++) + for (unsigned i = 0; i < _refItems.Size(); i++) { CItem &item = _items[_refItems[i].ItemIndex]; if (item.IsAltStream) @@ -1430,7 +1483,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (numItems == 0) return S_OK; unsigned lastIndex = 0; - CRecordVector<int> importantIndexes; + CRecordVector<unsigned> importantIndexes; CRecordVector<bool> extractStatuses; for (UInt32 t = 0; t < numItems; t++) @@ -1470,7 +1523,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; - CFilterCoder *filterStreamSpec = new CFilterCoder; + CFilterCoder *filterStreamSpec = new CFilterCoder(false); CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec; NCrypto::NRar20::CDecoder *rar20CryptoDecoderSpec = NULL; @@ -1576,22 +1629,25 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, // unpackedPos += 0; CMyComPtr<ISequentialInStream> inStream; + if (item.IsEncrypted()) { CMyComPtr<ICryptoSetPassword> cryptoSetPassword; + if (item.UnPackVersion >= 29) { if (!rar29CryptoDecoder) { rar29CryptoDecoderSpec = new NCrypto::NRar29::CDecoder; rar29CryptoDecoder = rar29CryptoDecoderSpec; - // RINOK(rar29CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar29Decoder)); } rar29CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36); + /* CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties; RINOK(rar29CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2, &cryptoProperties)); - RINOK(cryptoProperties->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0)); + */ + RINOK(rar29CryptoDecoderSpec->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0)); filterStreamSpec->Filter = rar29CryptoDecoder; } else if (item.UnPackVersion >= 20) @@ -1600,7 +1656,6 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { rar20CryptoDecoderSpec = new NCrypto::NRar20::CDecoder; rar20CryptoDecoder = rar20CryptoDecoderSpec; - // RINOK(rar20CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar20Decoder)); } filterStreamSpec->Filter = rar20CryptoDecoder; } @@ -1610,8 +1665,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); continue; } - RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, - &cryptoSetPassword)); + + RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)); if (!getTextPassword) extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); @@ -1624,7 +1679,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UString unicodePassword; unsigned len = 0; if (password) - len = MyStringLen((BSTR)password); + len = MyStringLen(password); CByteBuffer buffer(len * 2); for (unsigned i = 0; i < len; i++) { @@ -1646,14 +1701,18 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { RINOK(cryptoSetPassword->CryptoSetPassword(0, 0)); } + filterStreamSpec->SetInStream(folderInStream); + filterStreamSpec->SetOutStreamSize(NULL); inStream = filterStream; } else { inStream = folderInStream; } + CMyComPtr<ICompressCoder> commonCoder; + switch(item.Method) { case '0': @@ -1679,14 +1738,14 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, mi.Coder.Release(); if (item.UnPackVersion <= 40) { - UInt32 methodID = 0x040300; + UInt32 methodID = 0x40300; if (item.UnPackVersion < 20) methodID += 1; else if (item.UnPackVersion < 29) methodID += 2; else methodID += 3; - RINOK(CreateCoder(EXTERNAL_CODECS_VARS methodID, mi.Coder, false)); + RINOK(CreateCoder(EXTERNAL_CODECS_VARS methodID, false, mi.Coder)); } if (mi.Coder == 0) @@ -1722,7 +1781,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); continue; } + HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &item.Size, progress); + if (item.IsEncrypted()) filterStreamSpec->ReleaseInStream(); if (result == S_FALSE) @@ -1771,15 +1832,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, IMPL_ISetCompressCodecsInfo -IMP_CreateArcIn - -static CArcInfo g_ArcInfo = - { "Rar", "rar r00", 0, 3, - NHeader::kMarkerSize, SIGNATURE, +REGISTER_ARC_I( + "Rar", "rar r00", 0, 3, + kMarker, 0, NArcInfoFlags::kFindSignature, - CreateArc }; - -REGISTER_ARC(Rar) + NULL) }} diff --git a/CPP/7zip/Archive/Rar/RarHandler.h b/CPP/7zip/Archive/Rar/RarHandler.h index 81191be9..dd3daa5d 100644 --- a/CPP/7zip/Archive/Rar/RarHandler.h +++ b/CPP/7zip/Archive/Rar/RarHandler.h @@ -1,4 +1,4 @@ -// Rar/Handler.h +// RarHandler.h #ifndef __RAR_HANDLER_H #define __RAR_HANDLER_H @@ -24,18 +24,25 @@ struct CInArcInfo UInt32 EndFlags; UInt32 VolNumber; UInt32 DataCRC; + bool EndOfArchive_was_Read; - CInArcInfo(): EndFlags(0) {} + CInArcInfo(): EndFlags(0), EndOfArchive_was_Read(false) {} 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 ExtraZeroTail_is_Possible() const { return IsVolume() && IsRecovery() && EndOfArchive_was_Read; } + bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; } + bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; } + // kLock + bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; } bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 0; } - bool IsFirstVolume() const { return (Flags & NHeader::NArchive::kFirstVolume) != 0; } + // kAuthenticity + bool IsRecovery() const { return (Flags & NHeader::NArchive::kRecovery) != 0; } bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; } + bool IsFirstVolume() const { return (Flags & NHeader::NArchive::kFirstVolume) != 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; } diff --git a/CPP/7zip/Archive/Rar/RarItem.h b/CPP/7zip/Archive/Rar/RarItem.h index 56d25f2c..13daa1cb 100644 --- a/CPP/7zip/Archive/Rar/RarItem.h +++ b/CPP/7zip/Archive/Rar/RarItem.h @@ -84,10 +84,10 @@ struct CItem CItem() { Clear(); } - UInt64 GetFullSize() const { return MainPartSize + CommentSize + AlignSize + PackSize; }; - // DWORD GetHeaderWithCommentSize() const { return MainPartSize + CommentSize; }; - UInt64 GetCommentPosition() const { return Position + MainPartSize; }; - UInt64 GetDataPosition() const { return GetCommentPosition() + CommentSize + AlignSize; }; + UInt64 GetFullSize() const { return MainPartSize + CommentSize + AlignSize + PackSize; } + // DWORD GetHeaderWithCommentSize() const { return MainPartSize + CommentSize; } + UInt64 GetCommentPosition() const { return Position + MainPartSize; } + UInt64 GetDataPosition() const { return GetCommentPosition() + CommentSize + AlignSize; } }; }} diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp index 220bc650..268e0837 100644 --- a/CPP/7zip/Archive/RpmHandler.cpp +++ b/CPP/7zip/Archive/RpmHandler.cpp @@ -77,7 +77,7 @@ enum k_EntryType_I18NSTRING }; -static const char *k_CPUs[] = +static const char * const k_CPUs[] = { "noarch" , "i386" @@ -101,7 +101,7 @@ static const char *k_CPUs[] = , "aarch64" // 19 }; -static const char *k_OS[] = +static const char * const k_OS[] = { "0" , "Linux" @@ -299,12 +299,7 @@ AString CHandler::GetBaseName() const } } else - { - char *p = s.GetBuffer(kNameSize); - memcpy(p, _lead.Name, kNameSize); - p[kNameSize] = 0; - s.ReleaseBuffer(); - } + s.SetFrom_CalcLen(_lead.Name, kNameSize); s += '.'; if (_lead.Type == kRpmType_Src) @@ -553,7 +548,7 @@ HRESULT CHandler::ReadHeader(ISequentialInStream *stream, bool isMainHeader) for (UInt32 t = 0; t < entry.Count; t++) { if (t != 0) - _metadata += ' '; + _metadata.Add_Space(); char temp[16]; ConvertUInt32ToString(Get32(p + t * 4), temp); _metadata += temp; @@ -592,7 +587,7 @@ HRESULT CHandler::ReadHeader(ISequentialInStream *stream, bool isMainHeader) for (UInt32 t = 0; t < entry.Count; t++) { if (t != 0) - _metadata += ' '; + _metadata.Add_Space(); char temp[16]; ConvertUInt32ToString(Get16(p + t * 2), temp); _metadata += temp; @@ -777,15 +772,13 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea COM_TRY_END } -IMP_CreateArcIn +static const Byte k_Signature[] = { 0xED, 0xAB, 0xEE, 0xDB}; -static CArcInfo g_ArcInfo = - { "Rpm", "rpm", 0, 0xEB, - 4, { 0xED, 0xAB, 0xEE, 0xDB}, +REGISTER_ARC_I( + "Rpm", "rpm", 0, 0xEB, + k_Signature, 0, 0, - CreateArc }; - -REGISTER_ARC(Rpm) + NULL) }} diff --git a/CPP/7zip/Archive/SplitHandler.cpp b/CPP/7zip/Archive/SplitHandler.cpp index 19dc1b47..23187064 100644 --- a/CPP/7zip/Archive/SplitHandler.cpp +++ b/CPP/7zip/Archive/SplitHandler.cpp @@ -71,68 +71,53 @@ struct CSeqName UString _changedPart; bool _splitStyle; - UString GetNextName() + bool GetNextName(UString &s) { - UString newName; - if (_splitStyle) { - int i; - int numLetters = _changedPart.Len(); - for (i = numLetters - 1; i >= 0; i--) + unsigned i = _changedPart.Len(); + for (;;) { - wchar_t c = _changedPart[i]; - if (c == 'z') + wchar_t c = _changedPart[--i]; + + if (_splitStyle) { - newName.InsertAtFront('a'); - continue; + if (c == 'z') + { + _changedPart.ReplaceOneCharAtPos(i, L'a'); + if (i == 0) + return false; + continue; + } + else if (c == 'Z') + { + _changedPart.ReplaceOneCharAtPos(i, L'A'); + if (i == 0) + return false; + continue; + } } - else if (c == 'Z') + else { - newName.InsertAtFront('A'); - continue; - } - c++; - if ((c == 'z' || c == 'Z') && i == 0) - { - _unchangedPart += c; - wchar_t newChar = (c == 'z') ? L'a' : L'A'; - newName.Empty(); - numLetters++; - for (int k = 0; k < numLetters; k++) - newName += newChar; - break; - } - newName.InsertAtFront(c); - i--; - for (; i >= 0; i--) - newName.InsertAtFront(_changedPart[i]); - break; - } - } - else - { - int i; - int numLetters = _changedPart.Len(); - for (i = numLetters - 1; i >= 0; i--) - { - wchar_t c = _changedPart[i]; - if (c == '9') - { - newName.InsertAtFront('0'); - if (i == 0) - newName.InsertAtFront('1'); - continue; + if (c == '9') + { + _changedPart.ReplaceOneCharAtPos(i, L'0'); + if (i == 0) + { + _changedPart.InsertAtFront(L'1'); + break; + } + continue; + } } + c++; - newName.InsertAtFront(c); - i--; - for (; i >= 0; i--) - newName.InsertAtFront(_changedPart[i]); + _changedPart.ReplaceOneCharAtPos(i, c); break; } } - _changedPart = newName; - return _unchangedPart + _changedPart; + + s = _unchangedPart + _changedPart; + return true; } }; @@ -156,7 +141,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) name = prop.bstrVal; } - int dotPos = name.ReverseFind('.'); + int dotPos = name.ReverseFind_Dot(); const UString prefix = name.Left(dotPos + 1); const UString ext = name.Ptr(dotPos + 1); UString ext2 = ext; @@ -196,7 +181,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) seqName._splitStyle = splitStyle; if (prefix.Len() < 1) - _subName = L"file"; + _subName.SetFromAscii("file"); else _subName.SetFrom(prefix, prefix.Len() - 1); @@ -220,7 +205,9 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) for (;;) { - const UString fullName = seqName.GetNextName(); + UString fullName; + if (!seqName.GetNextName(fullName)) + break; CMyComPtr<IInStream> nextStream; HRESULT result = volumeCallback->GetStream(fullName, &nextStream); if (result == S_FALSE) @@ -355,15 +342,10 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -IMP_CreateArcIn - -static CArcInfo g_ArcInfo = - { "Split", "001", 0, 0xEA, - 0, { 0 }, +REGISTER_ARC_I_NO_SIG( + "Split", "001", 0, 0xEA, 0, 0, - CreateArc }; - -REGISTER_ARC(Split) + NULL) }} diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp index 1f70bb8e..c65067af 100644 --- a/CPP/7zip/Archive/SquashfsHandler.cpp +++ b/CPP/7zip/Archive/SquashfsHandler.cpp @@ -28,10 +28,6 @@ namespace NArchive { namespace NSquashfs { -static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } -static void SzFree(void *p, void *address) { p = p; MyFree(address); } -static ISzAlloc g_Alloc = { SzAlloc, SzFree }; - static const UInt32 kNumFilesMax = (1 << 28); static const unsigned kNumDirLevelsMax = (1 << 10); @@ -68,7 +64,7 @@ static const UInt32 kSignature32_LZ = 0x71736873; #define kMethod_LZO 3 #define kMethod_XZ 4 -static const char *k_Methods[] = +static const char * const k_Methods[] = { "Unknown" , "ZLIB" @@ -1652,13 +1648,12 @@ AString CHandler::GetPath(int index) const len--; AString path; - char *dest = path.GetBuffer(len) + len; + char *dest = path.GetBuf_SetEnd(len) + len; index = indexMem; for (;;) { const CItem &item = _items[index]; index = item.Parent; - const Byte *p = _dirs.Data + item.Ptr; unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1; p += _h.GetFileNameOffset(); @@ -1670,7 +1665,6 @@ AString CHandler::GetPath(int index) const break; *(--dest) = CHAR_PATH_SEPARATOR; } - path.ReleaseBuffer(len); return path; } @@ -1846,7 +1840,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) AString res = "SquashFS"; if (_h.SeveralMethods) res += "-LZMA"; - res += ' '; + res.Add_Space(); char s[16]; ConvertUInt32ToString(_h.Major, s); res += s; @@ -2049,7 +2043,8 @@ HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) } if (offsetInBlock + blockSize > _cachedUnpackBlockSize) return S_FALSE; - memcpy(dest, _cachedBlock + offsetInBlock, blockSize); + if (blockSize != 0) + memcpy(dest, _cachedBlock + offsetInBlock, blockSize); return S_OK; } @@ -2208,20 +2203,16 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -IMP_CreateArcIn - -static CArcInfo g_ArcInfo = - { "SquashFS", "squashfs", 0, 0xD2, - 3 * (1 + 4), - { +static const Byte k_Signature[] = { 4, 'h', 's', 'q', 's', 4, 's', 'q', 's', 'h', - 4, 's', 'h', 's', 'q', - }, + 4, 's', 'h', 's', 'q' }; + +REGISTER_ARC_I( + "SquashFS", "squashfs", 0, 0xD2, + k_Signature, 0, NArcInfoFlags::kMultiSignature, - CreateArc }; - -REGISTER_ARC(Cramfs) + NULL) }} diff --git a/CPP/7zip/Archive/SwfHandler.cpp b/CPP/7zip/Archive/SwfHandler.cpp index 85c61fe2..77d2ad7d 100644 --- a/CPP/7zip/Archive/SwfHandler.cpp +++ b/CPP/7zip/Archive/SwfHandler.cpp @@ -170,7 +170,7 @@ public: INTERFACE_IInArchive(;) INTERFACE_IOutArchive(;) STDMETHOD(OpenSeq)(ISequentialInStream *stream); - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); }; static const Byte kProps[] = @@ -218,7 +218,7 @@ static void DicSizeToString(char *s, UInt32 val) else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } } ::ConvertUInt32ToString(val, s); - int pos = MyStringLen(s); + unsigned pos = MyStringLen(s); s[pos++] = c; s[pos] = 0; } @@ -558,11 +558,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return NCompress::CopyStream(_seqStream, outStream, NULL); } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { _lzmaMode = false; RINOK(_props.SetProperties(names, values, numProps)); - UString m = _props.MethodName; + AString m = _props.MethodName; m.MakeLower_Ascii(); if (m.IsEqualTo("lzma")) { @@ -576,21 +576,16 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v return S_OK; } -IMP_CreateArcIn -IMP_CreateArcOut - -static CArcInfo g_ArcInfo = - { "SWFc", "swf", "~.swf", 0xD8, - 2 + 3 + 3, - { +static const Byte k_Signature[] = { 3, 'C', 'W', 'S', - 3, 'Z', 'W', 'S', - }, + 3, 'Z', 'W', 'S' }; + +REGISTER_ARC_IO( + "SWFc", "swf", "~.swf", 0xD8, + k_Signature, 0, NArcInfoFlags::kMultiSignature, - REF_CreateArc_Pair, IsArc_Swfc }; - -REGISTER_ARC(Swfc) + IsArc_Swfc) } @@ -978,15 +973,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -IMP_CreateArcIn +static const Byte k_Signature[] = { 'F', 'W', 'S' }; -static CArcInfo g_ArcInfo = - { "SWF", "swf", 0, 0xD7, - 3, { 'F', 'W', 'S' }, +REGISTER_ARC_I( + "SWF", "swf", 0, 0xD7, + k_Signature, 0, NArcInfoFlags::kKeepName, - CreateArc, NULL, NSwfc::IsArc_Swf }; - -REGISTER_ARC(Swf) + NSwfc::IsArc_Swf) }} diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp index 5b587529..d1eec144 100644 --- a/CPP/7zip/Archive/Tar/TarHandler.cpp +++ b/CPP/7zip/Archive/Tar/TarHandler.cpp @@ -143,10 +143,10 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) if (!_forceCodePage) { - if (utf8_OK) utf8_OK = CheckUTF8(item.Name); + if (utf8_OK) utf8_OK = CheckUTF8(item.Name, item.NameCouldBeReduced); + if (utf8_OK) utf8_OK = CheckUTF8(item.LinkName, item.LinkNameCouldBeReduced); 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)); @@ -298,19 +298,12 @@ void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant { UString dest; if (_curCodePage == CP_UTF8) - { - if (!ConvertUTF8ToUnicode(s, dest)) - { - prop = "[ERROR-NAME]"; - return; - } - } + ConvertUTF8ToUnicode(s, dest); else - dest = MultiByteToUnicodeString(s, _curCodePage); + MultiByteToUnicodeString2(dest, s, _curCodePage); if (toOs) - prop = NItemName::GetOSName2(dest); - else - prop = dest; + NItemName::ConvertToOSName2(dest); + prop = dest; } STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) @@ -632,10 +625,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) if (item.IsSymLink()) { - CBufInStream *streamSpec = new CBufInStream; - CMyComPtr<IInStream> streamTemp = streamSpec; - streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this); - *stream = streamTemp.Detach(); + Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream); return S_OK; } @@ -651,7 +641,7 @@ void CHandler::Init() _curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP; } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { Init(); diff --git a/CPP/7zip/Archive/Tar/TarHandler.h b/CPP/7zip/Archive/Tar/TarHandler.h index 23854767..42d57d45 100644 --- a/CPP/7zip/Archive/Tar/TarHandler.h +++ b/CPP/7zip/Archive/Tar/TarHandler.h @@ -67,7 +67,7 @@ public: INTERFACE_IOutArchive(;) STDMETHOD(OpenSeq)(ISequentialInStream *stream); STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); + STDMETHOD(SetProperties)(const wchar_t * const *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 b909e96c..ae005ac5 100644 --- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp +++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp @@ -36,8 +36,8 @@ HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID pro s = NItemName::MakeLegalName(s); if (codePage == CP_UTF8) { - if (!ConvertUnicodeToUTF8(s, res)) - return E_INVALIDARG; + ConvertUnicodeToUTF8(s, res); + // if (!ConvertUnicodeToUTF8(s, res)) // return E_INVALIDARG; } else UnicodeStringToMultiByte2(res, s, codePage); diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp index 1584a520..80200c3b 100644 --- a/CPP/7zip/Archive/Tar/TarIn.cpp +++ b/CPP/7zip/Archive/Tar/TarIn.cpp @@ -180,6 +180,9 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE error = k_ErrorType_Corrupted; ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize; + item.NameCouldBeReduced = + (item.Name.Len() == NFileHeader::kNameSize || + item.Name.Len() == NFileHeader::kNameSize - 1); RIF(OctalToNumber32(p, 8, item.Mode)); p += 8; @@ -198,6 +201,9 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE item.LinkFlag = *p++; ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize; + item.LinkNameCouldBeReduced = + (item.LinkName.Len() == NFileHeader::kNameSize || + item.LinkName.Len() == NFileHeader::kNameSize - 1); memcpy(item.Magic, p, 8); p += 8; @@ -207,12 +213,17 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE 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); + if (p[0] != 0) + { + AString prefix; + ReadString(p, NFileHeader::kPrefixSize, prefix); + if (!prefix.IsEmpty() + && item.IsUstarMagic() + && (item.LinkFlag != 'L' /* || prefix != "00000000000" */ )) + item.Name = prefix + '/' + item.Name; + } + p += NFileHeader::kPrefixSize; - if (!prefix.IsEmpty() && item.IsUstarMagic() && - (item.LinkFlag != 'L' /* || prefix != "00000000000" */ )) - item.Name = prefix + AString('/') + item.Name; if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink) { @@ -353,12 +364,11 @@ HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, EErro if (item.PackSize > (1 << 14)) return S_OK; unsigned packSize = (unsigned)item.GetPackSizeAligned(); - char *buf = name->GetBuffer(packSize); + char *buf = name->GetBuf(packSize); size_t processedSize = packSize; HRESULT res = ReadStream(stream, buf, &processedSize); item.HeaderSize += (unsigned)processedSize; - buf[(size_t)item.PackSize] = 0; - name->ReleaseBuffer(); + name->ReleaseBuf_CalcLen((unsigned)item.PackSize); RINOK(res); if (processedSize != packSize) { @@ -392,8 +402,18 @@ HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, EErro return S_OK; } - if (flagL) item.Name = nameL; - if (flagK) item.LinkName = nameK; + if (flagL) + { + item.Name = nameL; + item.NameCouldBeReduced = false; + } + + if (flagK) + { + item.LinkName = nameK; + item.LinkNameCouldBeReduced = false; + } + error = k_ErrorType_OK; return S_OK; } diff --git a/CPP/7zip/Archive/Tar/TarItem.h b/CPP/7zip/Archive/Tar/TarItem.h index 805a2e7c..5245aaa4 100644 --- a/CPP/7zip/Archive/Tar/TarItem.h +++ b/CPP/7zip/Archive/Tar/TarItem.h @@ -86,6 +86,8 @@ struct CItemEx: public CItem { UInt64 HeaderPos; unsigned HeaderSize; + bool NameCouldBeReduced; + bool LinkNameCouldBeReduced; UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; } UInt64 GetFullSize() const { return HeaderSize + PackSize; } diff --git a/CPP/7zip/Archive/Tar/TarRegister.cpp b/CPP/7zip/Archive/Tar/TarRegister.cpp index 9e0f6f21..f7b256df 100644 --- a/CPP/7zip/Archive/Tar/TarRegister.cpp +++ b/CPP/7zip/Archive/Tar/TarRegister.cpp @@ -9,18 +9,15 @@ namespace NArchive { namespace NTar { -IMP_CreateArcIn -IMP_CreateArcOut +static const Byte k_Signature[] = { 'u', 's', 't', 'a', 'r' }; -static CArcInfo g_ArcInfo = - { "tar", "tar", 0, 0xEE, - 5, { 'u', 's', 't', 'a', 'r' }, +REGISTER_ARC_IO( + "tar", "tar", 0, 0xEE, + k_Signature, NFileHeader::kUstarMagic_Offset, NArcInfoFlags::kStartOpen | NArcInfoFlags::kSymLinks | NArcInfoFlags::kHardLinks, - REF_CreateArc_Pair, IsArc_Tar }; - -REGISTER_ARC(Tar) - + IsArc_Tar) + }} diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp index fdbce395..3adbdee9 100644 --- a/CPP/7zip/Archive/Tar/TarUpdate.cpp +++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp @@ -31,6 +31,9 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, CMyComPtr<IOutStream> outSeekStream; outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream); + CMyComPtr<IArchiveUpdateCallbackFile> opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + UInt64 complexity = 0; unsigned i; @@ -224,6 +227,13 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, } streamSpec->Init(size); + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArchive, + NUpdateNotifyOp::kReplicate)) + } + RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); if (copyCoderSpec->TotalSize != size) return E_FAIL; diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp index 6aa53ea9..d35db9fb 100644 --- a/CPP/7zip/Archive/Udf/UdfHandler.cpp +++ b/CPP/7zip/Archive/Udf/UdfHandler.cpp @@ -26,7 +26,7 @@ static void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop if (!NWindows::NTime::GetSecondsSince1601(t.GetYear(), d[4], d[5], d[6], d[7], d[8], numSecs)) return; if (t.IsLocal()) - numSecs -= t.GetMinutesOffset() * 60; + numSecs -= (Int64)((Int32)t.GetMinutesOffset() * 60); FILETIME ft; UInt64 v = (((numSecs * 100 + d[9]) * 100 + d[10]) * 100 + d[11]) * 10; ft.dwLowDateTime = (UInt32)v; @@ -227,13 +227,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) if (item.IsInline) { - CBufInStream *inStreamSpec = new CBufInStream; - CMyComPtr<ISequentialInStream> inStream = inStreamSpec; - CReferenceBuf *referenceBuf = new CReferenceBuf; - CMyComPtr<IUnknown> ref = referenceBuf; - referenceBuf->Buf = item.InlineData; - inStreamSpec->Init(referenceBuf); - *stream = inStream.Detach(); + Create_BufInStream_WithNewBuffer(item.InlineData, stream); return S_OK; } @@ -366,18 +360,16 @@ 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' }, +// 5, { 0, 'N', 'S', 'R', '0' }, +static const Byte k_Signature[] = { 1, 'C', 'D', '0', '0', '1' }; + +REGISTER_ARC_I( + "Udf", "udf iso img", 0, 0xE0, + k_Signature, kIsoStartPos, NArcInfoFlags::kStartOpen, - CreateArc, NULL, IsArc_Udf }; - -REGISTER_ARC(Udf) + IsArc_Udf) }} diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp index 3053a0c1..62df64dc 100644 --- a/CPP/7zip/Archive/Udf/UdfIn.cpp +++ b/CPP/7zip/Archive/Udf/UdfIn.cpp @@ -82,13 +82,13 @@ void CDString::Parse(const Byte *p, unsigned size) static UString ParseDString(const Byte *data, unsigned size) { UString res; - wchar_t *p; if (size > 0) { + wchar_t *p; Byte type = data[0]; if (type == 8) { - p = res.GetBuffer(size); + p = res.GetBuf(size); for (unsigned i = 1; i < size; i++) { wchar_t c = data[i]; @@ -99,7 +99,7 @@ static UString ParseDString(const Byte *data, unsigned size) } else if (type == 16) { - p = res.GetBuffer(size / 2); + p = res.GetBuf(size / 2); for (unsigned i = 1; i + 2 <= size; i += 2) { wchar_t c = GetBe16(data + i); @@ -110,8 +110,8 @@ static UString ParseDString(const Byte *data, unsigned size) } else return L"[unknow]"; - *p++ = 0; - res.ReleaseBuffer(); + *p = 0; + res.ReleaseBuf_SetLen((unsigned)(p - (const wchar_t *)res)); } return res; } @@ -432,6 +432,8 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la CTag tag; const Byte *p = buf; RINOK(tag.Parse(p, size)); + if (size < 176) + return S_FALSE; if (tag.Id != DESC_TYPE_File) return S_FALSE; @@ -449,7 +451,7 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la if ((extendedAttrLen & 3) != 0) return S_FALSE; - int pos = 176; + size_t pos = 176; if (extendedAttrLen > size - pos) return S_FALSE; /* @@ -595,7 +597,7 @@ API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size) if (SecLogSize < 8) return res; UInt32 offset = (UInt32)256 << SecLogSize; - size_t bufSize = 1 << SecLogSize; + size_t bufSize = (UInt32)1 << SecLogSize; if (offset + bufSize > size) res = k_IsArc_Res_NEED_MORE; else @@ -652,7 +654,7 @@ HRESULT CInArchive::Open2() if (offset >= fileSize) continue; RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); - size_t bufSize = 1 << SecLogSize; + size_t bufSize = (UInt32)1 << SecLogSize; size_t readSize = bufSize; RINOK(ReadStream(_stream, buf, &readSize)); if (readSize == bufSize) @@ -677,7 +679,7 @@ HRESULT CInArchive::Open2() for (UInt32 location = 0; ; location++) { - size_t bufSize = 1 << SecLogSize; + size_t bufSize = (UInt32)1 << SecLogSize; size_t pos = 0; if (((UInt64)(location + 1) << SecLogSize) > extentVDS.Len) return S_FALSE; @@ -950,7 +952,7 @@ HRESULT CInArchive::Open2() if (PhySize < fileSize) { RINOK(_stream->Seek(PhySize, STREAM_SEEK_SET, NULL)); - size_t bufSize = 1 << SecLogSize; + size_t bufSize = (UInt32)1 << SecLogSize; size_t readSize = bufSize; RINOK(ReadStream(_stream, buf, &readSize)); if (readSize == bufSize) @@ -1018,8 +1020,8 @@ UString CInArchive::GetComment() const UString res; FOR_VECTOR (i, LogVols) { - if (i > 0) - res += L" "; + if (i != 0) + res.Add_Space(); res += LogVols[i].GetName(); } return res; diff --git a/CPP/7zip/Archive/Udf/UdfRegister.cpp b/CPP/7zip/Archive/Udf/UdfRegister.cpp deleted file mode 100644 index ed32f12e..00000000 --- a/CPP/7zip/Archive/Udf/UdfRegister.cpp +++ /dev/null @@ -1,7 +0,0 @@ -// UdfRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "UdfHandler.h" diff --git a/CPP/7zip/Archive/UefiHandler.cpp b/CPP/7zip/Archive/UefiHandler.cpp index a6760b36..3de6351a 100644 --- a/CPP/7zip/Archive/UefiHandler.cpp +++ b/CPP/7zip/Archive/UefiHandler.cpp @@ -26,6 +26,7 @@ #include "../Common/StreamUtils.h" #include "../Compress/CopyCoder.h" +#include "../Compress/LzhDecoder.h" #ifdef SHOW_DEBUG_INFO #define PRF(x) x @@ -41,22 +42,18 @@ namespace NArchive { namespace NUefi { -static const UInt32 kBufTotalSizeMax = (1 << 29); -static const UInt32 kNumFilesMax = (1 << 18); -static const int kLevelMax = 64; +static const size_t kBufTotalSizeMax = (1 << 29); +static const unsigned kNumFilesMax = (1 << 18); +static const unsigned kLevelMax = 64; -static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } -static void SzFree(void *p, void *address) { p = p; MyFree(address); } -static ISzAlloc g_Alloc = { SzAlloc, SzFree }; +static const unsigned kFvHeaderSize = 0x38; -static const UInt32 kFvHeaderSize = 0x38; -static const UInt32 kGuidSize = 16; -static const UInt32 kCapsuleSigSize = kGuidSize; +static const unsigned kGuidSize = 16; #define CAPSULE_SIGNATURE \ { 0xBD,0x86,0x66,0x3B,0x76,0x0D,0x30,0x40,0xB7,0x0E,0xB5,0x51,0x9E,0x2F,0xC5,0xA0 } -static const Byte kCapsuleSig[kCapsuleSigSize] = CAPSULE_SIGNATURE; +static const Byte kCapsuleSig[kGuidSize] = CAPSULE_SIGNATURE; -static const UInt32 kFfsGuidOffset = 16; +static const unsigned kFfsGuidOffset = 16; #define FFS_SIGNATURE \ { 0xD9,0x54,0x93,0x7A,0x68,0x04,0x4A,0x44,0x81,0xCE,0x0B,0xF6,0x17,0xD8,0x90,0xDF } static const Byte k_FFS_Guid[kGuidSize] = FFS_SIGNATURE; @@ -84,7 +81,7 @@ static const Byte kGuids[][kGuidSize] = }; -static const char *kGuidNames[] = +static const char * const kGuidNames[] = { "CRC" , "VolumeTopFile" @@ -175,7 +172,7 @@ static bool AreGuidsEq(const Byte *p1, const Byte *p2) static int FindGuid(const Byte *p) { - for (int i = 0; i < ARRAY_SIZE(kGuids); i++) + for (unsigned i = 0; i < ARRAY_SIZE(kGuids); i++) if (AreGuidsEq(p, kGuids[i])) return i; return -1; @@ -325,7 +322,7 @@ static const CUInt32PCharPair g_SECTION_TYPE[] = #define COMPRESSION_TYPE_LZH 1 #define COMPRESSION_TYPE_LZMA 2 -static const char *g_Methods[] = +static const char * const g_Methods[] = { "COPY" , "LZH" @@ -367,7 +364,7 @@ static AString GuidToString(const Byte *p, bool full) return s; } -static const char *kExpressionCommands[] = +static const char * const kExpressionCommands[] = { "BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR" }; @@ -385,7 +382,7 @@ static bool ParseDepedencyExpression(const Byte *p, UInt32 size, AString &res) { if (i + kGuidSize > size) return false; - res += " "; + res.Add_Space(); res += GuidToString(p + i, false); i += kGuidSize; } @@ -427,9 +424,11 @@ static const UInt32 kFileHeaderSize = 24; static void AddSpaceAndString(AString &res, const AString &newString) { - if (!res.IsEmpty() && !newString.IsEmpty()) - res += ' '; - res += newString; + if (!newString.IsEmpty()) + { + res.Add_Space_if_NotEmpty(); + res += newString; + } } class CFfsFileHeader @@ -604,7 +603,7 @@ void CItem::SetGuid(const Byte *guidName, bool full) ThereIsUniqueName = true; int index = FindGuid(guidName); if (index >= 0) - Name = kGuidNames[index]; + Name = kGuidNames[(unsigned)index]; else Name = GuidToString(guidName, full); } @@ -617,9 +616,9 @@ AString CItem::GetName(int numChildsInParent) const char sz2[32]; ConvertUInt32ToString(NameIndex, sz); ConvertUInt32ToString(numChildsInParent - 1, sz2); - int numZeros = (int)strlen(sz2) - (int)strlen(sz); + unsigned numZeros = (unsigned)strlen(sz2) - (unsigned)strlen(sz); AString res; - for (int i = 0; i < numZeros; i++) + for (unsigned i = 0; i < numZeros; i++) res += '0'; return res + (AString)sz + '.' + Name; } @@ -646,7 +645,7 @@ class CHandler: UInt32 _methodsMask; bool _capsuleMode; - UInt32 _totalBufsSize; + size_t _totalBufsSize; CCapsuleHeader _h; UInt64 _phySize; @@ -654,9 +653,9 @@ class CHandler: int AddItem(const CItem &item); int AddFileItemWithIndex(CItem &item); int AddDirItem(CItem &item); - int AddBuf(UInt32 size); + unsigned AddBuf(size_t size); - HRESULT ParseSections(int bufIndex, UInt32 pos, UInt32 size, int parent, int method, int level); + HRESULT ParseSections(int bufIndex, UInt32 pos, UInt32 size, int parent, int method, unsigned level); HRESULT ParseVolume(int bufIndex, UInt32 posBase, UInt32 exactSize, UInt32 limitSize, int parent, int method, int level); @@ -711,7 +710,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val break; } case kpidIsDir: prop = item.IsDir; break; - case kpidMethod: if (item.Method >= 0) prop = g_Methods[item.Method]; break; + case kpidMethod: if (item.Method >= 0) prop = g_Methods[(unsigned)item.Method]; break; case kpidCharacts: if (!item2.Characts.IsEmpty()) prop = item2.Characts; break; case kpidSize: if (!item.IsDir) prop = (UInt64)item.Size; break; } @@ -739,15 +738,15 @@ void CHandler::AddCommentString(const wchar_t *name, UInt32 pos) c = Get16(buf + i); if (c == 0) break; - s += L'\n'; + s.Add_LF(); } s += c; } if (s.IsEmpty()) return; - _comment += L'\n'; + _comment.Add_LF(); _comment += name; - _comment += L": "; + _comment.AddAscii(": "); _comment += s; } @@ -760,7 +759,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidMethod: { AString s; - for (int i = 0; i < 32; i++) + for (unsigned i = 0; i < 32; i++) if ((_methodsMask & ((UInt32)1 << i)) != 0) AddSpaceAndString(s, g_Methods[i]); if (!s.IsEmpty()) @@ -792,341 +791,7 @@ static void MyPrint(UInt32 posBase, UInt32 size, int level, const char *name) #define MyPrint(posBase, size, level, name) #endif -static const unsigned kNumBigValueBits = 8 * 4; -static const unsigned kNumValueBytes = 3; -static const unsigned kNumValueBits = 8 * kNumValueBytes; -static const UInt32 kMask = (1 << kNumValueBits) - 1; - -class CBitmMemDecoder -{ - unsigned _bitPos; - UInt32 _value; - const Byte *_buf; - size_t _pos; - size_t _size; - size_t _extra; -public: - void Init(const Byte *buf, size_t size) - { - _buf = buf; - _size = size; - _pos = 0; - _extra = 0; - _bitPos = kNumBigValueBits; - Normalize(); - } - - bool IsFullFinished() const { return (_extra * 8) == (kNumBigValueBits - _bitPos); } - - void Normalize() - { - for (; _bitPos >= 8; _bitPos -= 8) - { - Byte b; - if (_pos < _size) - b = _buf[_pos++]; - else - { - b = 0; - _extra++; - } - _value = (_value << 8) | b; - } - } - - UInt32 GetValue(unsigned numBits) const - { - return ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - numBits); - } - - void MovePos(unsigned numBits) - { - _bitPos += numBits; - Normalize(); - } - - UInt32 ReadBitsFast(unsigned numBits) - { - UInt32 res = GetValue(numBits); - MovePos(numBits); - return res; - } - - UInt32 ReadBits(unsigned numBits); - UInt32 ReadAlignBits() { return ReadBits((32 - _bitPos) & 7); } -}; - -UInt32 CBitmMemDecoder::ReadBits(unsigned numBits) -{ - UInt32 res = GetValue(numBits); - MovePos(numBits); - return res; -} - -namespace NHuffman { - -static const int kNumTableBits = 9; -static const int kNumBitsMax = 16; - -class CDecoder -{ - UInt32 m_Limits[kNumBitsMax + 1]; - UInt32 m_Positions[kNumBitsMax + 1]; - Byte m_Lengths[1 << kNumTableBits]; - Int32 m_MainSymbol; - -public: - UInt32 *m_Symbols; - UInt32 m_NumSymbols; - - void SetSingleSymbolMode(UInt32 symbol) { m_MainSymbol = symbol; } - bool SetCodeLengths(const Byte *codeLengths); - UInt32 DecodeSymbol(CBitmMemDecoder *bitStream) - { - if (m_MainSymbol != -1) - return (UInt32)m_MainSymbol; - int numBits; - UInt32 value = bitStream->GetValue(kNumBitsMax); - if (value < m_Limits[kNumTableBits]) - numBits = m_Lengths[value >> (kNumBitsMax - kNumTableBits)]; - else - for (numBits = kNumTableBits + 1; value >= m_Limits[numBits]; numBits++); - bitStream->MovePos(numBits); - return m_Symbols[m_Positions[numBits] + ((value - m_Limits[numBits - 1]) >> (kNumBitsMax - numBits))]; - } -}; - -bool CDecoder::SetCodeLengths(const Byte *codeLengths) -{ - m_MainSymbol = -1; - int lenCounts[kNumBitsMax + 1]; - UInt32 tmpPositions[kNumBitsMax + 1]; - int i; - for (i = 1; i <= kNumBitsMax; i++) - lenCounts[i] = 0; - UInt32 symbol; - for (symbol = 0; symbol < m_NumSymbols; symbol++) - { - int len = codeLengths[symbol]; - if (len > kNumBitsMax) - return false; - lenCounts[len]++; - m_Symbols[symbol] = 0xFFFFFFFF; - } - lenCounts[0] = 0; - m_Positions[0] = m_Limits[0] = 0; - UInt32 startPos = 0; - UInt32 index = 0; - const UInt32 kMaxValue = (1 << kNumBitsMax); - for (i = 1; i <= kNumBitsMax; i++) - { - startPos += lenCounts[i] << (kNumBitsMax - i); - if (startPos > kMaxValue) - return false; - m_Limits[i] = (i == kNumBitsMax) ? kMaxValue : startPos; - m_Positions[i] = m_Positions[i - 1] + lenCounts[i - 1]; - tmpPositions[i] = m_Positions[i]; - if (i <= kNumTableBits) - { - UInt32 limit = (m_Limits[i] >> (kNumBitsMax - kNumTableBits)); - for (; index < limit; index++) - m_Lengths[index] = (Byte)i; - } - } - if (startPos != kMaxValue) - return false; - for (symbol = 0; symbol < m_NumSymbols; symbol++) - { - int len = codeLengths[symbol]; - if (len != 0) - m_Symbols[tmpPositions[len]++] = symbol; - } - return true; -} - -} - -static const int kMaxHuffmanLen = 16; -static const int kExtraSize = kMaxHuffmanLen + 3; -static const int kMinMatchLen = 3; -static const int kMaxMatchLen = 256; -static const int kNumAlphaSymsMax = 256 + kMaxMatchLen - kMinMatchLen + 1; -static const int kNumDistSymsMax = 24 + 2; // it's limited by bit decoder. - -#define HUFF_START_CODE(huff, numSymsMax, numSymBits) \ - UInt32 numSyms = bitDec.ReadBits(numSymBits); \ - Byte lens[numSymsMax]; memset(lens, 0, sizeof(lens)); \ - if (numSyms > (numSymsMax)) return S_FALSE; \ - huff.m_NumSymbols = numSyms; \ - if (numSyms == 0) { \ - numSyms = bitDec.ReadBits(numSymBits); \ - if (numSyms >= (numSymsMax)) return S_FALSE; \ - huff.SetSingleSymbolMode(numSyms); } \ - -static HRESULT LzhDecode(Byte *dest, UInt32 destSize, const Byte *src, UInt32 srcSize) -{ - if (srcSize < 8) - return S_FALSE; - { - UInt32 packSize = Get32(src); - UInt32 unpackSize = Get32(src + 4); - src += 8; - srcSize -= 8; - if (destSize != unpackSize || srcSize != packSize) - return S_FALSE; - } - - CBitmMemDecoder bitDec; - bitDec.Init(src, srcSize); - UInt32 pos = 0; - for (;;) - { - UInt32 blockSize = bitDec.ReadBits(16); - UInt32 symbols[kExtraSize + kNumAlphaSymsMax + kNumDistSymsMax]; - - NHuffman::CDecoder extraHuff; - extraHuff.m_Symbols = symbols; - { - HUFF_START_CODE(extraHuff, kExtraSize, 5) - else - { - for (UInt32 i = 0; i < numSyms; i++) - { - if (i == 3) - { - UInt32 numZeros = bitDec.ReadBits(2); - if (i + numZeros > numSyms) - return S_FALSE; - for (UInt32 j = 0; j < numZeros; j++, i++) - lens[i] = (Byte)0; - if (i == numSyms) - break; - } - - UInt32 len = bitDec.ReadBits(3); - if (len == 7) - { - for(;; len++) - { - if (len > kMaxHuffmanLen) - return S_FALSE; - if (bitDec.ReadBits(1) == 0) - break; - } - } - lens[i] = (Byte)len; - } - if (!extraHuff.SetCodeLengths(lens)) - return S_FALSE; - } - } - - NHuffman::CDecoder symHuff; - symHuff.m_Symbols = symbols + kExtraSize; - { - HUFF_START_CODE(symHuff, kNumAlphaSymsMax, 9) - else - { - for (UInt32 i = 0; i < numSyms;) - { - UInt32 c = extraHuff.DecodeSymbol(&bitDec); - if (c > 2) - lens[i++] = (Byte)(c - 2); - else - { - UInt32 numZeros; - if (c == 0) - numZeros = 1; - else if (c == 1) - numZeros = bitDec.ReadBits(4) + 3; - else - numZeros = bitDec.ReadBits(9) + 20; - if (i + numZeros > numSyms) - return S_FALSE; - for (UInt32 j = 0; j < numZeros; j++, i++) - lens[i] = (Byte)0; - } - } - if (!symHuff.SetCodeLengths(lens)) - return S_FALSE; - } - } - - NHuffman::CDecoder distHuff; - distHuff.m_Symbols = symbols + kExtraSize + kNumAlphaSymsMax; - { - const UInt32 version = 1; - const UInt32 numDistBits = version + 4; - HUFF_START_CODE(distHuff, kNumDistSymsMax, numDistBits) - else - { - for (UInt32 i = 0; i < numSyms; i++) - { - UInt32 len = bitDec.ReadBits(3); - if (len == 7) - { - for(;; len++) - { - if (len > kMaxHuffmanLen) - return S_FALSE; - if (bitDec.ReadBits(1) == 0) - break; - } - } - lens[i] = (Byte)len; - } - if (!distHuff.SetCodeLengths(lens)) - return S_FALSE; - } - } - - while (blockSize) - { - blockSize--; - UInt32 c = symHuff.DecodeSymbol(&bitDec); - if (c < 256) - { - if (destSize == 0) - return S_FALSE; - *dest++ = (Byte)c; - destSize--; - pos++; - continue; - } - c = c - 256 + kMinMatchLen; - if (destSize < c) - return S_FALSE; - UInt32 dist = distHuff.DecodeSymbol(&bitDec); - if (dist > 1) - dist = ((UInt32)1 << (dist - 1)) + bitDec.ReadBits(dist - 1); - dist++; - if (dist > pos) - return S_FALSE; - pos += c; - destSize -= c; - do - { - *dest = dest[0 - (Int32)dist]; - dest++; - } - while (--c); - } - - // PRF(printf("\ndestSize = %6d", destSize)); - if (destSize == 0) - { - if (bitDec.ReadAlignBits() != 0) - return S_FALSE; - if (bitDec.ReadBits(8) != 0) - return S_FALSE; - if (!bitDec.IsFullFinished()) - return S_FALSE; - break; - } - } - return S_OK; -} int CHandler::AddItem(const CItem &item) { @@ -1153,17 +818,17 @@ int CHandler::AddDirItem(CItem &item) return AddItem(item); } -int CHandler::AddBuf(UInt32 size) +unsigned CHandler::AddBuf(size_t size) { if (size > kBufTotalSizeMax - _totalBufsSize) throw 1; _totalBufsSize += size; - int index = _bufs.Size(); + unsigned index = _bufs.Size(); _bufs.AddNew().Alloc(size); return index; } -HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int parent, int method, int level) +HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int parent, int method, unsigned level) { if (level > kLevelMax) return S_FALSE; @@ -1229,9 +894,55 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p } else if (compressionType == COMPRESSION_TYPE_LZH) { - int newBufIndex = AddBuf(uncompressedSize); + unsigned newBufIndex = AddBuf(uncompressedSize); CByteBuffer &buf = _bufs[newBufIndex]; - RINOK(LzhDecode(buf, uncompressedSize, pStart, newSectSize)); + + NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = 0; + CMyComPtr<ICompressCoder> lzhDecoder; + + lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder; + lzhDecoder = lzhDecoderSpec; + + { + const Byte *src = pStart; + if (newSectSize < 8) + return S_FALSE; + UInt32 packSize = Get32(src); + UInt32 unpackSize = Get32(src + 4); + if (uncompressedSize != unpackSize || newSectSize - 8 != packSize) + return S_FALSE; + if (packSize < 1) + return S_FALSE; + packSize--; + src += 8; + if (src[packSize] != 0) + return S_FALSE; + + CBufInStream *inStreamSpec = new CBufInStream; + CMyComPtr<IInStream> inStream = inStreamSpec; + inStreamSpec->Init(src, packSize); + + CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; + CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; + outStreamSpec->Init(buf, uncompressedSize); + + UInt64 uncompressedSize64 = uncompressedSize; + lzhDecoderSpec->FinishMode = true; + /* + EFI 1.1 probably used small dictionary and (pbit = 4) in LZH. We don't support such archives. + New version of compression code (named Tiano) uses LZH with (1 << 19) dictionary. + But maybe LZH decoder in UEFI decoder supports larger than (1 << 19) dictionary. + */ + lzhDecoderSpec->SetDictSize(1 << 19); + + HRESULT res = lzhDecoder->Code(inStream, outStream, NULL, &uncompressedSize64, NULL); + if (res != S_OK) + return res; + + if (lzhDecoderSpec->GetInputProcessedSize() != packSize) + return S_FALSE; + } + RINOK(ParseSections(newBufIndex, 0, uncompressedSize, parent, compressionType, level)); } else @@ -1258,7 +969,7 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p if (lzmaUncompressedSize < uncompressedSize) return S_FALSE; SizeT destLen = (SizeT)lzmaUncompressedSize; - int newBufIndex = AddBuf((UInt32)lzmaUncompressedSize); + unsigned newBufIndex = AddBuf((size_t)lzmaUncompressedSize); CByteBuffer &buf = _bufs[newBufIndex]; ELzmaStatus status; SizeT srcLen = newSectSize - (addSize + 5 + 8); @@ -1278,7 +989,7 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p } else if (type == SECTION_GUID_DEFINED) { - const UInt32 kHeaderSize = 4 + kGuidSize + 4; + const unsigned kHeaderSize = 4 + kGuidSize + 4; if (sectSize < kHeaderSize) return S_FALSE; item.SetGuid(p + 4); @@ -1373,7 +1084,8 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p { item.BufIndex = AddBuf(s.Len()); CByteBuffer &buf0 = _bufs[item.BufIndex]; - memcpy(buf0, s, s.Len()); + if (s.Len() != 0) + memcpy(buf0, s, s.Len()); item.Offset = 0; item.Size = s.Len(); } @@ -1389,7 +1101,7 @@ HRESULT CHandler::ParseSections(int bufIndex, UInt32 posBase, UInt32 size, int p { AString s2 = "ver:"; s2 += UInt32ToString(Get16(p + 4)); - s2 += ' '; + s2.Add_Space(); s2 += s; AddSpaceAndString(_items[item.Parent].Characts, s2); needAdd = false; @@ -1617,7 +1329,7 @@ HRESULT CHandler::ParseVolume( HRESULT CHandler::OpenCapsule(IInStream *stream) { - const UInt32 kHeaderSize = 80; + const unsigned kHeaderSize = 80; Byte buf[kHeaderSize]; RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)); _h.Parse(buf); @@ -1632,7 +1344,7 @@ HRESULT CHandler::OpenCapsule(IInStream *stream) _h.OffsetToSplitInformation != 0 ) return E_NOTIMPL; - int bufIndex = AddBuf(_h.CapsuleImageSize); + unsigned bufIndex = AddBuf(_h.CapsuleImageSize); CByteBuffer &buf0 = _bufs[bufIndex]; memcpy(buf0, buf, kHeaderSize); ReadStream_FALSE(stream, buf0 + kHeaderSize, _h.CapsuleImageSize - kHeaderSize); @@ -1662,7 +1374,7 @@ HRESULT CHandler::OpenFv(IInStream *stream, const UInt64 * /* maxCheckStartPosit _phySize = ffsHeader.VolSize; RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); UInt32 fvSize32 = (UInt32)ffsHeader.VolSize; - int bufIndex = AddBuf(fvSize32); + unsigned bufIndex = AddBuf(fvSize32); RINOK(ReadStream_FALSE(stream, _bufs[bufIndex], fvSize32)); return ParseVolume(bufIndex, 0, fvSize32, fvSize32, -1, -1, 0); } @@ -1680,14 +1392,17 @@ HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, unsigned num = _items.Size(); CIntArr numChilds(num); + unsigned i; + for (i = 0; i < num; i++) numChilds[i] = 0; + for (i = 0; i < num; i++) { int parent = _items[i].Parent; if (parent >= 0) - numChilds[parent]++; + numChilds[(unsigned)parent]++; } for (i = 0; i < num; i++) @@ -1696,14 +1411,15 @@ HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, int parent = item.Parent; if (parent >= 0) { - CItem &parentItem = _items[parent]; - if (numChilds[parent] == 1) + CItem &parentItem = _items[(unsigned)parent]; + if (numChilds[(unsigned)parent] == 1) if (!item.ThereIsUniqueName || !parentItem.ThereIsUniqueName || !parentItem.ThereAreSubDirs) parentItem.Skip = true; } } CUIntVector mainToReduced; + for (i = 0; i < _items.Size(); i++) { mainToReduced.Add(_items2.Size()); @@ -1714,14 +1430,15 @@ HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, int numItems = -1; int parent = item.Parent; if (parent >= 0) - numItems = numChilds[parent]; + numItems = numChilds[(unsigned)parent]; AString name2 = item.GetName(numItems); AString characts2 = item.Characts; if (item.KeepName) name = name2; + while (parent >= 0) { - const CItem &item3 = _items[parent]; + const CItem &item3 = _items[(unsigned)parent]; if (!item3.Skip) break; if (item3.KeepName) @@ -1735,6 +1452,7 @@ HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, AddSpaceAndString(characts2, item3.Characts); parent = item3.Parent; } + if (name.IsEmpty()) name = name2; @@ -1743,7 +1461,7 @@ HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, item2.Name = name; item2.Characts = characts2; if (parent >= 0) - item2.Parent = mainToReduced[parent]; + item2.Parent = mainToReduced[(unsigned)parent]; _items2.Add(item2); /* CItem2 item2; @@ -1753,6 +1471,7 @@ HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, _items2.Add(item2); */ } + return S_OK; } @@ -1873,30 +1592,26 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) namespace UEFIc { -IMP_CreateArcIn_2(CHandler(true)) - -static CArcInfo g_ArcInfo = - { "UEFIc", "scap", 0, 0xD0, - kCapsuleSigSize, CAPSULE_SIGNATURE, +REGISTER_ARC_I_CLS( + CHandler(true), + "UEFIc", "scap", 0, 0xD0, + kCapsuleSig, 0, NArcInfoFlags::kFindSignature, - CreateArc }; + NULL) -REGISTER_ARC(UEFIc) } namespace UEFIf { -IMP_CreateArcIn_2(CHandler(false)) - -static CArcInfo g_ArcInfo = - { "UEFIf", "uefif", 0, 0xD1, - kGuidSize, FFS_SIGNATURE, +REGISTER_ARC_I_CLS( + CHandler(false), + "UEFIf", "uefif", 0, 0xD1, + k_FFS_Guid, kFfsGuidOffset, NArcInfoFlags::kFindSignature, - CreateArc }; - -REGISTER_ARC(UEFIf) + NULL) + } }} diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp index a2126811..7508adfa 100644 --- a/CPP/7zip/Archive/VhdHandler.cpp +++ b/CPP/7zip/Archive/VhdHandler.cpp @@ -6,8 +6,6 @@ #include "../../Common/ComTry.h" #include "../../Common/IntToString.h" -#include "../../Common/MyBuffer.h" -#include "../../Common/MyString.h" #include "../../Windows/PropVariant.h" @@ -41,7 +39,7 @@ static const UInt32 kDiskType_Fixed = 2; static const UInt32 kDiskType_Dynamic = 3; static const UInt32 kDiskType_Diff = 4; -static const char *kDiskTypes[] = +static const char * const kDiskTypes[] = { "0" , "1" @@ -201,11 +199,17 @@ bool CDynHeader::Parse(const Byte *p) memcpy(ParentId, p + 0x28, 16); { 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[kNameLen] = 0; - ParentName.ReleaseBuffer(); + wchar_t *s = ParentName.GetBuf(kNameLen); + unsigned i; + for (i = 0; i < kNameLen; i++) + { + wchar_t c = Get16(p + 0x40 + i * 2); + if (c == 0) + break; + s[i] = c; + } + s[i] = 0; + ParentName.ReleaseBuf_SetLen(i); } for (unsigned i = 0; i < 8; i++) if (!ParentLocators[i].Parse(p + 0x240 + i * 24)) @@ -240,7 +244,7 @@ class CHandler: void AddErrorMessage(const wchar_t *s) { if (!_errorMessage.IsEmpty()) - _errorMessage += L'\n'; + _errorMessage.Add_LF(); _errorMessage += s; } void UpdatePhySize(UInt64 value) @@ -265,7 +269,7 @@ class CHandler: while (p && p->NeedParent()) { if (!res.IsEmpty()) - res += L" -> "; + res.AddAscii(" -> "); UString mainName; UString anotherName; if (Dyn.RelativeNameWasUsed) @@ -281,7 +285,7 @@ class CHandler: res += mainName; if (mainName != anotherName && !anotherName.IsEmpty()) { - res += L' '; + res.Add_Space(); res += L'('; res += anotherName; res += L')'; @@ -425,12 +429,20 @@ HRESULT CHandler::Open3() 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(); + { + wchar_t *s = tempString.GetBuf(len); + RINOK(ReadPhy(locator.DataOffset, nameBuf, locator.DataLen)); + unsigned j; + for (j = 0; j < len; j++) + { + wchar_t c = GetUi16(nameBuf + j * 2); + if (c == 0) + break; + s[j] = c; + } + s[j] = 0; + tempString.ReleaseBuf_SetLen(j); + } if (tempString[0] == L'.' && tempString[1] == L'\\') tempString.DeleteFrontal(2); Dyn.RelativeParentNameFromLocator = tempString; @@ -518,10 +530,10 @@ HRESULT CHandler::Open3() STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize) { - if (processedSize != NULL) + if (processedSize) *processedSize = 0; if (_virtPos >= Footer.CurrentSize) - return (Footer.CurrentSize == _virtPos) ? S_OK: E_FAIL; + return S_OK; UInt64 rem = Footer.CurrentSize - _virtPos; if (size > rem) size = (UInt32)rem; @@ -576,7 +588,7 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize) cur += rem; } } - if (processedSize != NULL) + if (processedSize) *processedSize = size; _virtPos += size; return res; @@ -705,7 +717,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) AString res = s; res.Trim(); ConvertUInt32ToString(Footer.CreatorVersion >> 16, s); - res += ' '; + res.Add_Space(); res += s; res += '.'; ConvertUInt32ToString(Footer.CreatorVersion & 0xFFFF, s); @@ -971,15 +983,11 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea COM_TRY_END } -IMP_CreateArcIn - -static CArcInfo g_ArcInfo = - { "VHD", "vhd", ".mbr", 0xDC, - kSignatureSize, SIGNATURE, +REGISTER_ARC_I( + "VHD", "vhd", ".mbr", 0xDC, + kSignature, 0, NArcInfoFlags::kUseGlobalOffset, - CreateArc }; - -REGISTER_ARC(Vhd) + NULL) }} diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp index 886d8d77..bca551a6 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.cpp +++ b/CPP/7zip/Archive/Wim/WimHandler.cpp @@ -37,7 +37,9 @@ static const Byte kProps[] = kpidMethod, kpidShortName, kpidINode, - kpidLinks + kpidLinks, + kpidIsAltStream, + kpidNumAltStreams, #ifdef WIM_DETAILS , kpidVolume @@ -269,14 +271,12 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) res = kMethodLZX; if (xpress) { - if (!res.IsEmpty()) - res += ' '; + res.Add_Space_if_NotEmpty(); res += kMethodXpress; } if (copy) { - if (!res.IsEmpty()) - res += ' '; + res.Add_Space_if_NotEmpty(); res += kMethodCopy; } prop = res; @@ -308,6 +308,26 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) AddErrorMessage(s, "Some files have incorrect reference count"); if (!s.IsEmpty()) prop = s; + break; + } + + case kpidReadOnly: + { + bool readOnly = false; + if (ThereIsError()) + readOnly = true; + else if (_volumes.Size() != 0) + { + if (_version != kWimVersion + || _volumes.Size() != 2 + || _volumes[0].Stream + // || _db.Images.Size() > kNumImagesMax + ) + readOnly = true; + } + if (readOnly) + prop = readOnly; + break; } } prop.Detach(value); @@ -397,6 +417,22 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidSize: prop = (UInt64)(si ? si->Resource.UnpackSize : 0); break; case kpidIsDir: prop = item.IsDir; break; case kpidIsAltStream: prop = item.IsAltStream; break; + case kpidNumAltStreams: + { + if (!item.IsAltStream && mainItem->HasMetadata()) + { + UInt32 dirRecordSize = _db.IsOldVersion ? kDirRecordSizeOld : kDirRecordSize; + UInt32 numAltStreams = Get16(metadata + dirRecordSize - 6); + if (numAltStreams != 0) + { + if (!item.IsDir) + numAltStreams--; + prop = numAltStreams; + } + } + break; + } + case kpidAttrib: if (!item.IsAltStream && mainItem->ImageIndex >= 0) { @@ -481,7 +517,7 @@ STDMETHODIMP CHandler::GetRootProp(PROPID propID, PROPVARIANT *value) { // COM_TRY_BEGIN NCOM::CPropVariant prop; - if (_db.Images.Size() != 0 && _db.NumExludededItems != 0) + if (_db.Images.Size() != 0 && _db.NumExcludededItems != 0) { const CImage &image = _db.Images[_db.IndexOfUserImage]; const CItem &item = _db.Items[image.StartItem]; @@ -532,7 +568,7 @@ STDMETHODIMP CHandler::GetRootRawProp(PROPID propID, const void **data, UInt32 * *data = 0; *dataSize = 0; *propType = 0; - if (propID == kpidNtSecure && _db.Images.Size() != 0 && _db.NumExludededItems != 0) + if (propID == kpidNtSecure && _db.Images.Size() != 0 && _db.NumExcludededItems != 0) { const CImage &image = _db.Images[_db.IndexOfUserImage]; const CItem &item = _db.Items[image.StartItem]; @@ -705,7 +741,7 @@ class CVolumeName public: void InitName(const UString &name) { - int dotPos = name.ReverseFind('.'); + int dotPos = name.ReverseFind_Dot(); if (dotPos < 0) dotPos = name.Len(); _before = name.Left(dotPos); @@ -798,11 +834,11 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal if (_xmls.IsEmpty() || xml.Data != _xmls[0].Data) { - wchar_t sz[16]; + char sz[16]; ConvertUInt32ToString(xml.VolIndex, sz); xml.FileName = L'['; - xml.FileName += sz; - xml.FileName += L"].xml"; + xml.FileName.AddAscii(sz); + xml.FileName.AddAscii("].xml"); _xmls.Add(xml); } @@ -957,11 +993,12 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, int streamIndex = item.StreamIndex; if (streamIndex < 0) { - if (!testMode && !realOutStream) - continue; + if (!item.IsDir) + if (!testMode && !realOutStream) + continue; RINOK(extractCallback->PrepareOperation(askMode)); realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(_db.ItemHasStream(item) ? + RINOK(extractCallback->SetOperationResult(!item.IsDir && _db.ItemHasStream(item) ? NExtract::NOperationResult::kDataError : NExtract::NOperationResult::kOK)); continue; @@ -1016,7 +1053,7 @@ CHandler::CHandler() _xmlError = false; } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { InitDefaults(); diff --git a/CPP/7zip/Archive/Wim/WimHandler.h b/CPP/7zip/Archive/Wim/WimHandler.h index 416e11ca..00de1b87 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.h +++ b/CPP/7zip/Archive/Wim/WimHandler.h @@ -70,7 +70,7 @@ public: INTERFACE_IInArchive(;) INTERFACE_IArchiveGetRawProps(;) INTERFACE_IArchiveGetRootProps(;) - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); + STDMETHOD(SetProperties)(const wchar_t * const *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 149989d1..145ede42 100644 --- a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp +++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp @@ -21,7 +21,7 @@ #include "../../Common/UniqBlocks.h" #include "../../Crypto/RandGen.h" -#include "../../Crypto/Sha1.h" +#include "../../Crypto/Sha1Cls.h" #include "WimHandler.h" @@ -676,6 +676,8 @@ static void AddTrees(CObjectVector<CDir> &trees, CObjectVector<CMetaItem> &metaI trees.AddNew().Dirs.AddNew().MetaIndex = metaItems.Add(ri); } +#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') + STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 numItems, IArchiveUpdateCallback *callback) { COM_TRY_BEGIN @@ -789,7 +791,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu unsigned imageIndex = (unsigned)val - 1; if (imageIndex < _db.Images.Size()) isChangedImage[imageIndex] = true; - if (_defaultImageNumber > 0 && val != _defaultImageNumber) + if (_defaultImageNumber > 0 && val != (unsigned)_defaultImageNumber) return E_INVALIDARG; } } @@ -1065,9 +1067,16 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu int colonPos = fileName.Find(L':'); if (colonPos < 0) return E_INVALIDARG; + + // we want to support cases of c::substream, where c: is drive name + if (colonPos == 1 && fileName[2] == L':' && IS_LETTER_CHAR(fileName[0])) + colonPos = 2; const UString mainName = fileName.Left(colonPos); unsigned indexOfDir; - if (curItem->FindDir(db.MetaItems, mainName, indexOfDir)) + + if (mainName.IsEmpty()) + ui.MetaIndex = curItem->MetaIndex; + else if (curItem->FindDir(db.MetaItems, mainName, indexOfDir)) ui.MetaIndex = curItem->Dirs[indexOfDir].MetaIndex; else { @@ -1082,6 +1091,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu } } } + if (ui.MetaIndex >= 0) { CAltStream ss; @@ -1126,7 +1136,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu NCOM::CPropVariant prop; RINOK(GetOutProperty(callback, i, arcIndex, kpidShortName, &prop)); if (prop.vt == VT_BSTR) - mi.ShortName = prop.bstrVal; + mi.ShortName.SetFromBstr(prop.bstrVal); else if (prop.vt != VT_EMPTY) return E_INVALIDARG; } @@ -1235,7 +1245,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu { const CItem &item = _db.Items[k]; if (item.StreamIndex >= 0) - streamsRefs[item.StreamIndex]++; + streamsRefs[(unsigned)item.StreamIndex]++; } } @@ -1250,7 +1260,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu continue; const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]]; if (item.StreamIndex >= 0) - streamsRefs[item.StreamIndex]++; + streamsRefs[(unsigned)item.StreamIndex]++; } else { @@ -1614,7 +1624,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu db.DefaultDirItem = ri; pos += db.WriteTree_Dummy(tree); - CByteBuffer meta(pos); + CByteArr meta(pos); Set32((Byte *)meta + 4, secBufs.Size()); // num security entries pos = kSecuritySize; @@ -1637,8 +1647,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu { const CByteBuffer &buf = secBufs[i]; size_t size = buf.Size(); - memcpy(meta + pos, buf, size); - pos += size; + if (size != 0) + { + memcpy(meta + pos, buf, size); + pos += size; + } } while ((pos & 7) != 0) meta[pos++] = 0; @@ -1740,15 +1753,15 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 nu size_t xmlSize; { - UString utf16String; - if (!ConvertUTF8ToUnicode(xml, utf16String)) + UString utf16; + if (!ConvertUTF8ToUnicode(xml, utf16)) return S_FALSE; - xmlSize = (utf16String.Len() + 1) * 2; + xmlSize = (utf16.Len() + 1) * 2; - CByteBuffer xmlBuf(xmlSize); + CByteArr xmlBuf(xmlSize); Set16((Byte *)xmlBuf, 0xFEFF); - for (i = 0; i < (unsigned)utf16String.Len(); i++) - Set16((Byte *)xmlBuf + 2 + i * 2, utf16String[i]); + for (i = 0; i < (unsigned)utf16.Len(); i++) + Set16((Byte *)xmlBuf + 2 + i * 2, utf16[i]); RINOK(WriteStream(outStream, (const Byte *)xmlBuf, xmlSize)); } diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp index cec037cc..12b8525c 100644 --- a/CPP/7zip/Archive/Wim/WimIn.cpp +++ b/CPP/7zip/Archive/Wim/WimIn.cpp @@ -325,10 +325,13 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO { unsigned size = 0; int index = index1; - unsigned newLevel; int imageIndex = Items[index].ImageIndex; const CImage &image = Images[imageIndex]; - for (newLevel = 0;;) + + unsigned newLevel = 0; + bool needColon = false; + + for (;;) { const CItem &item = Items[index]; index = item.Parent; @@ -338,10 +341,11 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO meta += item.IsAltStream ? (IsOldVersion ? 0x10 : 0x24) : (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2); + needColon = item.IsAltStream; size += Get16(meta) / 2; size += newLevel; newLevel = 1; - if ((UInt32)size >= ((UInt32)1 << 15)) + if (size >= ((UInt32)1 << 15)) { path = kLongPath; return; @@ -356,7 +360,9 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO size += image.RootName.Len(); size += newLevel; } - + else if (needColon) + size++; + wchar_t *s = path.AllocBstr(size); s[size] = 0; @@ -364,28 +370,31 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO { MyStringCopy(s, (const wchar_t *)image.RootName); if (newLevel) - s[image.RootName.Len()] = WCHAR_PATH_SEPARATOR; + s[image.RootName.Len()] = (wchar_t)(needColon ? L':' : WCHAR_PATH_SEPARATOR); } + else if (needColon) + s[0] = L':'; index = index1; wchar_t separator = 0; + for (;;) { const CItem &item = Items[index]; index = item.Parent; if (index >= 0 || image.NumEmptyRootItems == 0) { - if (separator) + if (separator != 0) 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; + unsigned len = Get16(meta) / 2; size -= len; wchar_t *dest = s + size; meta += 2; - for (UInt32 i = 0; i < len; i++) + for (unsigned i = 0; i < len; i++) dest[i] = Get16(meta + i * 2); } if (index < 0) @@ -394,6 +403,14 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO } } +static bool IsEmptySha(const Byte *data) +{ + for (unsigned i = 0; i < kHashSize; i++) + if (data[i] != 0) + return false; + return true; +} + // 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. @@ -472,6 +489,8 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) pos += (size_t)len; + unsigned numItems2 = Items.Size(); + for (UInt32 i = 0; i < numAltStreams; i++) { size_t rem = DirSize - pos; @@ -522,7 +541,13 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) return S_FALSE; } - if (fileNameLen == 0) + + /* wim uses alt sreams list, if there is at least one alt stream. + And alt stream without name is main stream. */ + + if (fileNameLen == 0 && + (attrib & FILE_ATTRIBUTE_REPARSE_POINT + || !item.IsDir /* && (IsOldVersion || IsEmptySha(prevMeta + 0x40)) */ )) { Byte *prevMeta = DirData + item.Offset; if (IsOldVersion) @@ -546,7 +571,7 @@ HRESULT CDatabase::ParseDirItem(size_t pos, int parent) if (parent < 0 && numItems == 0 && shortNameLen == 0 && fileNameLen == 0 && item.IsDir) { CImage &image = Images.Back(); - image.NumEmptyRootItems = Items.Size() - image.StartItem; + image.NumEmptyRootItems = numItems2 - image.StartItem; // Items.Size() } if (item.IsDir && subdirOffset != 0) @@ -732,14 +757,6 @@ static HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db) return (i == offsetBuf.Size()) ? S_OK : S_FALSE; } -static bool IsEmptySha(const Byte *data) -{ - for (unsigned i = 0; i < kHashSize; i++) - if (data[i] != 0) - return false; - return true; -} - HRESULT CDatabase::OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml) { return UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL); @@ -1046,7 +1063,7 @@ HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber) SortedItems.Clear(); VirtualRoots.Clear(); IndexOfUserImage = imageIndex; - NumExludededItems = 0; + NumExcludededItems = 0; ExludedItem = -1; if (Images.Size() != 1 && imageIndex < 0) @@ -1054,6 +1071,7 @@ HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber) unsigned startItem = 0; unsigned endItem = 0; + if (imageIndex < 0) { endItem = Items.Size(); @@ -1062,7 +1080,7 @@ HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber) IndexOfUserImage = 0; const CImage &image = Images[0]; if (!showImageNumber) - NumExludededItems = image.NumEmptyRootItems; + NumExcludededItems = image.NumEmptyRootItems; } } else if ((unsigned)imageIndex < Images.Size()) @@ -1071,12 +1089,13 @@ HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber) startItem = image.StartItem; endItem = startItem + image.NumItems; if (!showImageNumber) - NumExludededItems = image.NumEmptyRootItems; + NumExcludededItems = image.NumEmptyRootItems; } - if (NumExludededItems != 0) + + if (NumExcludededItems != 0) { ExludedItem = startItem; - startItem += NumExludededItems; + startItem += NumExcludededItems; } unsigned num = endItem - startItem; @@ -1205,7 +1224,8 @@ HRESULT CDatabase::ExtractReparseStreams(const CObjectVector<CVolume> &volumes, Byte *dest = (Byte *)reparse; SetUi32(dest, tag); SetUi32(dest + 4, (UInt32)buf.Size()); - memcpy(dest + 8, buf, buf.Size()); + if (buf.Size() != 0) + memcpy(dest + 8, buf, buf.Size()); ItemToReparse[i] = ReparseItems.Size() - 1; } @@ -1278,20 +1298,28 @@ void CWimXml::ToUnicode(UString &s) const Byte *p = Data; if (Get16(p) != 0xFEFF) return; - wchar_t *chars = s.GetBuffer((unsigned)size / 2); + wchar_t *chars = s.GetBuf((unsigned)(size / 2)); for (size_t i = 2; i < size; i += 2) - *chars++ = (wchar_t)Get16(p + i); + { + wchar_t c = Get16(p + i); + if (c == 0) + break; + *chars++ = c; + } *chars = 0; - s.ReleaseBuffer(); + s.ReleaseBuf_SetLen((unsigned)(chars - (const wchar_t *)s)); } bool CWimXml::Parse() { - UString s; - ToUnicode(s); AString utf; - if (!ConvertUnicodeToUTF8(s, utf)) - return false; + { + UString s; + ToUnicode(s); + // if (!ConvertUnicodeToUTF8(s, utf)) return false; + ConvertUnicodeToUTF8(s, utf); + } + if (!Xml.Parse(utf)) return false; if (Xml.Root.Name != "WIM") diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h index 4b7c6d95..c3b93a8d 100644 --- a/CPP/7zip/Archive/Wim/WimIn.h +++ b/CPP/7zip/Archive/Wim/WimIn.h @@ -406,7 +406,7 @@ public: CUIntVector SortedItems; int IndexOfUserImage; // -1 : if more than one images was filled to Sorted Items - unsigned NumExludededItems; + unsigned NumExcludededItems; int ExludedItem; // -1 : if there are no exclude items CUIntVector VirtualRoots; // we use them for old 1.10 WIM archives @@ -418,7 +418,7 @@ public: return 0; if (imageIndex >= Images.Size()) return 0; - return Images[imageIndex].NumItems - NumExludededItems; + return Images[imageIndex].NumItems - NumExcludededItems; } bool ItemHasStream(const CItem &item) const; diff --git a/CPP/7zip/Archive/Wim/WimRegister.cpp b/CPP/7zip/Archive/Wim/WimRegister.cpp index 35d78314..3063dec4 100644 --- a/CPP/7zip/Archive/Wim/WimRegister.cpp +++ b/CPP/7zip/Archive/Wim/WimRegister.cpp @@ -9,19 +9,14 @@ namespace NArchive { namespace NWim { -IMP_CreateArcIn -IMP_CreateArcOut - -static CArcInfo g_ArcInfo = - { "wim", "wim swm", 0, 0xE6, - 8, { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }, +REGISTER_ARC_IO( + "wim", "wim swm", 0, 0xE6, + kSignature, 0, NArcInfoFlags::kAltStreams | NArcInfoFlags::kNtSecure | NArcInfoFlags::kSymLinks | NArcInfoFlags::kHardLinks - , REF_CreateArc_Pair }; - -REGISTER_ARC(Wim) + , NULL) }} diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp index 918ef736..7e89bf48 100644 --- a/CPP/7zip/Archive/XarHandler.cpp +++ b/CPP/7zip/Archive/XarHandler.cpp @@ -35,15 +35,15 @@ using namespace NWindows; namespace NArchive { namespace NXar { -static const UInt32 kXmlSizeMax = ((UInt32)1 << 30) - (1 << 14); -static const UInt32 kXmlPackSizeMax = kXmlSizeMax; +static const size_t kXmlSizeMax = ((size_t )1 << 30) - (1 << 14); +static const size_t kXmlPackSizeMax = kXmlSizeMax; /* #define XAR_CKSUM_NONE 0 #define XAR_CKSUM_SHA1 1 #define XAR_CKSUM_MD5 2 -static const char *k_ChecksumAlgos[] = +static const char * const k_ChecksumAlgos[] = { "None" , "SHA-1" @@ -76,8 +76,8 @@ struct CFile bool Sha1IsDefined; // bool packSha1IsDefined; - Byte Sha1[NCrypto::NSha1::kDigestSize]; - // Byte packSha1[NCrypto::NSha1::kDigestSize]; + Byte Sha1[SHA1_DIGEST_SIZE]; + // Byte packSha1[SHA1_DIGEST_SIZE]; int Parent; @@ -107,7 +107,8 @@ class CHandler: { UInt64 _dataStartPos; CMyComPtr<IInStream> _inStream; - AString _xml; + CByteArr _xml; + size_t _xmlLen; CObjectVector<CFile> _files; // UInt32 _checkSumAlgo; UInt64 _phySize; @@ -182,7 +183,7 @@ static UInt64 ParseTime(const CXmlItem &item, const char *name) return numSecs * 10000000; } -static int HexToByte(char c) +static int HexToByte(unsigned char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'F') return c - 'A' + 10; @@ -200,7 +201,7 @@ static bool ParseSha1(const CXmlItem &item, const char *name, Byte *digest) if (style == "SHA1") { const AString s = checkItem.GetSubString(); - if (s.Len() != NCrypto::NSha1::kDigestSize * 2) + if (s.Len() != SHA1_DIGEST_SIZE * 2) return false; for (unsigned i = 0; i < s.Len(); i += 2) { @@ -321,8 +322,9 @@ HRESULT CHandler::Open2(IInStream *stream) _dataStartPos = kHeaderSize + packSize; _phySize = _dataStartPos; - char *ss = _xml.GetBuffer((unsigned)unpackSize); - + _xml.Alloc((size_t)unpackSize + 1); + _xmlLen = (size_t)unpackSize; + NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder(); CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec; @@ -333,18 +335,18 @@ HRESULT CHandler::Open2(IInStream *stream) CBufPtrSeqOutStream *outStreamLimSpec = new CBufPtrSeqOutStream; CMyComPtr<ISequentialOutStream> outStreamLim(outStreamLimSpec); - outStreamLimSpec->Init((Byte *)ss, (size_t)unpackSize); + outStreamLimSpec->Init(_xml, (size_t)unpackSize); RINOK(zlibCoder->Code(inStreamLim, outStreamLim, NULL, NULL, NULL)); if (outStreamLimSpec->GetPos() != (size_t)unpackSize) return S_FALSE; - ss[(size_t)unpackSize] = 0; - _xml.ReleaseBuffer(); + _xml[(size_t)unpackSize] = 0; + if (strlen((const char *)(const Byte *)_xml) != unpackSize) return S_FALSE; CXml xml; - if (!xml.Parse(_xml)) + if (!xml.Parse((const char *)(const Byte *)_xml)) return S_FALSE; if (!xml.Root.IsTagged("xar") || xml.Root.SubItems.Size() != 1) @@ -390,7 +392,8 @@ STDMETHODIMP CHandler::Close() _phySize = 0; _inStream.Release(); _files.Clear(); - _xml.Empty(); + _xmlLen = 0; + _xml.Free(); _mainSubfile = -1; _is_pkg = false; return S_OK; @@ -456,7 +459,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { case kpidPath: prop = "[TOC].xml"; break; case kpidSize: - case kpidPackSize: prop = (UInt64)_xml.Len(); break; + case kpidPackSize: prop = (UInt64)_xmlLen; break; } } else @@ -531,7 +534,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, UInt32 index = (allFilesMode ? i : indices[i]); #ifdef XAR_SHOW_RAW if (index == _files.Size()) - totalSize += _xml.Len(); + totalSize += _xmlLen; else #endif totalSize += _files[index].Size; @@ -614,9 +617,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (index == _files.Size()) { outStreamSha1Spec->Init(false); - outStreamLimSpec->Init(_xml.Len()); - RINOK(WriteStream(outStream, (const char *)_xml, _xml.Len())); - currentPackSize = currentUnpSize = _xml.Len(); + outStreamLimSpec->Init(_xmlLen); + RINOK(WriteStream(outStream, _xml, _xmlLen)); + currentPackSize = currentUnpSize = _xmlLen; } else #endif @@ -670,9 +673,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } else if (item.Sha1IsDefined) { - Byte digest[NCrypto::NSha1::kDigestSize]; + Byte digest[SHA1_DIGEST_SIZE]; outStreamSha1Spec->Final(digest); - if (memcmp(digest, item.Sha1, NCrypto::NSha1::kDigestSize) != 0) + if (memcmp(digest, item.Sha1, SHA1_DIGEST_SIZE) != 0) opRes = NExtract::NOperationResult::kCRCError; } } @@ -695,7 +698,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) #ifdef XAR_SHOW_RAW if (index == _files.Size()) { - Create_BufInStream_WithNewBuf((const void *)(const char *)_xml, _xml.Len(), stream); + Create_BufInStream_WithNewBuffer(_xml, _xmlLen, stream); return S_OK; } else @@ -709,15 +712,13 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) COM_TRY_END } -IMP_CreateArcIn +static const Byte k_Signature[] = { 'x', 'a', 'r', '!', 0, 0x1C }; -static CArcInfo g_ArcInfo = - { "Xar", "xar pkg", 0, 0xE1, - 6, { 'x', 'a', 'r', '!', 0, 0x1C }, +REGISTER_ARC_I( + "Xar", "xar pkg", 0, 0xE1, + k_Signature, 0, 0, - CreateArc }; - -REGISTER_ARC(Xar) + NULL) }} diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp index 0de58a44..ada14fbf 100644 --- a/CPP/7zip/Archive/XzHandler.cpp +++ b/CPP/7zip/Archive/XzHandler.cpp @@ -23,6 +23,8 @@ #include "Common/HandlerOut.h" +#include "XzHandler.h" + using namespace NWindows; namespace NCompress { @@ -32,92 +34,36 @@ HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzm }} -static void *SzAlloc(void *, size_t size) { return MyAlloc(size); } -static void SzFree(void *, void *address) { MyFree(address); } -static ISzAlloc g_Alloc = { SzAlloc, SzFree }; - namespace NArchive { namespace NXz { struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit; -static const wchar_t *k_LZMA2_Name = L"LZMA2"; +static const char *k_LZMA2_Name = "LZMA2"; -struct CStatInfo +void CStatInfo::Clear() { - 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; + InSize = 0; + OutSize = 0; + PhySize = 0; - 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(); + NumStreams = 0; + NumBlocks = 0; + + UnpackSize_Defined = false; + + NumStreams_Defined = false; + NumBlocks_Defined = false; + + IsArc = false; + UnexpectedEnd = false; + DataAfterEnd = false; + Unsupported = false; + HeadersError = false; + DataError = false; + CrcError = false; } - class CHandler: public IInArchive, public IArchiveOpenSeq, @@ -148,10 +94,11 @@ class CHandler: HRESULT Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback); - HRESULT Decode2(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, IDecodeState &progress) + HRESULT Decode2(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, + CDecoder &decoder, ICompressProgressInfo *progress) { - RINOK(progress.Decode(seqInStream, outStream)); - _stat = progress; + RINOK(decoder.Decode(seqInStream, outStream, progress)); + _stat = decoder; _phySize_Defined = true; return S_OK; } @@ -171,7 +118,7 @@ public: #ifndef EXTRACT_ONLY INTERFACE_IOutArchive(;) - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); #endif CHandler(); @@ -295,12 +242,11 @@ static AString GetMethodString(const CXzFilter &f) static void AddString(AString &dest, const AString &src) { - if (!dest.IsEmpty()) - dest += ' '; + dest.Add_Space_if_NotEmpty(); dest += src; } -static const char *kChecks[] = +static const char * const kChecks[] = { "NoCheck" , "CRC32" @@ -423,26 +369,6 @@ struct CXzsCPP ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); } }; - -struct CVirtProgress_To_OpenProgress: public IDecodeState -{ - IArchiveOpenCallback *Callback; - UInt64 Offset; - - HRESULT Progress(); -}; - -HRESULT CVirtProgress_To_OpenProgress::Progress() -{ - if (Callback) - { - UInt64 files = 0; - UInt64 value = Offset + InSize; - return Callback->SetCompleted(&files, &value); - } - return S_OK; -} - static HRESULT SRes_to_Open_HRESULT(SRes res) { switch (res) @@ -527,6 +453,7 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal { res = SZ_OK; } + RINOK(SRes_to_Open_HRESULT(res)); _stream = inStream; _seqStream = inStream; @@ -587,38 +514,32 @@ STDMETHODIMP CSeekToSeqStream::Read(void *data, UInt32 size, UInt32 *processedSi STDMETHODIMP CSeekToSeqStream::Seek(Int64, UInt32, UInt64 *) { return E_NOTIMPL; } -struct CXzUnpackerCPP +CXzUnpackerCPP::CXzUnpackerCPP(): InBuf(0), OutBuf(0) { - Byte *InBuf; - Byte *OutBuf; - CXzUnpacker p; - - CXzUnpackerCPP(): InBuf(0), OutBuf(0) - { - XzUnpacker_Construct(&p, &g_Alloc); - } - ~CXzUnpackerCPP() - { - XzUnpacker_Free(&p); - MyFree(InBuf); - MyFree(OutBuf); - } -}; + XzUnpacker_Construct(&p, &g_Alloc); +} + +CXzUnpackerCPP::~CXzUnpackerCPP() +{ + XzUnpacker_Free(&p); + MyFree(InBuf); + MyFree(OutBuf); +} -HRESULT IDecodeState::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream) +HRESULT CDecoder::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress) { const size_t kInBufSize = 1 << 15; const size_t kOutBufSize = 1 << 21; + Clear(); DecodeRes = SZ_OK; - CXzUnpackerCPP xzu; XzUnpacker_Init(&xzu.p); - xzu.InBuf = (Byte *)MyAlloc(kInBufSize); - xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize); - if (!xzu.InBuf || !xzu.OutBuf) - return E_OUTOFMEMORY; - + if (!xzu.InBuf) + xzu.InBuf = (Byte *)MyAlloc(kInBufSize); + if (!xzu.OutBuf) + xzu.OutBuf = (Byte *)MyAlloc(kOutBufSize); + UInt32 inSize = 0; SizeT inPos = 0; SizeT outPos = 0; @@ -664,7 +585,10 @@ HRESULT IDecodeState::Decode(ISequentialInStream *seqInStream, ISequentialOutStr else outPos = 0; - RINOK(Progress()); + if (progress) + { + RINOK(progress->SetRatioInfo(&InSize, &OutSize)); + } if (finished) { @@ -730,6 +654,30 @@ HRESULT IDecodeState::Decode(ISequentialInStream *seqInStream, ISequentialOutStr return S_OK; } +Int32 CDecoder::Get_Extract_OperationResult() const +{ + Int32 opRes; + if (!IsArc) + opRes = NExtract::NOperationResult::kIsNotArc; + else if (UnexpectedEnd) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + else if (DataAfterEnd) + opRes = NExtract::NOperationResult::kDataAfterEnd; + else if (CrcError) + opRes = NExtract::NOperationResult::kCRCError; + else if (Unsupported) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else if (HeadersError) + opRes = NExtract::NOperationResult::kDataError; + else if (DataError) + opRes = NExtract::NOperationResult::kDataError; + else if (DecodeRes != SZ_OK) + opRes = NExtract::NOperationResult::kDataError; + else + opRes = NExtract::NOperationResult::kOK; + return opRes; +} + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { @@ -739,7 +687,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; - extractCallback->SetTotal(_stat.PhySize); + if (_phySize_Defined) + extractCallback->SetTotal(_stat.PhySize); + UInt64 currentTotalPacked = 0; RINOK(extractCallback->SetCompleted(¤tTotalPacked)); CMyComPtr<ISequentialOutStream> realOutStream; @@ -754,11 +704,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, extractCallback->PrepareOperation(askMode); - CVirtProgress_To_LocalProgress vp; - vp.lps = new CLocalProgress; - vp.progress = vp.lps; - vp.lps->Init(extractCallback, true); - + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> lpsRef = lps; + lps->Init(extractCallback, true); if (_needSeekToStart) { @@ -769,28 +717,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, 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; + CDecoder decoder; + RINOK(Decode2(_seqStream, realOutStream, decoder, lpsRef)); + Int32 opRes = decoder.Get_Extract_OperationResult(); realOutStream.Release(); return extractCallback->SetOperationResult(opRes); @@ -808,6 +737,8 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) { + COM_TRY_BEGIN + CSeqOutStreamWrap seqOutStream(outStream); if (numItems == 0) @@ -927,16 +858,37 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); return SResToHRESULT(res); } + if (indexInArchive != 0) return E_INVALIDARG; + + CMyComPtr<IArchiveUpdateCallbackFile> opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + if (opCallback) + { + RINOK(opCallback->ReportOperation(NEventIndexType::kInArcIndex, 0, NUpdateNotifyOp::kReplicate)) + } + if (_stream) + { + if (_phySize_Defined) + RINOK(updateCallback->SetTotal(_stat.PhySize)); RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); - return NCompress::CopyStream(_stream, outStream, NULL); + } + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(updateCallback, true); + + return NCompress::CopyStream(_stream, outStream, progress); + + COM_TRY_END } -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { COM_TRY_BEGIN + Init(); for (UInt32 i = 0; i < numProps; i++) { @@ -964,28 +916,25 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v return E_INVALIDARG; if (_methods.Size() == 1) { - UString &methodName = _methods[0].MethodName; + AString &methodName = _methods[0].MethodName; if (methodName.IsEmpty()) methodName = k_LZMA2_Name; - else if (!methodName.IsEqualToNoCase(k_LZMA2_Name)) + else if (!methodName.IsEqualTo_Ascii_NoCase(k_LZMA2_Name)) return E_INVALIDARG; } + return S_OK; + COM_TRY_END } #endif -IMP_CreateArcIn -IMP_CreateArcOut - -static CArcInfo g_ArcInfo = - { "xz", "xz txz", "* .tar", 0xC, - 6, { 0xFD, '7' , 'z', 'X', 'Z', 0 }, +REGISTER_ARC_IO( + "xz", "xz txz", "* .tar", 0xC, + XZ_SIG, 0, NArcInfoFlags::kKeepName, - REF_CreateArc_Pair }; - -REGISTER_ARC(xz) + NULL) }} diff --git a/CPP/7zip/Archive/XzHandler.h b/CPP/7zip/Archive/XzHandler.h new file mode 100644 index 00000000..4a59e356 --- /dev/null +++ b/CPP/7zip/Archive/XzHandler.h @@ -0,0 +1,65 @@ +// XzHandler.h + +#ifndef __XZ_HANDLER_H +#define __XZ_HANDLER_H + +#include "../../../C/Xz.h" + +#include "../ICoder.h" + +namespace NArchive { +namespace NXz { + +struct CXzUnpackerCPP +{ + Byte *InBuf; + Byte *OutBuf; + CXzUnpacker p; + + CXzUnpackerCPP(); + ~CXzUnpackerCPP(); +}; + +struct CStatInfo +{ + UInt64 InSize; + UInt64 OutSize; + UInt64 PhySize; + + UInt64 NumStreams; + UInt64 NumBlocks; + + bool UnpackSize_Defined; + + bool NumStreams_Defined; + bool NumBlocks_Defined; + + bool IsArc; + bool UnexpectedEnd; + bool DataAfterEnd; + bool Unsupported; + bool HeadersError; + bool DataError; + bool CrcError; + + CStatInfo() { Clear(); } + + void Clear(); +}; + +struct CDecoder: public CStatInfo +{ + CXzUnpackerCPP xzu; + SRes DecodeRes; // it's not HRESULT + + CDecoder(): DecodeRes(SZ_OK) {} + + /* Decode() can return ERROR code only if there is progress or stream error. + Decode() returns S_OK in case of xz decoding error, but DecodeRes and CStatInfo contain error information */ + HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, ICompressProgressInfo *compressProgress); + Int32 Get_Extract_OperationResult() const; +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/ZHandler.cpp b/CPP/7zip/Archive/ZHandler.cpp index 7635f22d..29934367 100644 --- a/CPP/7zip/Archive/ZHandler.cpp +++ b/CPP/7zip/Archive/ZHandler.cpp @@ -224,15 +224,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_END } -IMP_CreateArcIn +static const Byte k_Signature[] = { 0x1F, 0x9D }; -static CArcInfo g_ArcInfo = - { "Z", "z taz", "* .tar", 5, - 2, { 0x1F, 0x9D }, +REGISTER_ARC_I( + "Z", "z taz", "* .tar", 5, + k_Signature, 0, 0, - CreateArc, NULL, IsArc_Z }; - -REGISTER_ARC(Z) + IsArc_Z) }} diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp index 9a0d7515..c9c290aa 100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp @@ -3,6 +3,7 @@ #include "StdAfx.h" #include "../../../../C/7zCrc.h" +#include "../../../../C/Alloc.h" #include "../../../Windows/PropVariant.h" @@ -77,32 +78,46 @@ STDMETHODIMP CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStr CAddCommon::CAddCommon(const CCompressionMethodMode &options): - _options(options), - _copyCoderSpec(NULL), - _cryptoStreamSpec(0) - {} + _options(options), + _copyCoderSpec(NULL), + _cryptoStreamSpec(NULL), + _buf(NULL) + {} -static HRESULT GetStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC) +CAddCommon::~CAddCommon() { + MidFree(_buf); +} + +static const UInt32 kBufSize = ((UInt32)1 << 16); + +HRESULT CAddCommon::CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC) +{ + if (!_buf) + { + _buf = (Byte *)MidAlloc(kBufSize); + if (!_buf) + return E_OUTOFMEMORY; + } + UInt32 crc = CRC_INIT_VAL; - const UInt32 kBufSize = (1 << 14); - Byte buf[kBufSize]; for (;;) { UInt32 processed; - RINOK(inStream->Read(buf, kBufSize, &processed)); + RINOK(inStream->Read(_buf, kBufSize, &processed)); if (processed == 0) { resultCRC = CRC_GET_DIGEST(crc); return S_OK; } - crc = CrcUpdate(crc, buf, (size_t)processed); + crc = CrcUpdate(crc, _buf, (size_t)processed); } } HRESULT CAddCommon::Compress( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, IOutStream *outStream, + UInt32 /* fileTime */, ICompressProgressInfo *progress, CCompressingResult &opRes) { if (!inStream) @@ -111,13 +126,14 @@ HRESULT CAddCommon::Compress( return E_INVALIDARG; } - CSequentialInStreamWithCRC *inSecCrcStreamSpec = NULL; + // CSequentialInStreamWithCRC *inSecCrcStreamSpec = NULL; CInStreamWithCRC *inCrcStreamSpec = NULL; CMyComPtr<ISequentialInStream> inCrcStream; { CMyComPtr<IInStream> inStream2; - // we don't support stdin, since stream from stdin can require 64-bit size header - RINOK(inStream->QueryInterface(IID_IInStream, (void **)&inStream2)); + + inStream->QueryInterface(IID_IInStream, (void **)&inStream2); + if (inStream2) { inCrcStreamSpec = new CInStreamWithCRC; @@ -127,28 +143,29 @@ HRESULT CAddCommon::Compress( } else { + // we don't support stdin, since stream from stdin can require 64-bit size header + return E_NOTIMPL; + /* inSecCrcStreamSpec = new CSequentialInStreamWithCRC; inCrcStream = inSecCrcStreamSpec; inSecCrcStreamSpec->SetStream(inStream); inSecCrcStreamSpec->Init(); + */ } } unsigned numTestMethods = _options.MethodSequence.Size(); - if (numTestMethods > 1 || _options.PasswordIsDefined) - { - if (!inCrcStreamSpec) - { - if (_options.PasswordIsDefined) - return E_NOTIMPL; - numTestMethods = 1; - } - } + if (numTestMethods > 1 && !inCrcStreamSpec) + numTestMethods = 1; + + UInt32 crc = 0; + bool crc_IsCalculated = false; Byte method = 0; - COutStreamReleaser outStreamReleaser; + CFilterCoder::C_OutStream_Releaser outStreamReleaser; opRes.ExtractVersion = NFileHeader::NCompressionMethod::kExtractVersion_Default; + opRes.FileTimeWasUsed = false; for (unsigned i = 0; i < numTestMethods; i++) { @@ -164,7 +181,7 @@ HRESULT CAddCommon::Compress( if (!_cryptoStream) { - _cryptoStreamSpec = new CFilterCoder; + _cryptoStreamSpec = new CFilterCoder(true); _cryptoStream = _cryptoStreamSpec; } @@ -186,13 +203,32 @@ HRESULT CAddCommon::Compress( _cryptoStreamSpec->Filter = _filterSpec = new NCrypto::NZip::CEncoder; _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)); + + UInt32 check; + + // if (inCrcStreamSpec) + { + if (!crc_IsCalculated) + { + RINOK(CalcStreamCRC(inStream, crc)); + crc_IsCalculated = true; + RINOK(inCrcStreamSpec->Seek(0, STREAM_SEEK_SET, NULL)); + } + check = (crc >> 16); + } + /* + else + { + opRes.FileTimeWasUsed = true; + check = (fileTime & 0xFFFF); + } + */ + + RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check)); } RINOK(_cryptoStreamSpec->SetOutStream(outStream)); + RINOK(_cryptoStreamSpec->InitEncoder()); outStreamReleaser.FilterCoder = _cryptoStreamSpec; } @@ -250,7 +286,7 @@ HRESULT CAddCommon::Compress( } RINOK(CreateCoder( EXTERNAL_CODECS_LOC_VARS - methodId, _compressEncoder, true)); + methodId, true, _compressEncoder)); if (!_compressEncoder) return E_NOTIMPL; @@ -284,34 +320,42 @@ HRESULT CAddCommon::Compress( } } + if (_options.PasswordIsDefined) + { + RINOK(_cryptoStreamSpec->OutStreamFinish()); + + if (_options.IsAesMode) + { + RINOK(_filterAesSpec->WriteFooter(outStream)); + } + } + RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize)); - if (inCrcStreamSpec) + // if (inCrcStreamSpec) { opRes.CRC = inCrcStreamSpec->GetCRC(); opRes.UnpackSize = inCrcStreamSpec->GetSize(); } + /* else { opRes.CRC = inSecCrcStreamSpec->GetCRC(); opRes.UnpackSize = inSecCrcStreamSpec->GetSize(); } + */ if (_options.PasswordIsDefined) { if (opRes.PackSize < opRes.UnpackSize + - (_options.IsAesMode ? _filterAesSpec->GetHeaderSize() : NCrypto::NZip::kHeaderSize)) + (_options.IsAesMode ? _filterAesSpec->GetAddPackSize() : NCrypto::NZip::kHeaderSize)) break; } else if (opRes.PackSize < opRes.UnpackSize) break; } - - if (_options.PasswordIsDefined && _options.IsAesMode) - { - RINOK(_filterAesSpec->WriteFooter(outStream)); - RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize)); - } + + opRes.Method = method; return S_OK; } diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.h b/CPP/7zip/Archive/Zip/ZipAddCommon.h index e4c02db3..1e0c3bfa 100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.h +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.h @@ -26,6 +26,7 @@ struct CCompressingResult UInt32 CRC; UInt16 Method; Byte ExtractVersion; + bool FileTimeWasUsed; }; class CAddCommon @@ -43,11 +44,16 @@ class CAddCommon NCrypto::NZip::CEncoder *_filterSpec; NCrypto::NWzAes::CEncoder *_filterAesSpec; + Byte *_buf; + + HRESULT CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC); public: CAddCommon(const CCompressionMethodMode &options); + ~CAddCommon(); HRESULT Compress( DECL_EXTERNAL_CODECS_LOC_VARS ISequentialInStream *inStream, IOutStream *outStream, + UInt32 fileTime, ICompressProgressInfo *progress, CCompressingResult &operationResult); }; diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp index f556068c..3e29a880 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp @@ -28,6 +28,8 @@ #include "../Common/ItemNameUtils.h" #include "../Common/OutStreamWithCRC.h" +#include "../XzHandler.h" + #include "ZipHandler.h" using namespace NWindows; @@ -38,7 +40,7 @@ namespace NZip { static const CMethodId kMethodId_ZipBase = 0x040100; static const CMethodId kMethodId_BZip2 = 0x040202; -static const char *kHostOS[] = +static const char * const kHostOS[] = { "FAT" , "AMIGA" @@ -62,7 +64,7 @@ static const char *kHostOS[] = , "OS/X" }; -static const char *kMethods[] = +static const char * const kMethods[] = { "Store" , "Shrink" @@ -91,6 +93,7 @@ static const CIdToNamePair k_MethodIdNamePairs[] = { { NFileHeader::NCompressionMethod::kBZip2, "BZip2" }, { NFileHeader::NCompressionMethod::kLZMA, "LZMA" }, + { NFileHeader::NCompressionMethod::kXz, "xz" }, { NFileHeader::NCompressionMethod::kJpeg, "Jpeg" }, { NFileHeader::NCompressionMethod::kWavPack, "WavPack" }, { NFileHeader::NCompressionMethod::kPPMd, "PPMd" } @@ -156,14 +159,7 @@ CHandler::CHandler() static AString BytesToString(const CByteBuffer &data) { AString s; - unsigned size = (unsigned)data.Size(); - if (size > 0) - { - char *p = s.GetBuffer(size); - memcpy(p, (const Byte *)data, size); - p[size] = 0; - s.ReleaseBuffer(); - } + s.SetFrom_CalcLen((const char *)(const Byte *)data, (unsigned)data.Size()); return s; } @@ -220,6 +216,14 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) prop = v; break; } + + case kpidReadOnly: + { + if (m_Archive.IsOpen()) + if (!m_Archive.CanUpdate()) + prop = true; + break; + } } prop.Detach(value); COM_TRY_END @@ -334,12 +338,12 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidMethod: { - UInt16 methodId = item.Method; + unsigned id = item.Method; AString m; if (item.IsEncrypted()) { - if (methodId == NFileHeader::NCompressionMethod::kWzAES) + if (id == NFileHeader::NCompressionMethod::kWzAES) { m += kMethod_AES; CWzAesExtra aesField; @@ -349,7 +353,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val s[0] = '-'; ConvertUInt32ToString(((unsigned)aesField.Strength + 1) * 64 , s + 1); m += s; - methodId = aesField.Method; + id = aesField.Method; } } else if (item.IsStrongEncrypted()) @@ -381,19 +385,19 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { char temp[16]; const char *s = NULL; - if (methodId < ARRAY_SIZE(kMethods)) - s = kMethods[methodId]; + if (id < ARRAY_SIZE(kMethods)) + s = kMethods[id]; else { - s = FindNameForId(k_MethodIdNamePairs, ARRAY_SIZE(k_MethodIdNamePairs), methodId); + s = FindNameForId(k_MethodIdNamePairs, ARRAY_SIZE(k_MethodIdNamePairs), id); if (!s) { - ConvertUInt32ToString(methodId, temp); + ConvertUInt32ToString(id, temp); s = temp; } } m += s; - if (methodId == NFileHeader::NCompressionMethod::kLZMA && item.IsLzmaEOS()) + if (id == NFileHeader::NCompressionMethod::kLZMA && item.IsLzmaEOS()) m += ":EOS"; } @@ -507,9 +511,36 @@ HRESULT CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream * return Decoder->Code(inStream, outStream, NULL, outSize, progress); } + +class CXzDecoder: + public ICompressCoder, + public CMyUnknownImp +{ + NArchive::NXz::CDecoder _decoder; +public: + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + MY_UNKNOWN_IMP +}; + +HRESULT CXzDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) +{ + RINOK(_decoder.Decode(inStream, outStream, progress)); + Int32 opRes = _decoder.Get_Extract_OperationResult(); + if (opRes == NExtract::NOperationResult::kUnsupportedMethod) + return E_NOTIMPL; + if (opRes != NExtract::NOperationResult::kOK) + return S_FALSE; + return S_OK; +} + + struct CMethodItem { - UInt16 ZipMethod; + unsigned ZipMethod; CMyComPtr<ICompressCoder> Coder; }; @@ -559,12 +590,13 @@ HRESULT CZipDecoder::Decode( Int32 &res) { res = NExtract::NOperationResult::kDataError; - CInStreamReleaser inStreamReleaser; + CFilterCoder::C_InStream_Releaser inStreamReleaser; bool needCRC = true; bool wzAesMode = false; bool pkAesMode = false; - UInt16 methodId = item.Method; + unsigned id = item.Method; + if (item.IsEncrypted()) { if (item.IsStrongEncrypted()) @@ -580,7 +612,7 @@ HRESULT CZipDecoder::Decode( return S_OK; } } - if (!pkAesMode && methodId == NFileHeader::NCompressionMethod::kWzAES) + if (!pkAesMode && id == NFileHeader::NCompressionMethod::kWzAES) { CWzAesExtra aesField; if (item.CentralExtra.GetWzAes(aesField)) @@ -613,6 +645,7 @@ HRESULT CZipDecoder::Decode( } CMyComPtr<ICompressFilter> cryptoFilter; + if (item.IsEncrypted()) { if (wzAesMode) @@ -620,15 +653,18 @@ HRESULT CZipDecoder::Decode( CWzAesExtra aesField; if (!item.CentralExtra.GetWzAes(aesField)) return S_OK; - methodId = aesField.Method; + id = aesField.Method; if (!_wzAesDecoder) { _wzAesDecoderSpec = new NCrypto::NWzAes::CDecoder; _wzAesDecoder = _wzAesDecoderSpec; } cryptoFilter = _wzAesDecoder; - Byte properties = aesField.Strength; - RINOK(_wzAesDecoderSpec->SetDecoderProperties2(&properties, 1)); + if (!_wzAesDecoderSpec->SetKeyMode(aesField.Strength)) + { + res = NExtract::NOperationResult::kUnsupportedMethod; + return S_OK; + } } else if (pkAesMode) { @@ -648,6 +684,7 @@ HRESULT CZipDecoder::Decode( } cryptoFilter = _zipCryptoDecoder; } + CMyComPtr<ICryptoSetPassword> cryptoSetPassword; RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)); @@ -699,39 +736,41 @@ HRESULT CZipDecoder::Decode( unsigned m; for (m = 0; m < methodItems.Size(); m++) - if (methodItems[m].ZipMethod == methodId) + if (methodItems[m].ZipMethod == id) break; if (m == methodItems.Size()) { CMethodItem mi; - mi.ZipMethod = methodId; - if (methodId == NFileHeader::NCompressionMethod::kStored) + mi.ZipMethod = id; + if (id == NFileHeader::NCompressionMethod::kStored) mi.Coder = new NCompress::CCopyCoder; - else if (methodId == NFileHeader::NCompressionMethod::kShrunk) + else if (id == NFileHeader::NCompressionMethod::kShrunk) mi.Coder = new NCompress::NShrink::CDecoder; - else if (methodId == NFileHeader::NCompressionMethod::kImploded) + else if (id == NFileHeader::NCompressionMethod::kImploded) mi.Coder = new NCompress::NImplode::NDecoder::CCoder; - else if (methodId == NFileHeader::NCompressionMethod::kLZMA) + else if (id == NFileHeader::NCompressionMethod::kLZMA) mi.Coder = new CLzmaDecoder; - else if (methodId == NFileHeader::NCompressionMethod::kPPMd) + else if (id == NFileHeader::NCompressionMethod::kXz) + mi.Coder = new CXzDecoder; + else if (id == NFileHeader::NCompressionMethod::kPPMd) mi.Coder = new NCompress::NPpmdZip::CDecoder(true); else { CMethodId szMethodID; - if (methodId == NFileHeader::NCompressionMethod::kBZip2) + if (id == NFileHeader::NCompressionMethod::kBZip2) szMethodID = kMethodId_BZip2; else { - if (methodId > 0xFF) + if (id > 0xFF) { res = NExtract::NOperationResult::kUnsupportedMethod; return S_OK; } - szMethodID = kMethodId_ZipBase + (Byte)methodId; + szMethodID = kMethodId_ZipBase + (Byte)id; } - RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, mi.Coder, false)); + RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, false, mi.Coder)); if (mi.Coder == 0) { @@ -741,6 +780,7 @@ HRESULT CZipDecoder::Decode( } m = methodItems.Add(mi); } + ICompressCoder *coder = methodItems[m].Coder; { @@ -771,13 +811,23 @@ HRESULT CZipDecoder::Decode( { if (!filterStream) { - filterStreamSpec = new CFilterCoder; + filterStreamSpec = new CFilterCoder(false); filterStream = filterStreamSpec; } + filterStreamSpec->Filter = cryptoFilter; + if (wzAesMode) { result = _wzAesDecoderSpec->ReadHeader(inStream); + if (result == S_OK) + { + if (!_wzAesDecoderSpec->Init_and_CheckPassword()) + { + res = NExtract::NOperationResult::kWrongPassword; + return S_OK; + } + } } else if (pkAesMode) { @@ -785,43 +835,64 @@ HRESULT CZipDecoder::Decode( if (result == S_OK) { bool passwOK; - result = _pkAesDecoderSpec->CheckPassword(passwOK); + result = _pkAesDecoderSpec->Init_and_CheckPassword(passwOK); if (result == S_OK && !passwOK) - result = S_FALSE; + { + res = NExtract::NOperationResult::kWrongPassword; + return S_OK; + } } } else { result = _zipCryptoDecoderSpec->ReadHeader(inStream); + if (result == S_OK) + { + _zipCryptoDecoderSpec->Init_BeforeDecode(); + + /* Info-ZIP modification to ZipCrypto format: + if bit 3 of the general purpose bit flag is set, + it uses high byte of 16-bit File Time. + Info-ZIP code probably writes 2 bytes of File Time. + We check only 1 byte. */ + + // UInt32 v1 = GetUi16(_zipCryptoDecoderSpec->_header + NCrypto::NZip::kHeaderSize - 2); + // UInt32 v2 = (item.HasDescriptor() ? (item.Time & 0xFFFF) : (item.Crc >> 16)); + + Byte v1 = _zipCryptoDecoderSpec->_header[NCrypto::NZip::kHeaderSize - 1]; + Byte v2 = (Byte)(item.HasDescriptor() ? (item.Time >> 8) : (item.Crc >> 24)); + + if (v1 != v2) + { + res = NExtract::NOperationResult::kWrongPassword; + return S_OK; + } + } } if (result == S_OK) { - 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; + RINOK(filterStreamSpec->SetInStream(inStream)); + + /* IFilter::Init() does nothing in all zip crypto filters. + So we can call any Initialize function in CFilterCoder. */ + + RINOK(filterStreamSpec->Init_NoSubFilterInit()); + // RINOK(filterStreamSpec->SetOutStreamSize(NULL)); + inStreamNew = filterStream; - if (wzAesMode) - { - if (!_wzAesDecoderSpec->CheckPasswordVerifyCode()) - result = S_FALSE; - } } } else inStreamNew = inStream; + if (result == S_OK) result = coder->Code(inStreamNew, outStream, NULL, &item.Size, compressProgress); + if (result == S_FALSE) return S_OK; + if (result == E_NOTIMPL) { res = NExtract::NOperationResult::kUnsupportedMethod; @@ -830,6 +901,7 @@ HRESULT CZipDecoder::Decode( RINOK(result); } + bool crcOK = true; bool authOk = true; if (needCRC) diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h index 7f1d2eba..c2a362a7 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.h +++ b/CPP/7zip/Archive/Zip/ZipHandler.h @@ -33,7 +33,7 @@ public: INTERFACE_IInArchive(;) INTERFACE_IOutArchive(;) - STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps); + STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); DECL_ISetCompressCodecsInfo diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp index ae58cbe2..f1c8b227 100644 --- a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp @@ -34,15 +34,16 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) return S_OK; } -static bool IsAsciiString(const UString &s) +static bool IsSimpleAsciiString(const wchar_t *s) { - for (unsigned i = 0; i < s.Len(); i++) + for (;;) { - wchar_t c = s[i]; + wchar_t c = *s++; + if (c == 0) + return true; if (c < 0x20 || c > 0x7F) return false; } - return true; } #define COM_TRY_BEGIN2 try { @@ -180,11 +181,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (tryUtf8) { - 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; + ui.IsUtf8 = !name.IsAscii(); + ConvertUnicodeToUTF8(name, ui.Name); } if (ui.Name.Len() >= (1 << 16)) @@ -249,10 +247,10 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt if (!m_ForceAesMode) options.IsAesMode = thereAreAesUpdates; - if (!IsAsciiString((BSTR)password)) + if (!IsSimpleAsciiString(password)) return E_INVALIDARG; if (password) - options.Password = UnicodeStringToMultiByte((BSTR)password, CP_OEMCP); + options.Password = UnicodeStringToMultiByte((LPCOLESTR)password, CP_OEMCP); if (options.IsAesMode) { if (options.Password.Len() > NCrypto::NWzAes::kPasswordSizeMax) @@ -297,7 +295,7 @@ static const CMethodIndexToName k_SupportedMethods[] = { NFileHeader::NCompressionMethod::kPPMd, "ppmd" } }; -STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) +STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { InitMethodProps(); #ifndef _7ZIP_ST @@ -318,7 +316,7 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *v UInt32 level = 9; RINOK(ParsePropToUInt32(name.Ptr(1), prop, level)); _props.Level = level; - _props.MethodInfo.AddLevelProp(level); + _props.MethodInfo.AddProp_Level(level); } else if (name == L"m") { diff --git a/CPP/7zip/Archive/Zip/ZipHeader.h b/CPP/7zip/Archive/Zip/ZipHeader.h index 1391cdf4..c109992c 100644 --- a/CPP/7zip/Archive/Zip/ZipHeader.h +++ b/CPP/7zip/Archive/Zip/ZipHeader.h @@ -54,6 +54,8 @@ namespace NFileHeader kLZMA = 14, kTerse = 18, kLz77 = 19, + + kXz = 0x5F, kJpeg = 0x60, kWavPack = 0x61, kPPMd = 0x62, diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index 345fbf56..6f495305 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -348,7 +348,7 @@ HRESULT CInArchive::FindAndReadMarker(IInStream *stream, const UInt64 *searchLim return S_FALSE; } -HRESULT CInArchive::IncreaseRealPosition(UInt64 addValue) +HRESULT CInArchive::IncreaseRealPosition(Int64 addValue) { return Stream->Seek(addValue, STREAM_SEEK_CUR, &m_Position); } @@ -439,10 +439,9 @@ void CInArchive::ReadFileName(unsigned size, AString &s) s.Empty(); return; } - char *p = s.GetBuffer(size); + char *p = s.GetBuf(size); SafeReadBytes(p, size); - p[size] = 0; - s.ReleaseBuffer(); + s.ReleaseBuf_CalcLen(size); } bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extraBlock, @@ -556,7 +555,12 @@ bool CInArchive::ReadLocalItem(CItemEx &item) UInt32 diskStartNumber = 0; if (!ReadExtra(extraSize, item.LocalExtra, item.Size, item.PackSize, localHeaderOffset, diskStartNumber)) - return false; + { + /* Most of archives are OK for Extra. But there are some rare cases + that have error. And if error in first item, it can't open archive. + So we ignore that error */ + // return false; + } } if (!CheckDosTime(item.Time)) { @@ -650,6 +654,7 @@ HRESULT CInArchive::ReadLocalItemDescriptor(CItemEx &item) numBytesInBuffer += processedSize; if (numBytesInBuffer < kDataDescriptorSize) return S_FALSE; + UInt32 i; for (i = 0; i <= numBytesInBuffer - kDataDescriptorSize; i++) { @@ -666,10 +671,11 @@ HRESULT CInArchive::ReadLocalItemDescriptor(CItemEx &item) item.Crc = Get32(buf + i + 4); item.PackSize = descriptorPackSize; item.Size = Get32(buf + i + 12); - return IncreaseRealPosition(Int64(Int32(0 - (numBytesInBuffer - i - kDataDescriptorSize)))); + return IncreaseRealPosition((Int64)(Int32)(0 - (numBytesInBuffer - i - kDataDescriptorSize))); } } } + packedSize += i; unsigned j; for (j = 0; i < numBytesInBuffer; i++, j++) @@ -1262,7 +1268,10 @@ HRESULT CInArchive::ReadHeaders2(CObjectVector<CItemEx> &items, CProgressVirt *p (UInt32)ecd64.cdSize != (UInt32)cdSize || ((UInt32)(ecd64.cdStartOffset) != (UInt32)cdRelatOffset && (!items.IsEmpty()))) - return S_FALSE; + { + // return S_FALSE; + HeadersError = true; + } // printf("\nOpen OK"); return S_OK; diff --git a/CPP/7zip/Archive/Zip/ZipIn.h b/CPP/7zip/Archive/Zip/ZipIn.h index f6b349b1..734d3bcb 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.h +++ b/CPP/7zip/Archive/Zip/ZipIn.h @@ -25,7 +25,7 @@ public: UInt64 GetLocalFullSize() const { return LocalFullHeaderSize + PackSize + (HasDescriptor() ? kDataDescriptorSize : 0); } UInt64 GetDataPosition() const - { return LocalHeaderPos + LocalFullHeaderSize; }; + { return LocalHeaderPos + LocalFullHeaderSize; } }; struct CInArchiveInfo @@ -107,7 +107,7 @@ class CInArchive HRESULT Seek(UInt64 offset); HRESULT FindAndReadMarker(IInStream *stream, const UInt64 *searchHeaderSizeLimit); - HRESULT IncreaseRealPosition(UInt64 addValue); + HRESULT IncreaseRealPosition(Int64 addValue); HRESULT ReadBytes(void *data, UInt32 size, UInt32 *processedSize); void SafeReadBytes(void *data, unsigned size); diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp index ae88944d..f2ccc814 100644 --- a/CPP/7zip/Archive/Zip/ZipItem.cpp +++ b/CPP/7zip/Archive/Zip/ZipItem.cpp @@ -114,7 +114,7 @@ bool CItem::IsDir() const case NHostOS::kMVS: return false; // change it throw kUnknownAttributes; case NHostOS::kUnix: - return (highAttrib & NUnixAttrib::kIFDIR) != 0; + return ((highAttrib & NUnixAttrib::kIFMT) == NUnixAttrib::kIFDIR); default: return false; } @@ -130,6 +130,11 @@ UInt32 CItem::GetWinAttrib() const if (FromCentral) winAttrib = ExternalAttrib; break; + case NHostOS::kUnix: + // do we need to clear 16 low bits in this case? + if (FromCentral) + winAttrib = ExternalAttrib & 0xFFFF0000; + break; } if (IsDir()) // test it; winAttrib |= FILE_ATTRIBUTE_DIRECTORY; diff --git a/CPP/7zip/Archive/Zip/ZipItem.h b/CPP/7zip/Archive/Zip/ZipItem.h index d50c3ae9..98afdf1d 100644 --- a/CPP/7zip/Archive/Zip/ZipItem.h +++ b/CPP/7zip/Archive/Zip/ZipItem.h @@ -179,9 +179,12 @@ struct CExtraBlock void RemoveUnknownSubBlocks() { - for (int i = SubBlocks.Size() - 1; i >= 0; i--) + for (unsigned i = SubBlocks.Size(); i != 0;) + { + i--; if (SubBlocks[i].ID != NFileHeader::NExtraID::kWzAES) SubBlocks.Delete(i); + } } }; @@ -204,8 +207,8 @@ public: bool IsUtf8() const { return (Flags & NFileHeader::NFlags::kUtf8) != 0; } bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kEncrypted) != 0; } - bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; }; - bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || Method == NFileHeader::NCompressionMethod::kWzAES); }; + bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; } + bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || Method == NFileHeader::NCompressionMethod::kWzAES); } bool IsLzmaEOS() const { return (Flags & NFileHeader::NFlags::kLzmaEOS) != 0; } bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; } @@ -237,6 +240,7 @@ public: void ClearFlags() { Flags = 0; } void SetEncrypted(bool encrypted) { SetFlag(NFileHeader::NFlags::kEncrypted, encrypted); } void SetUtf8(bool isUtf8) { SetFlag(NFileHeader::NFlags::kUtf8, isUtf8); } + void SetDescriptorMode(bool useDescriptor) { SetFlag(NFileHeader::NFlags::kDescriptorUsedMask, useDescriptor); } UINT GetCodePage() const { return CP_OEMCP; } }; @@ -277,6 +281,7 @@ public: void GetUnicodeString(const AString &s, UString &res, bool useSpecifiedCodePage, UINT codePage) const { bool isUtf8 = IsUtf8(); + bool ignore_Utf8_Errors = true; #ifdef _WIN32 if (!isUtf8) @@ -287,14 +292,15 @@ public: { /* 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? */ + Do we need to do it in POSIX version also? */ isUtf8 = true; + ignore_Utf8_Errors = false; } } #endif if (isUtf8) - if (ConvertUTF8ToUnicode(s, res)) + if (ConvertUTF8ToUnicode(s, res) || ignore_Utf8_Errors) return; MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage()); } diff --git a/CPP/7zip/Archive/Zip/ZipOut.h b/CPP/7zip/Archive/Zip/ZipOut.h index eaaa0320..056d0d09 100644 --- a/CPP/7zip/Archive/Zip/ZipOut.h +++ b/CPP/7zip/Archive/Zip/ZipOut.h @@ -63,7 +63,7 @@ public: HRESULT Create(IOutStream *outStream); void MoveCurPos(UInt64 distanceToMove); - UInt64 GetCurPos() const { return m_CurPos; }; + UInt64 GetCurPos() const { return m_CurPos; } void SeekToCurPos(); diff --git a/CPP/7zip/Archive/Zip/ZipRegister.cpp b/CPP/7zip/Archive/Zip/ZipRegister.cpp index 545e76c6..2be783e6 100644 --- a/CPP/7zip/Archive/Zip/ZipRegister.cpp +++ b/CPP/7zip/Archive/Zip/ZipRegister.cpp @@ -9,23 +9,18 @@ namespace NArchive { namespace NZip { -IMP_CreateArcIn -IMP_CreateArcOut - -static CArcInfo g_ArcInfo = - { "zip", "zip zipx jar xpi odt ods docx xlsx epub", 0, 1, - 3 + 4 + 4 + 6, - { +static const Byte k_Signature[] = { 4, 0x50, 0x4B, 0x03, 0x04, 4, 0x50, 0x4B, 0x05, 0x06, - 6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B, - }, + 6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B }; + +REGISTER_ARC_IO( + "zip", "zip zipx jar xpi odt ods docx xlsx epub", 0, 1, + k_Signature, 0, NArcInfoFlags::kFindSignature | NArcInfoFlags::kMultiSignature | NArcInfoFlags::kUseGlobalOffset, - REF_CreateArc_Pair, IsArc_Zip }; - -REGISTER_ARC(Zip) - + IsArc_Zip) + }} diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index 97cce5ac..9a9526cc 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -65,6 +65,7 @@ static void SetFileHeader( COutArchive &archive, const CCompressionMethodMode &options, const CUpdateItem &ui, + // bool isSeqMode, CItemOut &item) { item.Size = ui.Size; @@ -95,6 +96,8 @@ static void SetFileHeader( item.InternalAttrib = 0; // test it item.SetEncrypted(!isDir && options.PasswordIsDefined); + // item.SetDescriptorMode(isSeqMode); + if (isDir) { item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir; @@ -156,12 +159,14 @@ struct CThreadInfo bool IsFree; UInt32 UpdateIndex; + UInt32 FileTime; CThreadInfo(const CCompressionMethodMode &options): ExitThread(false), ProgressSpec(0), OutStreamSpec(0), - Coder(options) + Coder(options), + FileTime(0) {} HRESULT CreateEvents() @@ -192,9 +197,11 @@ void CThreadInfo::WaitAndCode() CompressEvent.Lock(); if (ExitThread) return; + Result = Coder.Compress( EXTERNAL_CODECS_LOC_VARS - InStream, OutStream, Progress, CompressingResult); + InStream, OutStream, FileTime, Progress, CompressingResult); + if (Result == S_OK && Progress) Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize); CompressionCompletedEvent.Set(); @@ -254,7 +261,7 @@ public: MY_UNKNOWN_IMP void Create(IProgress *progress, bool inSizeIsMain); void SetProgressOffset(UInt64 progressOffset); - HRESULT SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize); + HRESULT SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize); STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); }; @@ -274,16 +281,16 @@ void CMtProgressMixer2::SetProgressOffset(UInt64 progressOffset) CriticalSection.Leave(); } -HRESULT CMtProgressMixer2::SetRatioInfo(int index, const UInt64 *inSize, const UInt64 *outSize) +HRESULT CMtProgressMixer2::SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize) { NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); if (index == 0 && RatioProgress) { RINOK(RatioProgress->SetRatioInfo(inSize, outSize)); } - if (inSize != 0) + if (inSize) InSizes[index] = *inSize; - if (outSize != 0) + if (outSize) OutSizes[index] = *outSize; UInt64 v = ProgressOffset + (_inSizeIsMain ? (InSizes[0] + InSizes[1]) : @@ -332,8 +339,16 @@ static HRESULT UpdateItemOldData( CItemOut &item, /* bool izZip64, */ ICompressProgressInfo *progress, + IArchiveUpdateCallbackFile *opCallback, UInt64 &complexity) { + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc, + NUpdateNotifyOp::kReplicate)) + } + if (ui.NewProps) { if (item.HasDescriptor()) @@ -396,7 +411,8 @@ static HRESULT Update2St( const CObjectVector<CUpdateItem> &updateItems, const CCompressionMethodMode *options, const CByteBuffer *comment, - IArchiveUpdateCallback *updateCallback) + IArchiveUpdateCallback *updateCallback, + IArchiveUpdateCallbackFile *opCallback) { CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; @@ -445,15 +461,37 @@ static HRESULT Update2St( if (!fileInStream) return E_INVALIDARG; + // bool isSeqMode = false; + /* + { + CMyComPtr<IInStream> inStream2; + fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2); + isSeqMode = (inStream2 == NULL); + } + */ + // file Size can be 64-bit !!! SetFileHeader(archive, *options, ui, item); archive.PrepareWriteCompressedData(item.Name.Len(), ui.Size, options->IsRealAesMode()); CCompressingResult compressingResult; CMyComPtr<IOutStream> outStream; archive.CreateStreamForCompressing(&outStream); + RINOK(compressor.Compress( EXTERNAL_CODECS_LOC_VARS - fileInStream, outStream, progress, compressingResult)); + fileInStream, outStream, + ui.Time, + progress, compressingResult)); + + if (compressingResult.FileTimeWasUsed) + { + /* + if (!item.HasDescriptor()) + return E_FAIL; + */ + item.SetDescriptorMode(true); + } + SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); archive.WriteLocalHeader_And_SeekToNextFile(item); RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); @@ -465,13 +503,14 @@ static HRESULT Update2St( { UInt64 complexity = 0; lps->SendRatio = false; - RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, complexity)); + RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity)); lps->SendRatio = true; lps->ProgressOffset += complexity; } items.Add(item); lps->ProgressOffset += kLocalHeaderSize; } + lps->InSize = unpackSizeTotal; lps->OutSize = packSizeTotal; RINOK(lps->SetCur()); @@ -489,6 +528,9 @@ static HRESULT Update2( const CByteBuffer *comment, IArchiveUpdateCallback *updateCallback) { + CMyComPtr<IArchiveUpdateCallbackFile> opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + UInt64 complexity = 0; UInt64 numFilesToCompress = 0; UInt64 numBytesToCompress = 0; @@ -542,6 +584,7 @@ static HRESULT Update2( numThreads = MAXIMUM_WAIT_OBJECTS; if (numThreads < 1) numThreads = 1; + const size_t kMemPerThread = (1 << 25); const size_t kBlockSize = 1 << 16; @@ -558,7 +601,7 @@ static HRESULT Update2( { // fixed for 9.31. bzip2 default is just one thread. if (options2.NumThreadsWasChanged || method == NFileHeader::NCompressionMethod::kBZip2) - options2.MethodInfo.AddNumThreadsProp(numThreads); + options2.MethodInfo.AddProp_NumThreads(numThreads); } } else @@ -577,7 +620,7 @@ static HRESULT Update2( numBZip2Threads = 32; if (averageNumberOfBlocks < numBZip2Threads) numBZip2Threads = (UInt32)averageNumberOfBlocks; - options2.MethodInfo.AddNumThreadsProp(numBZip2Threads); + options2.MethodInfo.AddProp_NumThreads(numBZip2Threads); } numThreads /= numBZip2Threads; } @@ -599,7 +642,7 @@ static HRESULT Update2( return Update2St( EXTERNAL_CODECS_LOC_VARS archive, inArchive, - inputItems, updateItems, &options2, comment, updateCallback); + inputItems, updateItems, &options2, comment, updateCallback, opCallback); #ifndef _7ZIP_ST @@ -643,6 +686,7 @@ static HRESULT Update2( threadInfo.ProgressSpec = new CMtCompressProgress(); threadInfo.Progress = threadInfo.ProgressSpec; threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, (int)i); + threadInfo.FileTime = 0; // fix it ! RINOK(threadInfo.CreateThread()); } } @@ -784,7 +828,15 @@ static HRESULT Update2( DWORD result = ::WaitForMultipleObjects(compressingCompletedEvents.Size(), &compressingCompletedEvents.Front(), FALSE, INFINITE); - int t = (int)(result - WAIT_OBJECT_0); + if (result == WAIT_FAILED) + { + DWORD lastError = GetLastError(); + return lastError != 0 ? lastError : E_FAIL; + } + unsigned t = (unsigned)(result - WAIT_OBJECT_0); + if (t >= compressingCompletedEvents.Size()) + return E_FAIL; + CThreadInfo &threadInfo = threads.Threads[threadIndices[t]]; threadInfo.InStream.Release(); threadInfo.IsFree = true; @@ -813,7 +865,7 @@ static HRESULT Update2( } else { - RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, complexity)); + RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity)); } items.Add(item); complexity += kLocalHeaderSize; |