diff options
author | kh1 <karsten.heimrich@nokia.com> | 2012-03-15 14:53:47 +0100 |
---|---|---|
committer | Karsten Heimrich <karsten.heimrich@nokia.com> | 2012-03-19 16:14:04 +0100 |
commit | be3b47d0d504a3409ce66bd77bb8c0acff87c4f5 (patch) | |
tree | 09dfb02d484a4f395991972b828da71400fb761a /src/libs/7zip/win/CPP | |
parent | 9fd62353cf7f973d78cd2093328ac15b5c4980b6 (diff) |
Reorganize the tree, have better ifw.pri. Shadow build support.
Change-Id: I01fb12537f863ed0744979973c7e4153889cc5cb
Reviewed-by: Tim Jenssen <tim.jenssen@nokia.com>
Diffstat (limited to 'src/libs/7zip/win/CPP')
566 files changed, 98674 insertions, 0 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.cpp new file mode 100644 index 000000000..6774fc482 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.cpp @@ -0,0 +1,3 @@ +// CompressionMethod.cpp + +#include "StdAfx.h" diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.h new file mode 100644 index 000000000..55bbc68ee --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zCompressionMode.h @@ -0,0 +1,50 @@ +// 7zCompressionMode.h + +#ifndef __7Z_COMPRESSION_MODE_H +#define __7Z_COMPRESSION_MODE_H + +#include "../../../Common/MyString.h" + +#include "../../../Windows/PropVariant.h" + +#include "../../Common/MethodProps.h" + +namespace NArchive { +namespace N7z { + +struct CMethodFull: public CMethod +{ + UInt32 NumInStreams; + UInt32 NumOutStreams; + bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); } +}; + +struct CBind +{ + UInt32 InCoder; + UInt32 InStream; + UInt32 OutCoder; + UInt32 OutStream; +}; + +struct CCompressionMethodMode +{ + CObjectVector<CMethodFull> Methods; + CRecordVector<CBind> Binds; + #ifndef _7ZIP_ST + UInt32 NumThreads; + #endif + bool PasswordIsDefined; + UString Password; + + bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); } + CCompressionMethodMode(): PasswordIsDefined(false) + #ifndef _7ZIP_ST + , NumThreads(1) + #endif + {} +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.cpp new file mode 100644 index 000000000..425a34157 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.cpp @@ -0,0 +1,332 @@ +// 7zDecode.cpp + +#include "StdAfx.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/LockedStream.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamObjects.h" + +#include "7zDecode.h" + +namespace NArchive { +namespace N7z { + +static void ConvertFolderItemInfoToBindInfo(const CFolder &folder, + CBindInfoEx &bindInfo) +{ + bindInfo.Clear(); + int i; + for (i = 0; i < folder.BindPairs.Size(); i++) + { + NCoderMixer::CBindPair bindPair; + bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex; + bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex; + bindInfo.BindPairs.Add(bindPair); + } + UInt32 outStreamIndex = 0; + for (i = 0; i < folder.Coders.Size(); i++) + { + NCoderMixer::CCoderStreamsInfo coderStreamsInfo; + const CCoderInfo &coderInfo = folder.Coders[i]; + coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams; + coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams; + bindInfo.Coders.Add(coderStreamsInfo); + bindInfo.CoderMethodIDs.Add(coderInfo.MethodID); + for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++) + if (folder.FindBindPairForOutStream(outStreamIndex) < 0) + bindInfo.OutStreams.Add(outStreamIndex); + } + for (i = 0; i < folder.PackStreams.Size(); i++) + bindInfo.InStreams.Add((UInt32)folder.PackStreams[i]); +} + +static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1, + const NCoderMixer::CCoderStreamsInfo &a2) +{ + return (a1.NumInStreams == a2.NumInStreams) && + (a1.NumOutStreams == a2.NumOutStreams); +} + +static bool AreBindPairsEqual(const NCoderMixer::CBindPair &a1, const NCoderMixer::CBindPair &a2) +{ + return (a1.InIndex == a2.InIndex) && + (a1.OutIndex == a2.OutIndex); +} + +static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2) +{ + if (a1.Coders.Size() != a2.Coders.Size()) + return false; + int i; + 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()) + return false; + for (i = 0; i < a1.BindPairs.Size(); i++) + if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[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()) + return false; + if (a1.OutStreams.Size() != a2.OutStreams.Size()) + return false; + return true; +} + +CDecoder::CDecoder(bool multiThread) +{ + #ifndef _ST_MODE + multiThread = true; + #endif + _multiThread = multiThread; + _bindInfoExPrevIsDefined = false; +} + +HRESULT CDecoder::Decode( + DECL_EXTERNAL_CODECS_LOC_VARS + IInStream *inStream, + UInt64 startPos, + const UInt64 *packSizes, + const CFolder &folderInfo, + ISequentialOutStream *outStream, + ICompressProgressInfo *compressProgress + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined + #endif + #if !defined(_7ZIP_ST) && !defined(_SFX) + , bool mtMode, UInt32 numThreads + #endif + ) +{ + if (!folderInfo.CheckStructure()) + return E_NOTIMPL; + #ifndef _NO_CRYPTO + passwordIsDefined = false; + #endif + CObjectVector< CMyComPtr<ISequentialInStream> > inStreams; + + CLockedInStream lockedInStream; + lockedInStream.Init(inStream); + + for (int j = 0; j < folderInfo.PackStreams.Size(); j++) + { + CLockedSequentialInStreamImp *lockedStreamImpSpec = new + CLockedSequentialInStreamImp; + CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec; + lockedStreamImpSpec->Init(&lockedInStream, startPos); + startPos += packSizes[j]; + + CLimitedSequentialInStream *streamSpec = new + CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream = streamSpec; + streamSpec->SetStream(lockedStreamImp); + streamSpec->Init(packSizes[j]); + inStreams.Add(inStream); + } + + int numCoders = folderInfo.Coders.Size(); + + CBindInfoEx bindInfo; + ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo); + bool createNewCoders; + if (!_bindInfoExPrevIsDefined) + createNewCoders = true; + else + createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev); + if (createNewCoders) + { + int i; + _decoders.Clear(); + // _decoders2.Clear(); + + _mixerCoder.Release(); + + if (_multiThread) + { + _mixerCoderMTSpec = new NCoderMixer::CCoderMixer2MT; + _mixerCoder = _mixerCoderMTSpec; + _mixerCoderCommon = _mixerCoderMTSpec; + } + else + { + #ifdef _ST_MODE + _mixerCoderSTSpec = new NCoderMixer::CCoderMixer2ST; + _mixerCoder = _mixerCoderSTSpec; + _mixerCoderCommon = _mixerCoderSTSpec; + #endif + } + RINOK(_mixerCoderCommon->SetBindInfo(bindInfo)); + + for (i = 0; i < numCoders; i++) + { + const CCoderInfo &coderInfo = folderInfo.Coders[i]; + + + CMyComPtr<ICompressCoder> decoder; + CMyComPtr<ICompressCoder2> decoder2; + RINOK(CreateCoder( + EXTERNAL_CODECS_LOC_VARS + coderInfo.MethodID, decoder, decoder2, false)); + CMyComPtr<IUnknown> decoderUnknown; + if (coderInfo.IsSimpleCoder()) + { + if (decoder == 0) + return E_NOTIMPL; + + decoderUnknown = (IUnknown *)decoder; + + if (_multiThread) + _mixerCoderMTSpec->AddCoder(decoder); + #ifdef _ST_MODE + else + _mixerCoderSTSpec->AddCoder(decoder, false); + #endif + } + else + { + if (decoder2 == 0) + return E_NOTIMPL; + decoderUnknown = (IUnknown *)decoder2; + if (_multiThread) + _mixerCoderMTSpec->AddCoder2(decoder2); + #ifdef _ST_MODE + else + _mixerCoderSTSpec->AddCoder2(decoder2, false); + #endif + } + _decoders.Add(decoderUnknown); + #ifdef EXTERNAL_CODECS + CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; + decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo)); + } + #endif + } + _bindInfoExPrev = bindInfo; + _bindInfoExPrevIsDefined = true; + } + int i; + _mixerCoderCommon->ReInit(); + + UInt32 packStreamIndex = 0, unpackStreamIndex = 0; + UInt32 coderIndex = 0; + // UInt32 coder2Index = 0; + + for (i = 0; i < numCoders; i++) + { + const CCoderInfo &coderInfo = folderInfo.Coders[i]; + CMyComPtr<IUnknown> &decoder = _decoders[coderIndex]; + + { + CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties; + decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); + if (setDecoderProperties) + { + const CByteBuffer &props = coderInfo.Props; + size_t size = props.GetCapacity(); + if (size > 0xFFFFFFFF) + return E_NOTIMPL; + // if (size > 0) + { + RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size)); + } + } + } + + #if !defined(_7ZIP_ST) && !defined(_SFX) + if (mtMode) + { + CMyComPtr<ICompressSetCoderMt> setCoderMt; + decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); + if (setCoderMt) + { + RINOK(setCoderMt->SetNumberOfThreads(numThreads)); + } + } + #endif + + #ifndef _NO_CRYPTO + { + CMyComPtr<ICryptoSetPassword> cryptoSetPassword; + decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); + if (cryptoSetPassword) + { + if (getTextPassword == 0) + return E_FAIL; + CMyComBSTR passwordBSTR; + RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR)); + CByteBuffer buffer; + passwordIsDefined = true; + const UString password(passwordBSTR); + const UInt32 sizeInBytes = password.Length() * 2; + buffer.SetCapacity(sizeInBytes); + for (int i = 0; i < password.Length(); i++) + { + wchar_t c = password[i]; + ((Byte *)buffer)[i * 2] = (Byte)c; + ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); + } + RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes)); + } + } + #endif + + coderIndex++; + + UInt32 numInStreams = (UInt32)coderInfo.NumInStreams; + UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams; + CRecordVector<const UInt64 *> packSizesPointers; + CRecordVector<const UInt64 *> unpackSizesPointers; + packSizesPointers.Reserve(numInStreams); + unpackSizesPointers.Reserve(numOutStreams); + UInt32 j; + for (j = 0; j < numOutStreams; j++, unpackStreamIndex++) + unpackSizesPointers.Add(&folderInfo.UnpackSizes[unpackStreamIndex]); + + for (j = 0; j < numInStreams; j++, packStreamIndex++) + { + int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex); + if (bindPairIndex >= 0) + packSizesPointers.Add( + &folderInfo.UnpackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]); + else + { + int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex); + if (index < 0) + return E_FAIL; + packSizesPointers.Add(&packSizes[index]); + } + } + + _mixerCoderCommon->SetCoderInfo(i, + &packSizesPointers.Front(), + &unpackSizesPointers.Front()); + } + UInt32 mainCoder, temp; + bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp); + + if (_multiThread) + _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder); + /* + else + _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);; + */ + + if (numCoders == 0) + return 0; + CRecordVector<ISequentialInStream *> inStreamPointers; + inStreamPointers.Reserve(inStreams.Size()); + for (i = 0; i < inStreams.Size(); i++) + inStreamPointers.Add(inStreams[i]); + ISequentialOutStream *outStreamPointer = outStream; + return _mixerCoder->Code(&inStreamPointers.Front(), NULL, + inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress); +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.h new file mode 100644 index 000000000..d8a424a36 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zDecode.h @@ -0,0 +1,68 @@ +// 7zDecode.h + +#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 "7zItem.h" + +namespace NArchive { +namespace N7z { + +struct CBindInfoEx: public NCoderMixer::CBindInfo +{ + CRecordVector<CMethodId> CoderMethodIDs; + void Clear() + { + CBindInfo::Clear(); + CoderMethodIDs.Clear(); + } +}; + +class CDecoder +{ + bool _bindInfoExPrevIsDefined; + CBindInfoEx _bindInfoExPrev; + + bool _multiThread; + #ifdef _ST_MODE + NCoderMixer::CCoderMixer2ST *_mixerCoderSTSpec; + #endif + NCoderMixer::CCoderMixer2MT *_mixerCoderMTSpec; + NCoderMixer::CCoderMixer2 *_mixerCoderCommon; + + CMyComPtr<ICompressCoder2> _mixerCoder; + CObjectVector<CMyComPtr<IUnknown> > _decoders; + // CObjectVector<CMyComPtr<ICompressCoder2> > _decoders2; +public: + CDecoder(bool multiThread); + HRESULT Decode( + DECL_EXTERNAL_CODECS_LOC_VARS + IInStream *inStream, + UInt64 startPos, + const UInt64 *packSizes, + const CFolder &folder, + ISequentialOutStream *outStream, + ICompressProgressInfo *compressProgress + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getTextPasswordSpec, bool &passwordIsDefined + #endif + #if !defined(_7ZIP_ST) && !defined(_SFX) + , bool mtMode, UInt32 numThreads + #endif + ); +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.cpp new file mode 100644 index 000000000..87996bc0e --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.cpp @@ -0,0 +1,444 @@ +// 7zEncode.cpp + +#include "StdAfx.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/FilterCoder.h" +#include "../../Common/LimitedStreams.h" +#include "../../Common/InOutTempBuffer.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamObjects.h" + +#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) +{ + folder.Coders.Clear(); + // bindInfo.CoderMethodIDs.Clear(); + // folder.OutStreams.Clear(); + folder.PackStreams.Clear(); + folder.BindPairs.Clear(); + int i; + for (i = 0; i < bindInfo.BindPairs.Size(); i++) + { + CBindPair bindPair; + bindPair.InIndex = bindInfo.BindPairs[i].InIndex; + bindPair.OutIndex = bindInfo.BindPairs[i].OutIndex; + folder.BindPairs.Add(bindPair); + } + for (i = 0; i < bindInfo.Coders.Size(); i++) + { + CCoderInfo coderInfo; + const NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i]; + coderInfo.NumInStreams = coderStreamsInfo.NumInStreams; + coderInfo.NumOutStreams = coderStreamsInfo.NumOutStreams; + coderInfo.MethodID = decompressionMethods[i]; + folder.Coders.Add(coderInfo); + } + for (i = 0; i < bindInfo.InStreams.Size(); i++) + folder.PackStreams.Add(bindInfo.InStreams[i]); +} + +HRESULT CEncoder::CreateMixerCoder( + DECL_EXTERNAL_CODECS_LOC_VARS + const UInt64 *inSizeForReduce) +{ + _mixerCoderSpec = new NCoderMixer::CCoderMixer2MT; + _mixerCoder = _mixerCoderSpec; + RINOK(_mixerCoderSpec->SetBindInfo(_bindInfo)); + for (int i = 0; i < _options.Methods.Size(); i++) + { + const CMethodFull &methodFull = _options.Methods[i]; + _codersInfo.Add(CCoderInfo()); + CCoderInfo &encodingInfo = _codersInfo.Back(); + encodingInfo.MethodID = methodFull.Id; + CMyComPtr<ICompressCoder> encoder; + CMyComPtr<ICompressCoder2> encoder2; + + + RINOK(CreateCoder( + EXTERNAL_CODECS_LOC_VARS + methodFull.Id, encoder, encoder2, true)); + + if (!encoder && !encoder2) + return E_FAIL; + + CMyComPtr<IUnknown> encoderCommon = encoder ? (IUnknown *)encoder : (IUnknown *)encoder2; + + #ifndef _7ZIP_ST + { + CMyComPtr<ICompressSetCoderMt> setCoderMt; + encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); + if (setCoderMt) + { + RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads)); + } + } + #endif + + + RINOK(SetMethodProperties(methodFull, inSizeForReduce, encoderCommon)); + + /* + CMyComPtr<ICryptoResetSalt> resetSalt; + encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt); + if (resetSalt != NULL) + { + resetSalt->ResetSalt(); + } + */ + + #ifdef EXTERNAL_CODECS + CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; + encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecsInfo)); + } + #endif + + CMyComPtr<ICryptoSetPassword> cryptoSetPassword; + encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); + + if (cryptoSetPassword) + { + CByteBuffer buffer; + const UInt32 sizeInBytes = _options.Password.Length() * 2; + buffer.SetCapacity(sizeInBytes); + for (int i = 0; i < _options.Password.Length(); i++) + { + wchar_t c = _options.Password[i]; + ((Byte *)buffer)[i * 2] = (Byte)c; + ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); + } + RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, sizeInBytes)); + } + + if (encoder) + _mixerCoderSpec->AddCoder(encoder); + else + _mixerCoderSpec->AddCoder2(encoder2); + } + return S_OK; +} + +HRESULT CEncoder::Encode( + DECL_EXTERNAL_CODECS_LOC_VARS + ISequentialInStream *inStream, + const UInt64 *inStreamSize, const UInt64 *inSizeForReduce, + CFolder &folderItem, + ISequentialOutStream *outStream, + CRecordVector<UInt64> &packSizes, + ICompressProgressInfo *compressProgress) +{ + RINOK(EncoderConstr()); + + if (_mixerCoderSpec == NULL) + { + RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce)); + } + _mixerCoderSpec->ReInit(); + // _mixerCoderSpec->SetCoderInfo(0, NULL, NULL, progress); + + CObjectVector<CInOutTempBuffer> inOutTempBuffers; + CObjectVector<CSequentialOutTempBufferImp *> tempBufferSpecs; + CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers; + int numMethods = _bindInfo.Coders.Size(); + int i; + for (i = 1; i < _bindInfo.OutStreams.Size(); i++) + { + inOutTempBuffers.Add(CInOutTempBuffer()); + inOutTempBuffers.Back().Create(); + inOutTempBuffers.Back().InitWriting(); + } + for (i = 1; i < _bindInfo.OutStreams.Size(); i++) + { + CSequentialOutTempBufferImp *tempBufferSpec = new CSequentialOutTempBufferImp; + CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec; + tempBufferSpec->Init(&inOutTempBuffers[i - 1]); + tempBuffers.Add(tempBuffer); + tempBufferSpecs.Add(tempBufferSpec); + } + + for (i = 0; i < numMethods; i++) + _mixerCoderSpec->SetCoderInfo(i, NULL, NULL); + + if (_bindInfo.InStreams.IsEmpty()) + return E_FAIL; + UInt32 mainCoderIndex, mainStreamIndex; + _bindInfo.FindInStream(_bindInfo.InStreams[0], mainCoderIndex, mainStreamIndex); + + if (inStreamSize != NULL) + { + 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); + } + + + // UInt64 outStreamStartPos; + // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &outStreamStartPos)); + + CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2; + CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec; + CSequentialOutStreamSizeCount *outStreamSizeCountSpec = new CSequentialOutStreamSizeCount; + CMyComPtr<ISequentialOutStream> outStreamSizeCount = outStreamSizeCountSpec; + + inStreamSizeCountSpec->Init(inStream); + outStreamSizeCountSpec->SetStream(outStream); + outStreamSizeCountSpec->Init(); + + CRecordVector<ISequentialInStream *> inStreamPointers; + CRecordVector<ISequentialOutStream *> outStreamPointers; + inStreamPointers.Add(inStreamSizeCount); + outStreamPointers.Add(outStreamSizeCount); + for (i = 1; i < _bindInfo.OutStreams.Size(); i++) + outStreamPointers.Add(tempBuffers[i - 1]); + + for (i = 0; i < _codersInfo.Size(); i++) + { + CCoderInfo &encodingInfo = _codersInfo[i]; + + CMyComPtr<ICryptoResetInitVector> resetInitVector; + _mixerCoderSpec->_coders[i].QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector); + if (resetInitVector != NULL) + { + resetInitVector->ResetInitVector(); + } + + CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties; + _mixerCoderSpec->_coders[i].QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties); + if (writeCoderProperties != NULL) + { + CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream; + CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); + outStreamSpec->Init(); + writeCoderProperties->WriteCoderProperties(outStream); + outStreamSpec->CopyToBuffer(encodingInfo.Props); + } + } + + UInt32 progressIndex = mainCoderIndex; + + for (i = 0; i + 1 < _codersInfo.Size(); i++) + { + UInt64 m = _codersInfo[i].MethodID; + if (m == k_Delta || m == k_BCJ || m == k_BCJ2) + progressIndex = i + 1; + } + + _mixerCoderSpec->SetProgressCoderIndex(progressIndex); + + RINOK(_mixerCoder->Code(&inStreamPointers.Front(), NULL, 1, + &outStreamPointers.Front(), NULL, outStreamPointers.Size(), compressProgress)); + + ConvertBindInfoToFolderItemInfo(_decompressBindInfo, _decompressionMethods, folderItem); + + packSizes.Add(outStreamSizeCountSpec->GetSize()); + + for (i = 1; i < _bindInfo.OutStreams.Size(); i++) + { + CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1]; + RINOK(inOutTempBuffer.WriteToStream(outStream)); + packSizes.Add(inOutTempBuffer.GetDataSize()); + } + + for (i = 0; i < (int)_bindReverseConverter->NumSrcInStreams; i++) + { + int binder = _bindInfo.FindBinderForInStream( + _bindReverseConverter->DestOutToSrcInMap[i]); + UInt64 streamSize; + if (binder < 0) + streamSize = inStreamSizeCountSpec->GetSize(); + else + streamSize = _mixerCoderSpec->GetWriteProcessedSize(binder); + folderItem.UnpackSizes.Add(streamSize); + } + for (i = numMethods - 1; i >= 0; i--) + folderItem.Coders[numMethods - 1 - i].Props = _codersInfo[i].Props; + return S_OK; +} + + +CEncoder::CEncoder(const CCompressionMethodMode &options): + _bindReverseConverter(0), + _constructed(false) +{ + if (options.IsEmpty()) + throw 1; + + _options = options; + _mixerCoderSpec = NULL; +} + +HRESULT CEncoder::EncoderConstr() +{ + if (_constructed) + return S_OK; + if (_options.Methods.IsEmpty()) + { + // it has only password method; + if (!_options.PasswordIsDefined) + throw 1; + if (!_options.Binds.IsEmpty()) + throw 1; + NCoderMixer::CCoderStreamsInfo coderStreamsInfo; + CMethodFull method; + + method.NumInStreams = 1; + method.NumOutStreams = 1; + coderStreamsInfo.NumInStreams = 1; + coderStreamsInfo.NumOutStreams = 1; + method.Id = k_AES; + + _options.Methods.Add(method); + _bindInfo.Coders.Add(coderStreamsInfo); + + _bindInfo.InStreams.Add(0); + _bindInfo.OutStreams.Add(0); + } + else + { + + UInt32 numInStreams = 0, numOutStreams = 0; + int 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()) + { + if (i < _options.Methods.Size() - 1) + { + NCoderMixer::CBindPair bindPair; + bindPair.InIndex = numInStreams + coderStreamsInfo.NumInStreams; + bindPair.OutIndex = numOutStreams; + _bindInfo.BindPairs.Add(bindPair); + } + else + _bindInfo.OutStreams.Insert(0, numOutStreams); + for (UInt32 j = 1; j < coderStreamsInfo.NumOutStreams; j++) + _bindInfo.OutStreams.Add(numOutStreams + j); + } + + numInStreams += coderStreamsInfo.NumInStreams; + numOutStreams += coderStreamsInfo.NumOutStreams; + + _bindInfo.Coders.Add(coderStreamsInfo); + } + + if (!_options.Binds.IsEmpty()) + { + for (i = 0; i < _options.Binds.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); + } + for (i = 0; i < (int)numOutStreams; i++) + if (_bindInfo.FindBinderForOutStream(i) == -1) + _bindInfo.OutStreams.Add(i); + } + + for (i = 0; i < (int)numInStreams; i++) + if (_bindInfo.FindBinderForInStream(i) == -1) + _bindInfo.InStreams.Add(i); + + if (_bindInfo.InStreams.IsEmpty()) + throw 1; // this is error + + // Make main stream first in list + int inIndex = _bindInfo.InStreams[0]; + for (;;) + { + UInt32 coderIndex, coderStreamIndex; + _bindInfo.FindInStream(inIndex, coderIndex, coderStreamIndex); + UInt32 outIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex); + int binder = _bindInfo.FindBinderForOutStream(outIndex); + if (binder >= 0) + { + 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); + break; + } + break; + } + + if (_options.PasswordIsDefined) + { + int numCryptoStreams = _bindInfo.OutStreams.Size(); + + for (i = 0; i < numCryptoStreams; i++) + { + NCoderMixer::CBindPair bindPair; + bindPair.InIndex = numInStreams + i; + bindPair.OutIndex = _bindInfo.OutStreams[i]; + _bindInfo.BindPairs.Add(bindPair); + } + _bindInfo.OutStreams.Clear(); + + /* + if (numCryptoStreams == 0) + numCryptoStreams = 1; + */ + + 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.Id = k_AES; + + _options.Methods.Add(method); + _bindInfo.Coders.Add(coderStreamsInfo); + _bindInfo.OutStreams.Add(numOutStreams + i); + } + } + + } + + for (int i = _options.Methods.Size() - 1; i >= 0; i--) + { + const CMethodFull &methodFull = _options.Methods[i]; + _decompressionMethods.Add(methodFull.Id); + } + + _bindReverseConverter = new NCoderMixer::CBindReverseConverter(_bindInfo); + _bindReverseConverter->CreateReverseBindInfo(_decompressBindInfo); + _constructed = true; + return S_OK; +} + +CEncoder::~CEncoder() +{ + delete _bindReverseConverter; +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.h new file mode 100644 index 000000000..4909a6e89 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zEncode.h @@ -0,0 +1,55 @@ +// 7zEncode.h + +#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" + +namespace NArchive { +namespace N7z { + +class CEncoder +{ + NCoderMixer::CCoderMixer2MT *_mixerCoderSpec; + CMyComPtr<ICompressCoder2> _mixerCoder; + + CObjectVector<CCoderInfo> _codersInfo; + + CCompressionMethodMode _options; + NCoderMixer::CBindInfo _bindInfo; + NCoderMixer::CBindInfo _decompressBindInfo; + NCoderMixer::CBindReverseConverter *_bindReverseConverter; + CRecordVector<CMethodId> _decompressionMethods; + + 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, + CFolder &folderItem, + ISequentialOutStream *outStream, + CRecordVector<UInt64> &packSizes, + ICompressProgressInfo *compressProgress); +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zExtract.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zExtract.cpp new file mode 100644 index 000000000..d55f38e13 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zExtract.cpp @@ -0,0 +1,270 @@ +// 7zExtract.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" + +#include "../../Common/ProgressUtils.h" + +#include "7zDecode.h" +// #include "7z1Decode.h" +#include "7zFolderOutStream.h" +#include "7zHandler.h" + +namespace NArchive { +namespace N7z { + +struct CExtractFolderInfo +{ + #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) + { + if (fileIndex != kNumNoIndex) + { + ExtractStatuses.Reserve(1); + ExtractStatuses.Add(true); + } + }; +}; + +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; + + bool allFilesMode = (numItems == (UInt32)-1); + if (allFilesMode) + numItems = + #ifdef _7Z_VOL + _refs.Size(); + #else + _db.Files.Size(); + #endif + + if(numItems == 0) + return S_OK; + + /* + if(_volumes.Size() != 1) + return E_FAIL; + const CVolume &volume = _volumes.Front(); + const CArchiveDatabaseEx &_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++) + { + #ifdef _7Z_VOL + // const CRef &ref = ref2.Refs[ri]; + const CRef &ref = _refs[ref2Index]; + + int volumeIndex = ref.VolumeIndex; + const CVolume &volume = _volumes[volumeIndex]; + const CArchiveDatabaseEx &db = volume.Database; + UInt32 fileIndex = ref.ItemIndex; + #else + const CArchiveDatabaseEx &db = _db; + UInt32 fileIndex = ref2Index; + #endif + + 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)); + const CFolder &folderInfo = db.Folders[folderIndex]; + UInt64 unpackSize = folderInfo.GetUnpackSize(); + 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); + } + } + } + + RINOK(extractCallback->SetTotal(importantTotalUnpacked)); + + CDecoder decoder( + #ifdef _ST_MODE + false + #else + true + #endif + ); + // CDecoder1 decoder; + + UInt64 totalPacked = 0; + UInt64 totalUnpacked = 0; + UInt64 curPacked, curUnpacked; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + for (int i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked) + { + lps->OutSize = totalUnpacked; + lps->InSize = totalPacked; + RINOK(lps->SetCur()); + + if (i >= extractFolderInfoVector.Size()) + break; + + const CExtractFolderInfo &efi = extractFolderInfoVector[i]; + curUnpacked = efi.UnpackSize; + curPacked = 0; + + CFolderOutStream *folderOutStream = new CFolderOutStream; + CMyComPtr<ISequentialOutStream> outStream(folderOutStream); + + #ifdef _7Z_VOL + const CVolume &volume = _volumes[efi.VolumeIndex]; + const CArchiveDatabaseEx &db = volume.Database; + #else + const CArchiveDatabaseEx &db = _db; + #endif + + CNum startIndex; + if (efi.FileIndex != kNumNoIndex) + startIndex = efi.FileIndex; + else + startIndex = db.FolderStartFileIndex[efi.FolderIndex]; + + HRESULT result = folderOutStream->Init(&db, + #ifdef _7Z_VOL + volume.StartRef2Index, + #else + 0, + #endif + startIndex, + &efi.ExtractStatuses, extractCallback, testMode, _crcSize != 0); + + RINOK(result); + + if (efi.FileIndex != kNumNoIndex) + continue; + + CNum folderIndex = efi.FolderIndex; + const CFolder &folderInfo = db.Folders[folderIndex]; + + curPacked = _db.GetFolderFullPackSize(folderIndex); + + CNum packStreamIndex = db.FolderStartPackStreamIndex[folderIndex]; + UInt64 folderStartPackPos = db.GetFolderStreamPos(folderIndex, 0); + + #ifndef _NO_CRYPTO + CMyComPtr<ICryptoGetTextPassword> getTextPassword; + if (extractCallback) + extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); + #endif + + try + { + #ifndef _NO_CRYPTO + bool passwordIsDefined; + #endif + + HRESULT result = decoder.Decode( + EXTERNAL_CODECS_VARS + #ifdef _7Z_VOL + volume.Stream, + #else + _inStream, + #endif + folderStartPackPos, + &db.PackSizes[packStreamIndex], + folderInfo, + outStream, + progress + #ifndef _NO_CRYPTO + , getTextPassword, passwordIsDefined + #endif + #if !defined(_7ZIP_ST) && !defined(_SFX) + , true, _numThreads + #endif + ); + + if (result == S_FALSE) + { + RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); + continue; + } + if (result == E_NOTIMPL) + { + RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kUnSupportedMethod)); + continue; + } + if (result != S_OK) + return result; + if (folderOutStream->WasWritingFinished() != S_OK) + { + RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); + continue; + } + } + catch(...) + { + RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); + continue; + } + } + return S_OK; + COM_TRY_END +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.cpp new file mode 100644 index 000000000..edd276bc1 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.cpp @@ -0,0 +1,123 @@ +// 7zFolderInStream.cpp + +#include "StdAfx.h" + +#include "7zFolderInStream.h" + +namespace NArchive { +namespace N7z { + +CFolderInStream::CFolderInStream() +{ + _inStreamWithHashSpec = new CSequentialInStreamWithCRC; + _inStreamWithHash = _inStreamWithHashSpec; +} + +void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback, + const UInt32 *fileIndices, UInt32 numFiles) +{ + _updateCallback = updateCallback; + _numFiles = numFiles; + _fileIndex = 0; + _fileIndices = fileIndices; + Processed.Clear(); + CRCs.Clear(); + Sizes.Clear(); + _fileIsOpen = false; + _currentSizeIsDefined = false; +} + +HRESULT CFolderInStream::OpenStream() +{ + _filePos = 0; + while (_fileIndex < _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(); + if (stream) + { + _fileIsOpen = true; + CMyComPtr<IStreamGetSize> streamGetSize; + stream.QueryInterface(IID_IStreamGetSize, &streamGetSize); + if (streamGetSize) + { + RINOK(streamGetSize->GetSize(&_currentSize)); + _currentSizeIsDefined = true; + } + return S_OK; + } + RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); + Sizes.Add(0); + Processed.Add(result == S_OK); + AddDigest(); + } + return S_OK; +} + +void CFolderInStream::AddDigest() +{ + 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; +} + +STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize != 0) + *processedSize = 0; + while (size > 0) + { + if (_fileIsOpen) + { + UInt32 processed2; + RINOK(_inStreamWithHash->Read(data, size, &processed2)); + if (processed2 == 0) + { + RINOK(CloseStream()); + continue; + } + if (processedSize != 0) + *processedSize = processed2; + _filePos += processed2; + break; + } + if (_fileIndex >= _numFiles) + break; + RINOK(OpenStream()); + } + return S_OK; +} + +STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value) +{ + *value = 0; + int index2 = (int)subStream; + if (index2 < 0 || subStream > Sizes.Size()) + return E_FAIL; + if (index2 < Sizes.Size()) + { + *value = Sizes[index2]; + return S_OK; + } + if (!_currentSizeIsDefined) + return S_FALSE; + *value = _currentSize; + return S_OK; +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.h new file mode 100644 index 000000000..6df3672a1 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderInStream.h @@ -0,0 +1,58 @@ +// 7zFolderInStream.h + +#ifndef __7Z_FOLDER_IN_STREAM_H +#define __7Z_FOLDER_IN_STREAM_H + +#include "../../ICoder.h" +#include "../IArchive.h" +#include "../Common/InStreamWithCRC.h" + +#include "7zItem.h" + +namespace NArchive { +namespace N7z { + +class CFolderInStream: + public ISequentialInStream, + public ICompressGetSubStreamSize, + public CMyUnknownImp +{ + CSequentialInStreamWithCRC *_inStreamWithHashSpec; + CMyComPtr<ISequentialInStream> _inStreamWithHash; + CMyComPtr<IArchiveUpdateCallback> _updateCallback; + + bool _currentSizeIsDefined; + bool _fileIsOpen; + UInt64 _currentSize; + UInt64 _filePos; + const UInt32 *_fileIndices; + UInt32 _numFiles; + UInt32 _fileIndex; + + HRESULT OpenStream(); + HRESULT CloseStream(); + void AddDigest(); + +public: + CRecordVector<bool> Processed; + CRecordVector<UInt32> CRCs; + CRecordVector<UInt64> Sizes; + + MY_UNKNOWN_IMP1(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); + UInt64 GetFullSize() const + { + UInt64 size = 0; + for (int i = 0; i < Sizes.Size(); i++) + size += Sizes[i]; + return size; + } +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.cpp new file mode 100644 index 000000000..22c4600ec --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.cpp @@ -0,0 +1,149 @@ +// 7zFolderOutStream.cpp + +#include "StdAfx.h" + +#include "7zFolderOutStream.h" + +namespace NArchive { +namespace N7z { + +CFolderOutStream::CFolderOutStream() +{ + _crcStreamSpec = new COutStreamWithCRC; + _crcStream = _crcStreamSpec; +} + +HRESULT CFolderOutStream::Init( + const CArchiveDatabaseEx *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/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.h new file mode 100644 index 000000000..f9bb1af42 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zFolderOutStream.h @@ -0,0 +1,58 @@ +// 7zFolderOutStream.h + +#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 CArchiveDatabaseEx *_db; + const CBoolVector *_extractStatuses; + CMyComPtr<IArchiveExtractCallback> _extractCallback; + UInt32 _ref2Offset; + UInt32 _startIndex; + int _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 CArchiveDatabaseEx *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/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.cpp new file mode 100644 index 000000000..4ab7afa87 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.cpp @@ -0,0 +1,482 @@ +// 7zHandler.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" + +#ifndef __7Z_SET_PROPERTIES +#include "../../../Windows/System.h" +#endif + +#include "../Common/ItemNameUtils.h" + +#include "7zHandler.h" +#include "7zProperties.h" + +#ifdef __7Z_SET_PROPERTIES +#ifdef EXTRACT_ONLY +#include "../Common/ParseProperties.h" +#endif +#endif + +using namespace NWindows; + +extern UString ConvertMethodIdToString(UInt64 id); + +namespace NArchive { +namespace N7z { + +CHandler::CHandler() +{ + _crcSize = 4; + + #ifndef _NO_CRYPTO + _passwordIsDefined = false; + #endif + + #ifdef EXTRACT_ONLY + #ifdef __7Z_SET_PROPERTIES + _numThreads = NSystem::GetNumberOfProcessors(); + #endif + #else + Init(); + #endif +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _db.Files.Size(); + return S_OK; +} + +#ifdef _SFX + +IMP_IInArchive_ArcProps_NO + +STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 * /* numProperties */) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */, + BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */) +{ + return E_NOTIMPL; +} + + +#else + +STATPROPSTG kArcProps[] = +{ + { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidSolid, VT_BOOL}, + { NULL, kpidNumBlocks, VT_UI4}, + { NULL, kpidPhySize, VT_UI8}, + { NULL, kpidHeadersSize, VT_UI8}, + { NULL, kpidOffset, VT_UI8} +}; + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch(propID) + { + case kpidMethod: + { + UString resString; + CRecordVector<UInt64> ids; + int i; + for (i = 0; i < _db.Folders.Size(); i++) + { + const CFolder &f = _db.Folders[i]; + for (int j = f.Coders.Size() - 1; j >= 0; j--) + ids.AddToUniqueSorted(f.Coders[j].MethodID); + } + + for (i = 0; i < ids.Size(); i++) + { + UInt64 id = ids[i]; + UString methodName; + /* bool methodIsKnown = */ FindMethod(EXTERNAL_CODECS_VARS id, methodName); + if (methodName.IsEmpty()) + methodName = ConvertMethodIdToString(id); + if (!resString.IsEmpty()) + resString += L' '; + resString += methodName; + } + prop = resString; + break; + } + case kpidSolid: prop = _db.IsSolid(); break; + case kpidNumBlocks: prop = (UInt32)_db.Folders.Size(); break; + case kpidHeadersSize: prop = _db.HeadersSize; break; + case kpidPhySize: prop = _db.PhySize; break; + case kpidOffset: if (_db.ArchiveInfo.StartPosition != 0) prop = _db.ArchiveInfo.StartPosition; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +IMP_IInArchive_ArcProps + +#endif + +static void SetPropFromUInt64Def(CUInt64DefVector &v, int index, NCOM::CPropVariant &prop) +{ + UInt64 value; + if (v.GetItem(index, value)) + { + FILETIME ft; + ft.dwLowDateTime = (DWORD)value; + ft.dwHighDateTime = (DWORD)(value >> 32); + prop = ft; + } +} + +#ifndef _SFX + +static UString ConvertUInt32ToString(UInt32 value) +{ + wchar_t buffer[32]; + ConvertUInt64ToString(value, buffer); + return buffer; +} + +static UString GetStringForSizeValue(UInt32 value) +{ + for (int i = 31; i >= 0; i--) + if ((UInt32(1) << i) == value) + return ConvertUInt32ToString(i); + UString result; + if (value % (1 << 20) == 0) + { + result += ConvertUInt32ToString(value >> 20); + result += L"m"; + } + else if (value % (1 << 10) == 0) + { + result += ConvertUInt32ToString(value >> 10); + result += L"k"; + } + else + { + result += ConvertUInt32ToString(value); + result += L"b"; + } + return result; +} + +static const UInt64 k_Copy = 0x0; +static const UInt64 k_Delta = 3; +static const UInt64 k_LZMA2 = 0x21; +static const UInt64 k_LZMA = 0x030101; +static const UInt64 k_PPMD = 0x030401; + +static wchar_t GetHex(Byte value) +{ + return (wchar_t)((value < 10) ? (L'0' + value) : (L'A' + (value - 10))); +} +static inline void AddHexToString(UString &res, Byte value) +{ + res += GetHex((Byte)(value >> 4)); + res += GetHex((Byte)(value & 0xF)); +} + +#endif + +bool CHandler::IsEncrypted(UInt32 index2) const +{ + CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; + if (folderIndex != kNumNoIndex) + return _db.Folders[folderIndex].IsEncrypted(); + return false; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + /* + const CRef2 &ref2 = _refs[index]; + if (ref2.Refs.IsEmpty()) + return E_FAIL; + const CRef &ref = ref2.Refs.Front(); + */ + + const CFileItem &item = _db.Files[index]; + UInt32 index2 = index; + + switch(propID) + { + case kpidPath: + if (!item.Name.IsEmpty()) + prop = NItemName::GetOSName(item.Name); + break; + case kpidIsDir: prop = item.IsDir; break; + case kpidSize: + { + prop = item.Size; + // prop = ref2.Size; + break; + } + case kpidPackSize: + { + // prop = ref2.PackSize; + { + CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; + if (folderIndex != kNumNoIndex) + { + if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2) + prop = _db.GetFolderFullPackSize(folderIndex); + /* + else + prop = (UInt64)0; + */ + } + else + prop = (UInt64)0; + } + break; + } + case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) prop = v; break; } + case kpidCTime: SetPropFromUInt64Def(_db.CTime, index2, prop); break; + case kpidATime: SetPropFromUInt64Def(_db.ATime, index2, prop); break; + case kpidMTime: SetPropFromUInt64Def(_db.MTime, index2, prop); break; + case kpidAttrib: if (item.AttribDefined) prop = item.Attrib; break; + case kpidCRC: if (item.CrcDefined) prop = item.Crc; break; + case kpidEncrypted: prop = IsEncrypted(index2); break; + case kpidIsAnti: prop = _db.IsItemAnti(index2); break; + #ifndef _SFX + case kpidMethod: + { + CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; + if (folderIndex != kNumNoIndex) + { + const CFolder &folderInfo = _db.Folders[folderIndex]; + UString methodsString; + for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--) + { + const CCoderInfo &coder = folderInfo.Coders[i]; + if (!methodsString.IsEmpty()) + methodsString += L' '; + + UString methodName, propsString; + bool methodIsKnown = FindMethod( + EXTERNAL_CODECS_VARS + coder.MethodID, methodName); + + if (!methodIsKnown) + methodsString += ConvertMethodIdToString(coder.MethodID); + else + { + methodsString += methodName; + if (coder.MethodID == k_Delta && coder.Props.GetCapacity() == 1) + propsString = ConvertUInt32ToString((UInt32)coder.Props[0] + 1); + else if (coder.MethodID == k_LZMA && coder.Props.GetCapacity() == 5) + { + UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1); + propsString = GetStringForSizeValue(dicSize); + } + else if (coder.MethodID == k_LZMA2 && coder.Props.GetCapacity() == 1) + { + Byte p = coder.Props[0]; + UInt32 dicSize = (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)); + propsString = GetStringForSizeValue(dicSize); + } + else if (coder.MethodID == k_PPMD && coder.Props.GetCapacity() == 5) + { + Byte order = *(const Byte *)coder.Props; + propsString = L'o'; + propsString += ConvertUInt32ToString(order); + propsString += L":mem"; + UInt32 dicSize = GetUi32((const Byte *)coder.Props + 1); + propsString += GetStringForSizeValue(dicSize); + } + else if (coder.MethodID == k_AES && coder.Props.GetCapacity() >= 1) + { + const Byte *data = (const Byte *)coder.Props; + Byte firstByte = *data++; + UInt32 numCyclesPower = firstByte & 0x3F; + propsString = ConvertUInt32ToString(numCyclesPower); + /* + if ((firstByte & 0xC0) != 0) + { + UInt32 saltSize = (firstByte >> 7) & 1; + UInt32 ivSize = (firstByte >> 6) & 1; + if (coder.Props.GetCapacity() >= 2) + { + Byte secondByte = *data++; + saltSize += (secondByte >> 4); + ivSize += (secondByte & 0x0F); + } + } + */ + } + } + if (!propsString.IsEmpty()) + { + methodsString += L':'; + methodsString += propsString; + } + else if (coder.Props.GetCapacity() > 0) + { + methodsString += L":["; + for (size_t bi = 0; bi < coder.Props.GetCapacity(); bi++) + { + if (bi > 5 && bi + 1 < coder.Props.GetCapacity()) + { + methodsString += L".."; + break; + } + else + AddHexToString(methodsString, coder.Props[bi]); + } + methodsString += L']'; + } + } + prop = methodsString; + } + } + break; + case kpidBlock: + { + CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; + if (folderIndex != kNumNoIndex) + prop = (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)) + { + prop = _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0); + } + else + prop = (UInt64)0; + } + else + prop = (UInt64)0; + } + break; + #endif + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openArchiveCallback) +{ + COM_TRY_BEGIN + Close(); + #ifndef _SFX + _fileInfoPopIDs.Clear(); + #endif + try + { + CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback; + + #ifndef _NO_CRYPTO + CMyComPtr<ICryptoGetTextPassword> getTextPassword; + if (openArchiveCallback) + { + openArchiveCallbackTemp.QueryInterface( + IID_ICryptoGetTextPassword, &getTextPassword); + } + #endif + CInArchive archive; + RINOK(archive.Open(stream, maxCheckStartPosition)); + #ifndef _NO_CRYPTO + _passwordIsDefined = false; + UString password; + #endif + HRESULT result = archive.ReadDatabase( + EXTERNAL_CODECS_VARS + _db + #ifndef _NO_CRYPTO + , getTextPassword, _passwordIsDefined + #endif + ); + RINOK(result); + _db.Fill(); + _inStream = stream; + } + catch(...) + { + Close(); + return S_FALSE; + } + // _inStream = stream; + #ifndef _SFX + FillPopIDs(); + #endif + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + COM_TRY_BEGIN + _inStream.Release(); + _db.Clear(); + return S_OK; + COM_TRY_END +} + +#ifdef __7Z_SET_PROPERTIES +#ifdef EXTRACT_ONLY + +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) +{ + COM_TRY_BEGIN + const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); + _numThreads = numProcessors; + + for (int i = 0; i < numProperties; i++) + { + UString name = names[i]; + name.MakeUpper(); + if (name.IsEmpty()) + return E_INVALIDARG; + const PROPVARIANT &value = values[i]; + UInt32 number; + int index = ParseStringToUInt32(name, number); + if (index == 0) + { + if(name.Left(2).CompareNoCase(L"MT") == 0) + { + RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads)); + continue; + } + else + return E_INVALIDARG; + } + } + return S_OK; + COM_TRY_END +} + +#endif +#endif + +IMPL_ISetCompressCodecsInfo + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.h new file mode 100644 index 000000000..56062d464 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandler.h @@ -0,0 +1,119 @@ +// 7z/Handler.h + +#ifndef __7Z_HANDLER_H +#define __7Z_HANDLER_H + +#include "../../ICoder.h" +#include "../IArchive.h" + +#include "../../Common/CreateCoder.h" + +#ifndef EXTRACT_ONLY +#include "../Common/HandlerOut.h" +#endif + +#include "7zCompressionMode.h" +#include "7zIn.h" + +namespace NArchive { +namespace N7z { + +#ifndef __7Z_SET_PROPERTIES + +#ifdef EXTRACT_ONLY +#if !defined(_7ZIP_ST) && !defined(_SFX) +#define __7Z_SET_PROPERTIES +#endif +#else +#define __7Z_SET_PROPERTIES +#endif + +#endif + + +class CHandler: + #ifndef EXTRACT_ONLY + public NArchive::COutHandler, + #endif + public IInArchive, + #ifdef __7Z_SET_PROPERTIES + public ISetProperties, + #endif + #ifndef EXTRACT_ONLY + public IOutArchive, + #endif + PUBLIC_ISetCompressCodecsInfo + public CMyUnknownImp +{ +public: + MY_QUERYINTERFACE_BEGIN2(IInArchive) + #ifdef __7Z_SET_PROPERTIES + MY_QUERYINTERFACE_ENTRY(ISetProperties) + #endif + #ifndef EXTRACT_ONLY + MY_QUERYINTERFACE_ENTRY(IOutArchive) + #endif + QUERY_ENTRY_ISetCompressCodecsInfo + MY_QUERYINTERFACE_END + MY_ADDREF_RELEASE + + INTERFACE_IInArchive(;) + + #ifdef __7Z_SET_PROPERTIES + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties); + #endif + + #ifndef EXTRACT_ONLY + INTERFACE_IOutArchive(;) + #endif + + DECL_ISetCompressCodecsInfo + + CHandler(); + +private: + CMyComPtr<IInStream> _inStream; + NArchive::N7z::CArchiveDatabaseEx _db; + #ifndef _NO_CRYPTO + bool _passwordIsDefined; + #endif + + #ifdef EXTRACT_ONLY + + #ifdef __7Z_SET_PROPERTIES + UInt32 _numThreads; + #endif + + UInt32 _crcSize; + + #else + + CRecordVector<CBind> _binds; + + HRESULT SetCompressionMethod(CCompressionMethodMode &method, + CObjectVector<COneMethodInfo> &methodsInfo + #ifndef _7ZIP_ST + , UInt32 numThreads + #endif + ); + + HRESULT SetCompressionMethod( + CCompressionMethodMode &method, + CCompressionMethodMode &headerMethod); + + #endif + + bool IsEncrypted(UInt32 index2) const; + #ifndef _SFX + + CRecordVector<UInt64> _fileInfoPopIDs; + void FillPopIDs(); + + #endif + + DECL_EXTERNAL_CODECS_VARS +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandlerOut.cpp new file mode 100644 index 000000000..a8ccab6df --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHandlerOut.cpp @@ -0,0 +1,483 @@ +// 7zHandlerOut.cpp + +#include "StdAfx.h" + +#include "../../../Windows/PropVariant.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/StringToInt.h" + +#include "../../ICoder.h" + +#include "../Common/ItemNameUtils.h" +#include "../Common/ParseProperties.h" + +#include "7zHandler.h" +#include "7zOut.h" +#include "7zUpdate.h" + +using namespace NWindows; + +namespace NArchive { +namespace N7z { + +static const wchar_t *kLZMAMethodName = L"LZMA"; +static const wchar_t *kCopyMethod = L"Copy"; +static const wchar_t *kDefaultMethodName = kLZMAMethodName; + +static const UInt32 kLzmaAlgorithmX5 = 1; +static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2"; +static const UInt32 kDictionaryForHeaders = + #ifdef UNDER_CE + 1 << 18 + #else + 1 << 20 + #endif +; +static const UInt32 kNumFastBytesForHeaders = 273; +static const UInt32 kAlgorithmForHeaders = kLzmaAlgorithmX5; + +static inline bool IsCopyMethod(const UString &methodName) + { return (methodName.CompareNoCase(kCopyMethod) == 0); } + +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) +{ + *type = NFileTimeType::kWindows; + return S_OK; +} + +HRESULT CHandler::SetCompressionMethod( + CCompressionMethodMode &methodMode, + CCompressionMethodMode &headerMethod) +{ + HRESULT res = SetCompressionMethod(methodMode, _methods + #ifndef _7ZIP_ST + , _numThreads + #endif + ); + RINOK(res); + methodMode.Binds = _binds; + + if (_compressHeaders) + { + // headerMethod.Methods.Add(methodMode.Methods.Back()); + + CObjectVector<COneMethodInfo> headerMethodInfoVector; + COneMethodInfo oneMethodInfo; + oneMethodInfo.MethodName = kLZMAMethodName; + { + CProp prop; + prop.Id = NCoderPropID::kMatchFinder; + prop.Value = kLzmaMatchFinderForHeaders; + oneMethodInfo.Props.Add(prop); + } + { + CProp prop; + prop.Id = NCoderPropID::kAlgorithm; + prop.Value = kAlgorithmForHeaders; + oneMethodInfo.Props.Add(prop); + } + { + CProp prop; + prop.Id = NCoderPropID::kNumFastBytes; + prop.Value = (UInt32)kNumFastBytesForHeaders; + oneMethodInfo.Props.Add(prop); + } + { + CProp prop; + prop.Id = NCoderPropID::kDictionarySize; + prop.Value = (UInt32)kDictionaryForHeaders; + oneMethodInfo.Props.Add(prop); + } + headerMethodInfoVector.Add(oneMethodInfo); + HRESULT res = SetCompressionMethod(headerMethod, headerMethodInfoVector + #ifndef _7ZIP_ST + , 1 + #endif + ); + RINOK(res); + } + return S_OK; +} + +HRESULT CHandler::SetCompressionMethod( + CCompressionMethodMode &methodMode, + CObjectVector<COneMethodInfo> &methodsInfo + #ifndef _7ZIP_ST + , UInt32 numThreads + #endif + ) +{ + UInt32 level = _level; + + if (methodsInfo.IsEmpty()) + { + COneMethodInfo oneMethodInfo; + oneMethodInfo.MethodName = ((level == 0) ? kCopyMethod : kDefaultMethodName); + methodsInfo.Add(oneMethodInfo); + } + + bool needSolid = false; + for(int i = 0; i < methodsInfo.Size(); i++) + { + COneMethodInfo &oneMethodInfo = methodsInfo[i]; + SetCompressionMethod2(oneMethodInfo + #ifndef _7ZIP_ST + , numThreads + #endif + ); + + if (!IsCopyMethod(oneMethodInfo.MethodName)) + needSolid = true; + + CMethodFull methodFull; + + if (!FindMethod( + EXTERNAL_CODECS_VARS + oneMethodInfo.MethodName, methodFull.Id, methodFull.NumInStreams, methodFull.NumOutStreams)) + return E_INVALIDARG; + methodFull.Props = oneMethodInfo.Props; + methodMode.Methods.Add(methodFull); + + if (!_numSolidBytesDefined) + { + for (int j = 0; j < methodFull.Props.Size(); j++) + { + const CProp &prop = methodFull.Props[j]; + if ((prop.Id == NCoderPropID::kDictionarySize || + prop.Id == NCoderPropID::kUsedMemorySize) && prop.Value.vt == VT_UI4) + { + _numSolidBytes = ((UInt64)prop.Value.ulVal) << 7; + const UInt64 kMinSize = (1 << 24); + if (_numSolidBytes < kMinSize) + _numSolidBytes = kMinSize; + _numSolidBytesDefined = true; + break; + } + } + } + } + + if (!needSolid && !_numSolidBytesDefined) + { + _numSolidBytesDefined = true; + _numSolidBytes = 0; + } + return S_OK; +} + +static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, bool writeTime, PROPID propID, UInt64 &ft, bool &ftDefined) +{ + ft = 0; + ftDefined = false; + if (!writeTime) + return S_OK; + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(index, propID, &prop)); + if (prop.vt == VT_FILETIME) + { + ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32); + ftDefined = true; + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + return S_OK; +} + +STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback) +{ + COM_TRY_BEGIN + + const CArchiveDatabaseEx *db = 0; + #ifdef _7Z_VOL + if (_volumes.Size() > 1) + return E_FAIL; + const CVolume *volume = 0; + if (_volumes.Size() == 1) + { + volume = &_volumes.Front(); + db = &volume->Database; + } + #else + if (_inStream != 0) + db = &_db; + #endif + + CObjectVector<CUpdateItem> updateItems; + + for (UInt32 i = 0; i < numItems; i++) + { + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); + CUpdateItem ui; + ui.NewProps = IntToBool(newProps); + ui.NewData = IntToBool(newData); + ui.IndexInArchive = indexInArchive; + ui.IndexInClient = i; + ui.IsAnti = false; + ui.Size = 0; + + if (ui.IndexInArchive != -1) + { + if (db == 0 || ui.IndexInArchive >= db->Files.Size()) + return E_INVALIDARG; + const CFileItem &fi = db->Files[ui.IndexInArchive]; + ui.Name = fi.Name; + ui.IsDir = fi.IsDir; + ui.Size = fi.Size; + ui.IsAnti = db->IsItemAnti(ui.IndexInArchive); + + ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime); + ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime); + ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime); + } + + if (ui.NewProps) + { + bool nameIsDefined; + bool folderStatusIsDefined; + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop)); + if (prop.vt == VT_EMPTY) + ui.AttribDefined = false; + else if (prop.vt != VT_UI4) + return E_INVALIDARG; + else + { + ui.Attrib = prop.ulVal; + ui.AttribDefined = true; + } + } + + // we need MTime to sort files. + RINOK(GetTime(updateCallback, i, WriteCTime, kpidCTime, ui.CTime, ui.CTimeDefined)); + RINOK(GetTime(updateCallback, i, WriteATime, kpidATime, ui.ATime, ui.ATimeDefined)); + RINOK(GetTime(updateCallback, i, true, kpidMTime, ui.MTime, ui.MTimeDefined)); + + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidPath, &prop)); + if (prop.vt == VT_EMPTY) + nameIsDefined = false; + else if (prop.vt != VT_BSTR) + return E_INVALIDARG; + else + { + ui.Name = NItemName::MakeLegalName(prop.bstrVal); + nameIsDefined = true; + } + } + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop)); + if (prop.vt == VT_EMPTY) + folderStatusIsDefined = false; + else if (prop.vt != VT_BOOL) + return E_INVALIDARG; + else + { + ui.IsDir = (prop.boolVal != VARIANT_FALSE); + folderStatusIsDefined = true; + } + } + + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop)); + if (prop.vt == VT_EMPTY) + ui.IsAnti = false; + else if (prop.vt != VT_BOOL) + return E_INVALIDARG; + else + ui.IsAnti = (prop.boolVal != VARIANT_FALSE); + } + + if (ui.IsAnti) + { + ui.AttribDefined = false; + + ui.CTimeDefined = false; + ui.ATimeDefined = false; + ui.MTimeDefined = false; + + ui.Size = 0; + } + + if (!folderStatusIsDefined && ui.AttribDefined) + ui.SetDirStatusFromAttrib(); + } + + if (ui.NewData) + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidSize, &prop)); + if (prop.vt != VT_UI8) + return E_INVALIDARG; + ui.Size = (UInt64)prop.uhVal.QuadPart; + if (ui.Size != 0 && ui.IsAnti) + return E_INVALIDARG; + } + updateItems.Add(ui); + } + + CCompressionMethodMode methodMode, headerMethod; + RINOK(SetCompressionMethod(methodMode, headerMethod)); + #ifndef _7ZIP_ST + methodMode.NumThreads = _numThreads; + headerMethod.NumThreads = 1; + #endif + + CMyComPtr<ICryptoGetTextPassword2> getPassword2; + updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2); + + if (getPassword2) + { + CMyComBSTR password; + Int32 passwordIsDefined; + RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password)); + methodMode.PasswordIsDefined = IntToBool(passwordIsDefined); + if (methodMode.PasswordIsDefined) + methodMode.Password = password; + } + else + methodMode.PasswordIsDefined = false; + + bool compressMainHeader = _compressHeaders; // check it + + bool encryptHeaders = false; + + if (methodMode.PasswordIsDefined) + { + if (_encryptHeadersSpecified) + encryptHeaders = _encryptHeaders; + #ifndef _NO_CRYPTO + else + encryptHeaders = _passwordIsDefined; + #endif + compressMainHeader = true; + if (encryptHeaders) + { + headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined; + headerMethod.Password = methodMode.Password; + } + } + + if (numItems < 2) + compressMainHeader = false; + + CUpdateOptions options; + options.Method = &methodMode; + options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : 0; + options.UseFilters = _level != 0 && _autoFilter; + options.MaxFilter = _level >= 8; + + options.HeaderOptions.CompressMainHeader = compressMainHeader; + options.HeaderOptions.WriteCTime = WriteCTime; + options.HeaderOptions.WriteATime = WriteATime; + options.HeaderOptions.WriteMTime = WriteMTime; + + options.NumSolidFiles = _numSolidFiles; + options.NumSolidBytes = _numSolidBytes; + options.SolidExtension = _solidExtension; + options.RemoveSfxBlock = _removeSfxBlock; + options.VolumeMode = _volumeMode; + + COutArchive archive; + CArchiveDatabase newDatabase; + + CMyComPtr<ICryptoGetTextPassword> getPassword; + updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword); + + HRESULT res = Update( + EXTERNAL_CODECS_VARS + #ifdef _7Z_VOL + volume ? volume->Stream: 0, + volume ? db : 0, + #else + _inStream, + db, + #endif + updateItems, + archive, newDatabase, outStream, updateCallback, options + #ifndef _NO_CRYPTO + , getPassword + #endif + ); + + RINOK(res); + + updateItems.ClearAndFree(); + + return archive.WriteDatabase(EXTERNAL_CODECS_VARS + newDatabase, options.HeaderMethod, options.HeaderOptions); + + COM_TRY_END +} + +static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream) +{ + stream = 0; + int index = ParseStringToUInt32(srcString, coder); + if (index == 0) + return E_INVALIDARG; + srcString.Delete(0, index); + if (srcString[0] == 'S') + { + srcString.Delete(0); + int index = ParseStringToUInt32(srcString, stream); + if (index == 0) + return E_INVALIDARG; + srcString.Delete(0, index); + } + return S_OK; +} + +static HRESULT GetBindInfo(UString &srcString, CBind &bind) +{ + RINOK(GetBindInfoPart(srcString, bind.OutCoder, bind.OutStream)); + if (srcString[0] != ':') + return E_INVALIDARG; + srcString.Delete(0); + RINOK(GetBindInfoPart(srcString, bind.InCoder, bind.InStream)); + if (!srcString.IsEmpty()) + return E_INVALIDARG; + return S_OK; +} + +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) +{ + COM_TRY_BEGIN + _binds.Clear(); + BeforeSetProperty(); + + for (int i = 0; i < numProperties; i++) + { + UString name = names[i]; + name.MakeUpper(); + if (name.IsEmpty()) + return E_INVALIDARG; + + const PROPVARIANT &value = values[i]; + + if (name[0] == 'B') + { + name.Delete(0); + CBind bind; + RINOK(GetBindInfo(name, bind)); + _binds.Add(bind); + continue; + } + + RINOK(SetProperty(name, value)); + } + + return S_OK; + COM_TRY_END +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.cpp new file mode 100644 index 000000000..5b5f2fb37 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.cpp @@ -0,0 +1,14 @@ +// 7zHeader.cpp + +#include "StdAfx.h" +#include "7zHeader.h" + +namespace NArchive { +namespace N7z { + +Byte kSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; +#ifdef _7Z_VOL +Byte kFinishSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C + 1}; +#endif + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.h new file mode 100644 index 000000000..30622b90e --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zHeader.h @@ -0,0 +1,97 @@ +// 7z/7zHeader.h + +#ifndef __7Z_HEADER_H +#define __7Z_HEADER_H + +#include "../../../Common/Types.h" + +namespace NArchive { +namespace N7z { + +const int kSignatureSize = 6; +extern Byte kSignature[kSignatureSize]; + +// #define _7Z_VOL +// 7z-MultiVolume is not finished yet. +// It can work already, but I still do not like some +// things of that new multivolume format. +// So please keep it commented. + +#ifdef _7Z_VOL +extern Byte kFinishSignature[kSignatureSize]; +#endif + +struct CArchiveVersion +{ + Byte Major; + Byte Minor; +}; + +const Byte kMajorVersion = 0; + +struct CStartHeader +{ + UInt64 NextHeaderOffset; + UInt64 NextHeaderSize; + UInt32 NextHeaderCRC; +}; + +const UInt32 kStartHeaderSize = 20; + +#ifdef _7Z_VOL +struct CFinishHeader: public CStartHeader +{ + UInt64 ArchiveStartOffset; // data offset from end if that struct + UInt64 AdditionalStartBlockSize; // start signature & start header size +}; + +const UInt32 kFinishHeaderSize = kStartHeaderSize + 16; +#endif + +namespace NID +{ + enum EEnum + { + kEnd, + + kHeader, + + kArchiveProperties, + + kAdditionalStreamsInfo, + kMainStreamsInfo, + kFilesInfo, + + kPackInfo, + kUnpackInfo, + kSubStreamsInfo, + + kSize, + kCRC, + + kFolder, + + kCodersUnpackSize, + kNumUnpackStream, + + kEmptyStream, + kEmptyFile, + kAnti, + + kName, + kCTime, + kATime, + kMTime, + kWinAttributes, + kComment, + + kEncodedHeader, + + kStartPos, + kDummy + }; +} + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.cpp new file mode 100644 index 000000000..0feb81d2c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.cpp @@ -0,0 +1,1276 @@ +// 7zIn.cpp + +#include "StdAfx.h" + +#include "../../../../C/7zCrc.h" +#include "../../../../C/CpuArch.h" + +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "7zDecode.h" +#include "7zIn.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +// define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader +#ifndef _SFX +#define FORMAT_7Z_RECOVERY +#endif + +namespace NArchive { +namespace N7z { + +static void BoolVector_Fill_False(CBoolVector &v, int size) +{ + v.Clear(); + v.Reserve(size); + for (int i = 0; i < size; i++) + v.Add(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() const +{ + const int kNumCodersMax = sizeof(UInt32) * 8; // don't change it + const int kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax + const int kNumBindsMax = 32; + + if (Coders.Size() > kNumCodersMax || BindPairs.Size() > kNumBindsMax) + return false; + + { + CBoolVector v; + BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size()); + + int 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, UnpackSizes.Size()); + for (i = 0; i < BindPairs.Size(); i++) + if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex)) + return false; + } + + UInt32 mask[kMaskSize]; + int i; + for (i = 0; i < kMaskSize; i++) + mask[i] = 0; + + { + CIntVector 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 (int 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 {}; + +static void ThrowException() { throw CInArchiveException(); } +static inline void ThrowEndOfData() { ThrowException(); } +static inline void ThrowUnsupported() { ThrowException(); } +static inline void ThrowIncorrect() { ThrowException(); } +static inline void ThrowUnsupportedVersion() { ThrowException(); } + +/* +class CInArchiveException +{ +public: + enum CCauseType + { + kUnsupportedVersion = 0, + kUnsupported, + kIncorrect, + kEndOfData + } Cause; + CInArchiveException(CCauseType cause): Cause(cause) {}; +}; + +static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchiveException(c); } +static void ThrowEndOfData() { ThrowException(CInArchiveException::kEndOfData); } +static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupported); } +static void ThrowIncorrect() { ThrowException(CInArchiveException::kIncorrect); } +static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUnsupportedVersion); } +*/ + +class CStreamSwitch +{ + CInArchive *_archive; + bool _needRemove; +public: + CStreamSwitch(): _needRemove(false) {} + ~CStreamSwitch() { Remove(); } + void Remove(); + void Set(CInArchive *archive, const Byte *data, size_t size); + void Set(CInArchive *archive, const CByteBuffer &byteBuffer); + void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector); +}; + +void CStreamSwitch::Remove() +{ + if (_needRemove) + { + _archive->DeleteByteStream(); + _needRemove = false; + } +} + +void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size) +{ + Remove(); + _archive = archive; + _archive->AddByteStream(data, size); + _needRemove = true; +} + +void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer) +{ + Set(archive, byteBuffer, byteBuffer.GetCapacity()); +} + +void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector) +{ + Remove(); + Byte external = archive->ReadByte(); + if (external != 0) + { + int dataIndex = (int)archive->ReadNum(); + if (dataIndex < 0 || dataIndex >= dataVector->Size()) + ThrowIncorrect(); + Set(archive, (*dataVector)[dataIndex]); + } +} + +Byte CInByte2::ReadByte() +{ + if (_pos >= _size) + ThrowEndOfData(); + return _buffer[_pos++]; +} + +void CInByte2::ReadBytes(Byte *data, size_t size) +{ + if (size > _size - _pos) + ThrowEndOfData(); + for (size_t i = 0; i < size; i++) + data[i] = _buffer[_pos++]; +} + +void CInByte2::SkipData(UInt64 size) +{ + if (size > _size - _pos) + ThrowEndOfData(); + _pos += (size_t)size; +} + +void CInByte2::SkipData() +{ + SkipData(ReadNumber()); +} + +UInt64 CInByte2::ReadNumber() +{ + if (_pos >= _size) + ThrowEndOfData(); + Byte firstByte = _buffer[_pos++]; + Byte mask = 0x80; + UInt64 value = 0; + for (int i = 0; i < 8; i++) + { + if ((firstByte & mask) == 0) + { + UInt64 highPart = firstByte & (mask - 1); + value += (highPart << (i * 8)); + return value; + } + if (_pos >= _size) + ThrowEndOfData(); + value |= ((UInt64)_buffer[_pos++] << (8 * i)); + mask >>= 1; + } + return value; +} + +CNum CInByte2::ReadNum() +{ + UInt64 value = ReadNumber(); + if (value > kNumMax) + ThrowUnsupported(); + return (CNum)value; +} + +UInt32 CInByte2::ReadUInt32() +{ + if (_pos + 4 > _size) + ThrowEndOfData(); + UInt32 res = Get32(_buffer + _pos); + _pos += 4; + return res; +} + +UInt64 CInByte2::ReadUInt64() +{ + if (_pos + 8 > _size) + ThrowEndOfData(); + UInt64 res = Get64(_buffer + _pos); + _pos += 8; + return res; +} + +void CInByte2::ReadString(UString &s) +{ + const Byte *buf = _buffer + _pos; + size_t rem = (_size - _pos) / 2 * 2; + { + size_t i; + for (i = 0; i < rem; i += 2) + if (buf[i] == 0 && buf[i + 1] == 0) + break; + if (i == rem) + ThrowEndOfData(); + rem = i; + } + int len = (int)(rem / 2); + if (len < 0 || (size_t)len * 2 != rem) + ThrowUnsupported(); + wchar_t *p = s.GetBuffer(len); + int i; + for (i = 0; i < len; i++, buf += 2) + p[i] = (wchar_t)Get16(buf); + s.ReleaseBuffer(len); + _pos += rem + 2; +} + +static inline bool TestSignature(const Byte *p) +{ + for (int i = 0; i < kSignatureSize; i++) + if (p[i] != kSignature[i]) + return false; + return CrcCalc(p + 12, 20) == GetUi32(p + 8); +} + +#ifdef FORMAT_7Z_RECOVERY +static inline bool TestSignature2(const Byte *p) +{ + int i; + for (i = 0; i < kSignatureSize; i++) + if (p[i] != kSignature[i]) + return false; + if (CrcCalc(p + 12, 20) == GetUi32(p + 8)) + return true; + for (i = 8; i < kHeaderSize; i++) + if (p[i] != 0) + return false; + return (p[6] != 0 || p[7] != 0); +} +#else +#define TestSignature2(p) TestSignature(p) +#endif + +HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit) +{ + RINOK(ReadStream_FALSE(stream, _header, kHeaderSize)); + + if (TestSignature2(_header)) + return S_OK; + + CByteBuffer byteBuffer; + const UInt32 kBufferSize = (1 << 16); + byteBuffer.SetCapacity(kBufferSize); + Byte *buffer = byteBuffer; + UInt32 numPrevBytes = kHeaderSize; + memcpy(buffer, _header, kHeaderSize); + UInt64 curTestPos = _arhiveBeginStreamPosition; + for (;;) + { + if (searchHeaderSizeLimit != NULL) + if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit) + break; + do + { + UInt32 numReadBytes = kBufferSize - numPrevBytes; + UInt32 processedSize; + RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize)); + numPrevBytes += processedSize; + if (processedSize == 0) + return S_FALSE; + } + while (numPrevBytes <= kHeaderSize); + UInt32 numTests = numPrevBytes - kHeaderSize; + for (UInt32 pos = 0; pos < numTests; pos++) + { + for (; buffer[pos] != '7' && pos < numTests; pos++); + if (pos == numTests) + break; + if (TestSignature(buffer + pos)) + { + memcpy(_header, buffer + pos, kHeaderSize); + curTestPos += pos; + _arhiveBeginStreamPosition = curTestPos; + return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL); + } + } + curTestPos += numTests; + numPrevBytes -= numTests; + memmove(buffer, buffer + numTests, numPrevBytes); + } + return S_FALSE; +} + +// S_FALSE means that file is not archive +HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) +{ + HeadersSize = 0; + Close(); + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition)) + RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit)); + _stream = stream; + return S_OK; +} + +void CInArchive::Close() +{ + _stream.Release(); +} + +void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */) +{ + for (;;) + { + if (ReadID() == NID::kEnd) + break; + SkipData(); + } +} + +void CInArchive::GetNextFolderItem(CFolder &folder) +{ + CNum numCoders = ReadNum(); + + folder.Coders.Clear(); + folder.Coders.Reserve((int)numCoders); + CNum numInStreams = 0; + CNum numOutStreams = 0; + CNum i; + for (i = 0; i < numCoders; i++) + { + folder.Coders.Add(CCoderInfo()); + CCoderInfo &coder = folder.Coders.Back(); + + { + Byte mainByte = ReadByte(); + int idSize = (mainByte & 0xF); + Byte longID[15]; + ReadBytes(longID, idSize); + if (idSize > 8) + ThrowUnsupported(); + UInt64 id = 0; + for (int j = 0; j < idSize; j++) + id |= (UInt64)longID[idSize - 1 - j] << (8 * j); + coder.MethodID = id; + + if ((mainByte & 0x10) != 0) + { + coder.NumInStreams = ReadNum(); + coder.NumOutStreams = ReadNum(); + } + else + { + coder.NumInStreams = 1; + coder.NumOutStreams = 1; + } + if ((mainByte & 0x20) != 0) + { + CNum propsSize = ReadNum(); + coder.Props.SetCapacity((size_t)propsSize); + ReadBytes((Byte *)coder.Props, (size_t)propsSize); + } + if ((mainByte & 0x80) != 0) + ThrowUnsupported(); + } + numInStreams += coder.NumInStreams; + numOutStreams += coder.NumOutStreams; + } + + CNum numBindPairs = numOutStreams - 1; + folder.BindPairs.Clear(); + folder.BindPairs.Reserve(numBindPairs); + for (i = 0; i < numBindPairs; i++) + { + CBindPair bp; + bp.InIndex = ReadNum(); + bp.OutIndex = ReadNum(); + folder.BindPairs.Add(bp); + } + + if (numInStreams < numBindPairs) + ThrowUnsupported(); + CNum numPackStreams = numInStreams - numBindPairs; + folder.PackStreams.Reserve(numPackStreams); + if (numPackStreams == 1) + { + for (i = 0; i < numInStreams; i++) + if (folder.FindBindPairForInStream(i) < 0) + { + folder.PackStreams.Add(i); + break; + } + if (folder.PackStreams.Size() != 1) + ThrowUnsupported(); + } + else + for (i = 0; i < numPackStreams; i++) + folder.PackStreams.Add(ReadNum()); +} + +void CInArchive::WaitAttribute(UInt64 attribute) +{ + for (;;) + { + UInt64 type = ReadID(); + if (type == attribute) + return; + if (type == NID::kEnd) + ThrowIncorrect(); + SkipData(); + } +} + +void CInArchive::ReadHashDigests(int numItems, + CBoolVector &digestsDefined, + CRecordVector<UInt32> &digests) +{ + ReadBoolVector2(numItems, digestsDefined); + digests.Clear(); + digests.Reserve(numItems); + for (int i = 0; i < numItems; i++) + { + UInt32 crc = 0; + if (digestsDefined[i]) + crc = ReadUInt32(); + digests.Add(crc); + } +} + +void CInArchive::ReadPackInfo( + UInt64 &dataOffset, + CRecordVector<UInt64> &packSizes, + CBoolVector &packCRCsDefined, + CRecordVector<UInt32> &packCRCs) +{ + dataOffset = ReadNumber(); + CNum numPackStreams = ReadNum(); + + WaitAttribute(NID::kSize); + packSizes.Clear(); + packSizes.Reserve(numPackStreams); + for (CNum i = 0; i < numPackStreams; i++) + packSizes.Add(ReadNumber()); + + UInt64 type; + for (;;) + { + type = ReadID(); + if (type == NID::kEnd) + break; + if (type == NID::kCRC) + { + ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs); + continue; + } + SkipData(); + } + if (packCRCsDefined.IsEmpty()) + { + BoolVector_Fill_False(packCRCsDefined, numPackStreams); + packCRCs.Reserve(numPackStreams); + packCRCs.Clear(); + for (CNum i = 0; i < numPackStreams; i++) + packCRCs.Add(0); + } +} + +void CInArchive::ReadUnpackInfo( + const CObjectVector<CByteBuffer> *dataVector, + CObjectVector<CFolder> &folders) +{ + WaitAttribute(NID::kFolder); + CNum numFolders = ReadNum(); + + { + CStreamSwitch streamSwitch; + streamSwitch.Set(this, dataVector); + folders.Clear(); + folders.Reserve(numFolders); + for (CNum i = 0; i < numFolders; i++) + { + folders.Add(CFolder()); + GetNextFolderItem(folders.Back()); + } + } + + WaitAttribute(NID::kCodersUnpackSize); + + CNum i; + for (i = 0; i < numFolders; i++) + { + CFolder &folder = folders[i]; + CNum numOutStreams = folder.GetNumOutStreams(); + folder.UnpackSizes.Reserve(numOutStreams); + for (CNum j = 0; j < numOutStreams; j++) + folder.UnpackSizes.Add(ReadNumber()); + } + + for (;;) + { + UInt64 type = ReadID(); + if (type == NID::kEnd) + return; + if (type == NID::kCRC) + { + CBoolVector crcsDefined; + CRecordVector<UInt32> crcs; + ReadHashDigests(numFolders, crcsDefined, crcs); + for (i = 0; i < numFolders; i++) + { + CFolder &folder = folders[i]; + folder.UnpackCRCDefined = crcsDefined[i]; + folder.UnpackCRC = crcs[i]; + } + continue; + } + SkipData(); + } +} + +void CInArchive::ReadSubStreamsInfo( + const CObjectVector<CFolder> &folders, + CRecordVector<CNum> &numUnpackStreamsInFolders, + CRecordVector<UInt64> &unpackSizes, + CBoolVector &digestsDefined, + CRecordVector<UInt32> &digests) +{ + numUnpackStreamsInFolders.Clear(); + numUnpackStreamsInFolders.Reserve(folders.Size()); + UInt64 type; + for (;;) + { + type = ReadID(); + if (type == NID::kNumUnpackStream) + { + for (int i = 0; i < folders.Size(); i++) + numUnpackStreamsInFolders.Add(ReadNum()); + continue; + } + if (type == NID::kCRC || type == NID::kSize) + break; + if (type == NID::kEnd) + break; + SkipData(); + } + + if (numUnpackStreamsInFolders.IsEmpty()) + for (int i = 0; i < folders.Size(); i++) + numUnpackStreamsInFolders.Add(1); + + int i; + for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) + { + // v3.13 incorrectly worked with empty folders + // v4.07: we check that folder is empty + CNum numSubstreams = numUnpackStreamsInFolders[i]; + if (numSubstreams == 0) + continue; + UInt64 sum = 0; + for (CNum j = 1; j < numSubstreams; j++) + if (type == NID::kSize) + { + UInt64 size = ReadNumber(); + unpackSizes.Add(size); + sum += size; + } + unpackSizes.Add(folders[i].GetUnpackSize() - sum); + } + if (type == NID::kSize) + type = ReadID(); + + int numDigests = 0; + int numDigestsTotal = 0; + for (i = 0; i < folders.Size(); i++) + { + CNum numSubstreams = numUnpackStreamsInFolders[i]; + if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) + numDigests += numSubstreams; + numDigestsTotal += numSubstreams; + } + + for (;;) + { + if (type == NID::kCRC) + { + CBoolVector digestsDefined2; + CRecordVector<UInt32> digests2; + ReadHashDigests(numDigests, digestsDefined2, digests2); + int digestIndex = 0; + for (i = 0; i < folders.Size(); i++) + { + CNum numSubstreams = numUnpackStreamsInFolders[i]; + const CFolder &folder = folders[i]; + if (numSubstreams == 1 && folder.UnpackCRCDefined) + { + digestsDefined.Add(true); + digests.Add(folder.UnpackCRC); + } + else + for (CNum j = 0; j < numSubstreams; j++, digestIndex++) + { + digestsDefined.Add(digestsDefined2[digestIndex]); + digests.Add(digests2[digestIndex]); + } + } + } + else if (type == NID::kEnd) + { + if (digestsDefined.IsEmpty()) + { + BoolVector_Fill_False(digestsDefined, numDigestsTotal); + digests.Clear(); + for (int i = 0; i < numDigestsTotal; i++) + digests.Add(0); + } + return; + } + else + SkipData(); + type = ReadID(); + } +} + +void CInArchive::ReadStreamsInfo( + const CObjectVector<CByteBuffer> *dataVector, + UInt64 &dataOffset, + CRecordVector<UInt64> &packSizes, + CBoolVector &packCRCsDefined, + CRecordVector<UInt32> &packCRCs, + CObjectVector<CFolder> &folders, + CRecordVector<CNum> &numUnpackStreamsInFolders, + CRecordVector<UInt64> &unpackSizes, + CBoolVector &digestsDefined, + CRecordVector<UInt32> &digests) +{ + for (;;) + { + UInt64 type = ReadID(); + if (type > ((UInt32)1 << 30)) + ThrowIncorrect(); + switch((UInt32)type) + { + case NID::kEnd: + return; + case NID::kPackInfo: + { + ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs); + break; + } + case NID::kUnpackInfo: + { + ReadUnpackInfo(dataVector, folders); + break; + } + case NID::kSubStreamsInfo: + { + ReadSubStreamsInfo(folders, numUnpackStreamsInFolders, + unpackSizes, digestsDefined, digests); + break; + } + default: + ThrowIncorrect(); + } + } +} + +void CInArchive::ReadBoolVector(int numItems, CBoolVector &v) +{ + v.Clear(); + v.Reserve(numItems); + Byte b = 0; + Byte mask = 0; + for (int i = 0; i < numItems; i++) + { + if (mask == 0) + { + b = ReadByte(); + mask = 0x80; + } + v.Add((b & mask) != 0); + mask >>= 1; + } +} + +void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v) +{ + Byte allAreDefined = ReadByte(); + if (allAreDefined == 0) + { + ReadBoolVector(numItems, v); + return; + } + v.Clear(); + v.Reserve(numItems); + for (int i = 0; i < numItems; i++) + v.Add(true); +} + +void CInArchive::ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector, + CUInt64DefVector &v, int numFiles) +{ + ReadBoolVector2(numFiles, v.Defined); + + CStreamSwitch streamSwitch; + streamSwitch.Set(this, &dataVector); + v.Values.Reserve(numFiles); + + for (int i = 0; i < numFiles; i++) + { + UInt64 t = 0; + if (v.Defined[i]) + t = ReadUInt64(); + v.Values.Add(t); + } +} + +HRESULT CInArchive::ReadAndDecodePackedStreams( + DECL_EXTERNAL_CODECS_LOC_VARS + UInt64 baseOffset, + UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined + #endif + ) +{ + CRecordVector<UInt64> packSizes; + CBoolVector packCRCsDefined; + CRecordVector<UInt32> packCRCs; + CObjectVector<CFolder> folders; + + CRecordVector<CNum> numUnpackStreamsInFolders; + CRecordVector<UInt64> unpackSizes; + CBoolVector digestsDefined; + CRecordVector<UInt32> digests; + + ReadStreamsInfo(NULL, + dataOffset, + packSizes, + packCRCsDefined, + packCRCs, + folders, + numUnpackStreamsInFolders, + unpackSizes, + digestsDefined, + digests); + + // db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader; + + CNum packIndex = 0; + CDecoder decoder( + #ifdef _ST_MODE + false + #else + true + #endif + ); + UInt64 dataStartPos = baseOffset + dataOffset; + for (int i = 0; i < folders.Size(); i++) + { + const CFolder &folder = folders[i]; + dataVector.Add(CByteBuffer()); + CByteBuffer &data = dataVector.Back(); + UInt64 unpackSize64 = folder.GetUnpackSize(); + size_t unpackSize = (size_t)unpackSize64; + if (unpackSize != unpackSize64) + ThrowUnsupported(); + data.SetCapacity(unpackSize); + + CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; + CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; + outStreamSpec->Init(data, unpackSize); + + HRESULT result = decoder.Decode( + EXTERNAL_CODECS_LOC_VARS + _stream, dataStartPos, + &packSizes[packIndex], folder, outStream, NULL + #ifndef _NO_CRYPTO + , getTextPassword, passwordIsDefined + #endif + #if !defined(_7ZIP_ST) && !defined(_SFX) + , false, 1 + #endif + ); + RINOK(result); + + if (folder.UnpackCRCDefined) + if (CrcCalc(data, unpackSize) != folder.UnpackCRC) + ThrowIncorrect(); + for (int j = 0; j < folder.PackStreams.Size(); j++) + { + UInt64 packSize = packSizes[packIndex++]; + dataStartPos += packSize; + HeadersSize += packSize; + } + } + return S_OK; +} + +HRESULT CInArchive::ReadHeader( + DECL_EXTERNAL_CODECS_LOC_VARS + CArchiveDatabaseEx &db + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined + #endif + ) +{ + UInt64 type = ReadID(); + + if (type == NID::kArchiveProperties) + { + ReadArchiveProperties(db.ArchiveInfo); + type = ReadID(); + } + + CObjectVector<CByteBuffer> dataVector; + + if (type == NID::kAdditionalStreamsInfo) + { + HRESULT result = ReadAndDecodePackedStreams( + EXTERNAL_CODECS_LOC_VARS + db.ArchiveInfo.StartPositionAfterHeader, + db.ArchiveInfo.DataStartPosition2, + dataVector + #ifndef _NO_CRYPTO + , getTextPassword, passwordIsDefined + #endif + ); + RINOK(result); + db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader; + type = ReadID(); + } + + CRecordVector<UInt64> unpackSizes; + CBoolVector digestsDefined; + CRecordVector<UInt32> digests; + + if (type == NID::kMainStreamsInfo) + { + ReadStreamsInfo(&dataVector, + db.ArchiveInfo.DataStartPosition, + db.PackSizes, + db.PackCRCsDefined, + db.PackCRCs, + db.Folders, + db.NumUnpackStreamsVector, + unpackSizes, + digestsDefined, + digests); + db.ArchiveInfo.DataStartPosition += db.ArchiveInfo.StartPositionAfterHeader; + type = ReadID(); + } + else + { + for (int i = 0; i < db.Folders.Size(); i++) + { + db.NumUnpackStreamsVector.Add(1); + CFolder &folder = db.Folders[i]; + unpackSizes.Add(folder.GetUnpackSize()); + digestsDefined.Add(folder.UnpackCRCDefined); + digests.Add(folder.UnpackCRC); + } + } + + db.Files.Clear(); + + if (type == NID::kEnd) + return S_OK; + if (type != NID::kFilesInfo) + ThrowIncorrect(); + + CNum numFiles = ReadNum(); + db.Files.Reserve(numFiles); + CNum i; + for (i = 0; i < numFiles; i++) + db.Files.Add(CFileItem()); + + db.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize); + if (!db.PackSizes.IsEmpty()) + db.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo); + if (numFiles > 0 && !digests.IsEmpty()) + db.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC); + + CBoolVector emptyStreamVector; + BoolVector_Fill_False(emptyStreamVector, (int)numFiles); + CBoolVector emptyFileVector; + CBoolVector antiFileVector; + CNum numEmptyStreams = 0; + + for (;;) + { + UInt64 type = ReadID(); + if (type == NID::kEnd) + break; + UInt64 size = ReadNumber(); + size_t ppp = _inByteBack->_pos; + bool addPropIdToList = true; + bool isKnownType = true; + if (type > ((UInt32)1 << 30)) + isKnownType = false; + else switch((UInt32)type) + { + case NID::kName: + { + CStreamSwitch streamSwitch; + streamSwitch.Set(this, &dataVector); + for (int i = 0; i < db.Files.Size(); i++) + _inByteBack->ReadString(db.Files[i].Name); + break; + } + case NID::kWinAttributes: + { + CBoolVector boolVector; + ReadBoolVector2(db.Files.Size(), boolVector); + CStreamSwitch streamSwitch; + streamSwitch.Set(this, &dataVector); + for (i = 0; i < numFiles; i++) + { + CFileItem &file = db.Files[i]; + file.AttribDefined = boolVector[i]; + if (file.AttribDefined) + file.Attrib = ReadUInt32(); + } + break; + } + case NID::kEmptyStream: + { + ReadBoolVector(numFiles, emptyStreamVector); + for (i = 0; i < (CNum)emptyStreamVector.Size(); i++) + if (emptyStreamVector[i]) + numEmptyStreams++; + + BoolVector_Fill_False(emptyFileVector, numEmptyStreams); + BoolVector_Fill_False(antiFileVector, numEmptyStreams); + + break; + } + case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break; + case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break; + case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (int)numFiles); break; + case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (int)numFiles); break; + case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (int)numFiles); break; + case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (int)numFiles); break; + case NID::kDummy: + { + for (UInt64 j = 0; j < size; j++) + if (ReadByte() != 0) + ThrowIncorrect(); + addPropIdToList = false; + break; + } + default: + addPropIdToList = isKnownType = false; + } + if (isKnownType) + { + if(addPropIdToList) + db.ArchiveInfo.FileInfoPopIDs.Add(type); + } + else + SkipData(size); + bool checkRecordsSize = (db.ArchiveInfo.Version.Major > 0 || + db.ArchiveInfo.Version.Minor > 2); + if (checkRecordsSize && _inByteBack->_pos - ppp != size) + ThrowIncorrect(); + } + + CNum emptyFileIndex = 0; + CNum sizeIndex = 0; + + CNum numAntiItems = 0; + for (i = 0; i < numEmptyStreams; i++) + if (antiFileVector[i]) + numAntiItems++; + + for (i = 0; i < numFiles; i++) + { + CFileItem &file = db.Files[i]; + bool isAnti; + file.HasStream = !emptyStreamVector[i]; + if (file.HasStream) + { + file.IsDir = false; + isAnti = false; + file.Size = unpackSizes[sizeIndex]; + file.Crc = digests[sizeIndex]; + file.CrcDefined = digestsDefined[sizeIndex]; + sizeIndex++; + } + else + { + file.IsDir = !emptyFileVector[emptyFileIndex]; + isAnti = antiFileVector[emptyFileIndex]; + emptyFileIndex++; + file.Size = 0; + file.CrcDefined = false; + } + if (numAntiItems != 0) + db.IsAnti.Add(isAnti); + } + return S_OK; +} + + +void CArchiveDatabaseEx::FillFolderStartPackStream() +{ + FolderStartPackStreamIndex.Clear(); + FolderStartPackStreamIndex.Reserve(Folders.Size()); + CNum startPos = 0; + for (int i = 0; i < Folders.Size(); i++) + { + FolderStartPackStreamIndex.Add(startPos); + startPos += (CNum)Folders[i].PackStreams.Size(); + } +} + +void CArchiveDatabaseEx::FillStartPos() +{ + PackStreamStartPositions.Clear(); + PackStreamStartPositions.Reserve(PackSizes.Size()); + UInt64 startPos = 0; + for (int i = 0; i < PackSizes.Size(); i++) + { + PackStreamStartPositions.Add(startPos); + startPos += PackSizes[i]; + } +} + +void CArchiveDatabaseEx::FillFolderStartFileIndex() +{ + FolderStartFileIndex.Clear(); + FolderStartFileIndex.Reserve(Folders.Size()); + FileIndexToFolderIndexMap.Clear(); + FileIndexToFolderIndexMap.Reserve(Files.Size()); + + int folderIndex = 0; + CNum indexInFolder = 0; + for (int i = 0; i < Files.Size(); i++) + { + const CFileItem &file = Files[i]; + bool emptyStream = !file.HasStream; + if (emptyStream && indexInFolder == 0) + { + FileIndexToFolderIndexMap.Add(kNumNoIndex); + continue; + } + if (indexInFolder == 0) + { + // v3.13 incorrectly worked with empty folders + // v4.07: Loop for skipping empty folders + for (;;) + { + if (folderIndex >= Folders.Size()) + ThrowIncorrect(); + FolderStartFileIndex.Add(i); // check it + if (NumUnpackStreamsVector[folderIndex] != 0) + break; + folderIndex++; + } + } + FileIndexToFolderIndexMap.Add(folderIndex); + if (emptyStream) + continue; + indexInFolder++; + if (indexInFolder >= NumUnpackStreamsVector[folderIndex]) + { + folderIndex++; + indexInFolder = 0; + } + } +} + +HRESULT CInArchive::ReadDatabase2( + DECL_EXTERNAL_CODECS_LOC_VARS + CArchiveDatabaseEx &db + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined + #endif + ) +{ + db.Clear(); + db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition; + + db.ArchiveInfo.Version.Major = _header[6]; + db.ArchiveInfo.Version.Minor = _header[7]; + + if (db.ArchiveInfo.Version.Major != kMajorVersion) + ThrowUnsupportedVersion(); + + UInt32 crcFromArchive = Get32(_header + 8); + UInt64 nextHeaderOffset = Get64(_header + 0xC); + UInt64 nextHeaderSize = Get64(_header + 0x14); + UInt32 nextHeaderCRC = Get32(_header + 0x1C); + UInt32 crc = CrcCalc(_header + 0xC, 20); + + #ifdef FORMAT_7Z_RECOVERY + if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0) + { + UInt64 cur, cur2; + RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur)); + const int kCheckSize = 500; + Byte buf[kCheckSize]; + RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2)); + int checkSize = kCheckSize; + if (cur2 - cur < kCheckSize) + checkSize = (int)(cur2 - cur); + RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2)); + + RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize)); + + int i; + for (i = (int)checkSize - 2; i >= 0; i--) + if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04) + break; + if (i < 0) + return S_FALSE; + nextHeaderSize = checkSize - i; + nextHeaderOffset = cur2 - cur + i; + nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize); + RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL)); + } + else + #endif + { + if (crc != crcFromArchive) + ThrowIncorrect(); + } + + db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize; + + if (nextHeaderSize == 0) + return S_OK; + + if (nextHeaderSize > (UInt64)0xFFFFFFFF) + return S_FALSE; + + if ((Int64)nextHeaderOffset < 0) + return S_FALSE; + + RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL)); + + CByteBuffer buffer2; + buffer2.SetCapacity((size_t)nextHeaderSize); + + RINOK(ReadStream_FALSE(_stream, buffer2, (size_t)nextHeaderSize)); + HeadersSize += kHeaderSize + nextHeaderSize; + db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize; + + if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC) + ThrowIncorrect(); + + CStreamSwitch streamSwitch; + streamSwitch.Set(this, buffer2); + + CObjectVector<CByteBuffer> dataVector; + + UInt64 type = ReadID(); + if (type != NID::kHeader) + { + if (type != NID::kEncodedHeader) + ThrowIncorrect(); + HRESULT result = ReadAndDecodePackedStreams( + EXTERNAL_CODECS_LOC_VARS + db.ArchiveInfo.StartPositionAfterHeader, + db.ArchiveInfo.DataStartPosition2, + dataVector + #ifndef _NO_CRYPTO + , getTextPassword, passwordIsDefined + #endif + ); + RINOK(result); + if (dataVector.Size() == 0) + return S_OK; + if (dataVector.Size() > 1) + ThrowIncorrect(); + streamSwitch.Remove(); + streamSwitch.Set(this, dataVector.Front()); + if (ReadID() != NID::kHeader) + ThrowIncorrect(); + } + + db.HeadersSize = HeadersSize; + + return ReadHeader( + EXTERNAL_CODECS_LOC_VARS + db + #ifndef _NO_CRYPTO + , getTextPassword, passwordIsDefined + #endif + ); +} + +HRESULT CInArchive::ReadDatabase( + DECL_EXTERNAL_CODECS_LOC_VARS + CArchiveDatabaseEx &db + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined + #endif + ) +{ + try + { + return ReadDatabase2( + EXTERNAL_CODECS_LOC_VARS db + #ifndef _NO_CRYPTO + , getTextPassword, passwordIsDefined + #endif + ); + } + catch(CInArchiveException &) { return S_FALSE; } +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.h new file mode 100644 index 000000000..971f27b2a --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zIn.h @@ -0,0 +1,245 @@ +// 7zIn.h + +#ifndef __7Z_IN_H +#define __7Z_IN_H + +#include "../../../Common/MyCom.h" + +#include "../../IPassword.h" +#include "../../IStream.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/InBuffer.h" + +#include "7zItem.h" + +namespace NArchive { +namespace N7z { + +struct CInArchiveInfo +{ + CArchiveVersion Version; + UInt64 StartPosition; + UInt64 StartPositionAfterHeader; + UInt64 DataStartPosition; + UInt64 DataStartPosition2; + CRecordVector<UInt64> FileInfoPopIDs; + void Clear() + { + FileInfoPopIDs.Clear(); + } +}; + +struct CArchiveDatabaseEx: public CArchiveDatabase +{ + CInArchiveInfo ArchiveInfo; + CRecordVector<UInt64> PackStreamStartPositions; + CRecordVector<CNum> FolderStartPackStreamIndex; + CRecordVector<CNum> FolderStartFileIndex; + CRecordVector<CNum> FileIndexToFolderIndexMap; + + UInt64 HeadersSize; + UInt64 PhySize; + + void Clear() + { + CArchiveDatabase::Clear(); + ArchiveInfo.Clear(); + PackStreamStartPositions.Clear(); + FolderStartPackStreamIndex.Clear(); + FolderStartFileIndex.Clear(); + FileIndexToFolderIndexMap.Clear(); + + HeadersSize = 0; + PhySize = 0; + } + + void FillFolderStartPackStream(); + void FillStartPos(); + void FillFolderStartFileIndex(); + + void Fill() + { + FillFolderStartPackStream(); + FillStartPos(); + FillFolderStartFileIndex(); + } + + UInt64 GetFolderStreamPos(int folderIndex, int indexInFolder) const + { + return ArchiveInfo.DataStartPosition + + PackStreamStartPositions[FolderStartPackStreamIndex[folderIndex] + indexInFolder]; + } + + UInt64 GetFolderFullPackSize(int folderIndex) const + { + CNum packStreamIndex = FolderStartPackStreamIndex[folderIndex]; + const CFolder &folder = Folders[folderIndex]; + UInt64 size = 0; + for (int i = 0; i < folder.PackStreams.Size(); i++) + size += PackSizes[packStreamIndex + i]; + return size; + } + + UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const + { + return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex]; + } + + UInt64 GetFilePackSize(CNum fileIndex) const + { + CNum folderIndex = FileIndexToFolderIndexMap[fileIndex]; + if (folderIndex != kNumNoIndex) + if (FolderStartFileIndex[folderIndex] == fileIndex) + return GetFolderFullPackSize(folderIndex); + return 0; + } +}; + +class CInByte2 +{ + const Byte *_buffer; + size_t _size; +public: + size_t _pos; + void Init(const Byte *buffer, size_t size) + { + _buffer = buffer; + _size = size; + _pos = 0; + } + Byte ReadByte(); + void ReadBytes(Byte *data, size_t size); + void SkipData(UInt64 size); + void SkipData(); + UInt64 ReadNumber(); + CNum ReadNum(); + UInt32 ReadUInt32(); + UInt64 ReadUInt64(); + void ReadString(UString &s); +}; + +class CStreamSwitch; + +const UInt32 kHeaderSize = 32; + +class CInArchive +{ + friend class CStreamSwitch; + + CMyComPtr<IInStream> _stream; + + CObjectVector<CInByte2> _inByteVector; + CInByte2 *_inByteBack; + + UInt64 _arhiveBeginStreamPosition; + + Byte _header[kHeaderSize]; + + UInt64 HeadersSize; + + void AddByteStream(const Byte *buffer, size_t size) + { + _inByteVector.Add(CInByte2()); + _inByteBack = &_inByteVector.Back(); + _inByteBack->Init(buffer, size); + } + + void DeleteByteStream() + { + _inByteVector.DeleteBack(); + if (!_inByteVector.IsEmpty()) + _inByteBack = &_inByteVector.Back(); + } + +private: + HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit); + + void ReadBytes(Byte *data, size_t size) { _inByteBack->ReadBytes(data, size); } + Byte ReadByte() { return _inByteBack->ReadByte(); } + UInt64 ReadNumber() { return _inByteBack->ReadNumber(); } + CNum ReadNum() { return _inByteBack->ReadNum(); } + UInt64 ReadID() { return _inByteBack->ReadNumber(); } + UInt32 ReadUInt32() { return _inByteBack->ReadUInt32(); } + UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); } + void SkipData(UInt64 size) { _inByteBack->SkipData(size); } + void SkipData() { _inByteBack->SkipData(); } + void WaitAttribute(UInt64 attribute); + + void ReadArchiveProperties(CInArchiveInfo &archiveInfo); + void GetNextFolderItem(CFolder &itemInfo); + void ReadHashDigests(int numItems, + CBoolVector &digestsDefined, CRecordVector<UInt32> &digests); + + void ReadPackInfo( + UInt64 &dataOffset, + CRecordVector<UInt64> &packSizes, + CBoolVector &packCRCsDefined, + CRecordVector<UInt32> &packCRCs); + + void ReadUnpackInfo( + const CObjectVector<CByteBuffer> *dataVector, + CObjectVector<CFolder> &folders); + + void ReadSubStreamsInfo( + const CObjectVector<CFolder> &folders, + CRecordVector<CNum> &numUnpackStreamsInFolders, + CRecordVector<UInt64> &unpackSizes, + CBoolVector &digestsDefined, + CRecordVector<UInt32> &digests); + + void ReadStreamsInfo( + const CObjectVector<CByteBuffer> *dataVector, + UInt64 &dataOffset, + CRecordVector<UInt64> &packSizes, + CBoolVector &packCRCsDefined, + CRecordVector<UInt32> &packCRCs, + CObjectVector<CFolder> &folders, + CRecordVector<CNum> &numUnpackStreamsInFolders, + CRecordVector<UInt64> &unpackSizes, + CBoolVector &digestsDefined, + CRecordVector<UInt32> &digests); + + + void ReadBoolVector(int numItems, CBoolVector &v); + void ReadBoolVector2(int numItems, CBoolVector &v); + void ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector, + CUInt64DefVector &v, int numFiles); + HRESULT ReadAndDecodePackedStreams( + DECL_EXTERNAL_CODECS_LOC_VARS + UInt64 baseOffset, UInt64 &dataOffset, + CObjectVector<CByteBuffer> &dataVector + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined + #endif + ); + HRESULT ReadHeader( + DECL_EXTERNAL_CODECS_LOC_VARS + CArchiveDatabaseEx &db + #ifndef _NO_CRYPTO + ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined + #endif + ); + HRESULT ReadDatabase2( + DECL_EXTERNAL_CODECS_LOC_VARS + CArchiveDatabaseEx &db + #ifndef _NO_CRYPTO + ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined + #endif + ); +public: + HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive + void Close(); + + HRESULT ReadDatabase( + DECL_EXTERNAL_CODECS_LOC_VARS + CArchiveDatabaseEx &db + #ifndef _NO_CRYPTO + ,ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined + #endif + ); +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zItem.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zItem.h new file mode 100644 index 000000000..34f10775c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zItem.h @@ -0,0 +1,268 @@ +// 7zItem.h + +#ifndef __7Z_ITEM_H +#define __7Z_ITEM_H + +#include "../../../Common/Buffer.h" +#include "../../../Common/MyString.h" + +#include "../../Common/MethodId.h" + +#include "7zHeader.h" + +namespace NArchive { +namespace N7z { + +const UInt64 k_AES = 0x06F10701; + +typedef UInt32 CNum; +const CNum kNumMax = 0x7FFFFFFF; +const CNum kNumNoIndex = 0xFFFFFFFF; + +struct CCoderInfo +{ + CMethodId MethodID; + CByteBuffer Props; + CNum NumInStreams; + CNum NumOutStreams; + bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); } +}; + +struct CBindPair +{ + CNum InIndex; + CNum OutIndex; +}; + +struct CFolder +{ + CObjectVector<CCoderInfo> Coders; + CRecordVector<CBindPair> BindPairs; + CRecordVector<CNum> PackStreams; + CRecordVector<UInt64> UnpackSizes; + UInt32 UnpackCRC; + bool UnpackCRCDefined; + + CFolder(): UnpackCRCDefined(false) {} + + UInt64 GetUnpackSize() const // test it + { + if (UnpackSizes.IsEmpty()) + return 0; + for (int i = UnpackSizes.Size() - 1; i >= 0; i--) + if (FindBindPairForOutStream(i) < 0) + return UnpackSizes[i]; + throw 1; + } + + CNum GetNumOutStreams() const + { + CNum result = 0; + for (int i = 0; i < Coders.Size(); i++) + result += Coders[i].NumOutStreams; + return result; + } + + int FindBindPairForInStream(CNum inStreamIndex) const + { + for(int i = 0; i < BindPairs.Size(); i++) + if (BindPairs[i].InIndex == inStreamIndex) + return i; + return -1; + } + int FindBindPairForOutStream(CNum outStreamIndex) const + { + for(int i = 0; i < BindPairs.Size(); i++) + if (BindPairs[i].OutIndex == outStreamIndex) + return i; + return -1; + } + int FindPackStreamArrayIndex(CNum inStreamIndex) const + { + for(int i = 0; i < PackStreams.Size(); i++) + if (PackStreams[i] == inStreamIndex) + return i; + return -1; + } + + bool IsEncrypted() const + { + for (int i = Coders.Size() - 1; i >= 0; i--) + if (Coders[i].MethodID == k_AES) + return true; + return false; + } + + bool CheckStructure() const; +}; + +struct CUInt64DefVector +{ + CRecordVector<UInt64> Values; + CRecordVector<bool> Defined; + + void Clear() + { + Values.Clear(); + Defined.Clear(); + } + + void ReserveDown() + { + Values.ReserveDown(); + Values.ReserveDown(); + } + + bool GetItem(int index, UInt64 &value) const + { + if (index < Defined.Size() && Defined[index]) + { + value = Values[index]; + return true; + } + value = 0; + return false; + } + + void SetItem(int index, bool defined, UInt64 value) + { + while (index >= Defined.Size()) + Defined.Add(false); + Defined[index] = defined; + if (!defined) + return; + while (index >= Values.Size()) + Values.Add(0); + Values[index] = value; + } + + bool CheckSize(int size) const { return Defined.Size() == size || Defined.Size() == 0; } +}; + +struct CFileItem +{ + UInt64 Size; + UInt32 Attrib; + UInt32 Crc; + UString Name; + + bool HasStream; // Test it !!! it means that there is + // stream in some folder. It can be empty stream + bool IsDir; + bool CrcDefined; + bool AttribDefined; + + CFileItem(): + HasStream(true), + IsDir(false), + CrcDefined(false), + AttribDefined(false) + {} + void SetAttrib(UInt32 attrib) + { + AttribDefined = true; + Attrib = attrib; + } +}; + +struct CFileItem2 +{ + UInt64 CTime; + UInt64 ATime; + UInt64 MTime; + UInt64 StartPos; + bool CTimeDefined; + bool ATimeDefined; + bool MTimeDefined; + bool StartPosDefined; + bool IsAnti; +}; + +struct CArchiveDatabase +{ + CRecordVector<UInt64> PackSizes; + CRecordVector<bool> PackCRCsDefined; + CRecordVector<UInt32> PackCRCs; + CObjectVector<CFolder> Folders; + CRecordVector<CNum> NumUnpackStreamsVector; + CObjectVector<CFileItem> Files; + + CUInt64DefVector CTime; + CUInt64DefVector ATime; + CUInt64DefVector MTime; + CUInt64DefVector StartPos; + CRecordVector<bool> IsAnti; + + void Clear() + { + PackSizes.Clear(); + PackCRCsDefined.Clear(); + PackCRCs.Clear(); + Folders.Clear(); + NumUnpackStreamsVector.Clear(); + Files.Clear(); + CTime.Clear(); + ATime.Clear(); + MTime.Clear(); + StartPos.Clear(); + IsAnti.Clear(); + } + + void ReserveDown() + { + PackSizes.ReserveDown(); + PackCRCsDefined.ReserveDown(); + PackCRCs.ReserveDown(); + Folders.ReserveDown(); + NumUnpackStreamsVector.ReserveDown(); + Files.ReserveDown(); + CTime.ReserveDown(); + ATime.ReserveDown(); + MTime.ReserveDown(); + StartPos.ReserveDown(); + IsAnti.ReserveDown(); + } + + bool IsEmpty() const + { + return (PackSizes.IsEmpty() && + PackCRCsDefined.IsEmpty() && + PackCRCs.IsEmpty() && + Folders.IsEmpty() && + NumUnpackStreamsVector.IsEmpty() && + Files.IsEmpty()); + } + + bool CheckNumFiles() const + { + int size = Files.Size(); + return ( + CTime.CheckSize(size) && + ATime.CheckSize(size) && + MTime.CheckSize(size) && + StartPos.CheckSize(size) && + (size == IsAnti.Size() || IsAnti.Size() == 0)); + } + + bool IsSolid() const + { + for (int i = 0; i < NumUnpackStreamsVector.Size(); i++) + if (NumUnpackStreamsVector[i] > 1) + return true; + return false; + } + bool IsItemAnti(int index) const { return (index < IsAnti.Size() && IsAnti[index]); } + void SetItemAnti(int index, bool isAnti) + { + while (index >= IsAnti.Size()) + IsAnti.Add(false); + IsAnti[index] = isAnti; + } + + void GetFile(int index, CFileItem &file, CFileItem2 &file2) const; + void AddFile(const CFileItem &file, const CFileItem2 &file2); +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.cpp new file mode 100644 index 000000000..0c8aa7e8c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.cpp @@ -0,0 +1,866 @@ +// 7zOut.cpp + +#include "StdAfx.h" + +#include "../../../../C/7zCrc.h" + +#include "../../../Common/AutoPtr.h" + +#include "../../Common/StreamObjects.h" + +#include "7zOut.h" + +static HRESULT WriteBytes(ISequentialOutStream *stream, const void *data, size_t size) +{ + while (size > 0) + { + UInt32 curSize = (UInt32)MyMin(size, (size_t)0xFFFFFFFF); + UInt32 processedSize; + RINOK(stream->Write(data, curSize, &processedSize)); + if (processedSize == 0) + return E_FAIL; + data = (const void *)((const Byte *)data + processedSize); + size -= processedSize; + } + return S_OK; +} + +namespace NArchive { +namespace N7z { + +HRESULT COutArchive::WriteDirect(const void *data, UInt32 size) +{ + return ::WriteBytes(SeqStream, data, size); +} + +HRESULT COutArchive::WriteSignature() +{ + Byte buf[8]; + memcpy(buf, kSignature, kSignatureSize); + buf[kSignatureSize] = kMajorVersion; + buf[kSignatureSize + 1] = 3; + return WriteDirect(buf, 8); +} + +#ifdef _7Z_VOL +HRESULT COutArchive::WriteFinishSignature() +{ + RINOK(WriteDirect(kFinishSignature, kSignatureSize)); + CArchiveVersion av; + av.Major = kMajorVersion; + av.Minor = 2; + RINOK(WriteDirectByte(av.Major)); + return WriteDirectByte(av.Minor); +} +#endif + +static void SetUInt32(Byte *p, UInt32 d) +{ + for (int i = 0; i < 4; i++, d >>= 8) + p[i] = (Byte)d; +} + +static void SetUInt64(Byte *p, UInt64 d) +{ + for (int i = 0; i < 8; i++, d >>= 8) + p[i] = (Byte)d; +} + +HRESULT COutArchive::WriteStartHeader(const CStartHeader &h) +{ + Byte buf[24]; + SetUInt64(buf + 4, h.NextHeaderOffset); + SetUInt64(buf + 12, h.NextHeaderSize); + SetUInt32(buf + 20, h.NextHeaderCRC); + SetUInt32(buf, CrcCalc(buf + 4, 20)); + return WriteDirect(buf, 24); +} + +#ifdef _7Z_VOL +HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h) +{ + CCRC crc; + crc.UpdateUInt64(h.NextHeaderOffset); + crc.UpdateUInt64(h.NextHeaderSize); + crc.UpdateUInt32(h.NextHeaderCRC); + crc.UpdateUInt64(h.ArchiveStartOffset); + crc.UpdateUInt64(h.AdditionalStartBlockSize); + RINOK(WriteDirectUInt32(crc.GetDigest())); + RINOK(WriteDirectUInt64(h.NextHeaderOffset)); + RINOK(WriteDirectUInt64(h.NextHeaderSize)); + RINOK(WriteDirectUInt32(h.NextHeaderCRC)); + RINOK(WriteDirectUInt64(h.ArchiveStartOffset)); + return WriteDirectUInt64(h.AdditionalStartBlockSize); +} +#endif + +HRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker) +{ + Close(); + #ifdef _7Z_VOL + // endMarker = false; + _endMarker = endMarker; + #endif + SeqStream = stream; + if (!endMarker) + { + SeqStream.QueryInterface(IID_IOutStream, &Stream); + if (!Stream) + { + return E_NOTIMPL; + // endMarker = true; + } + } + #ifdef _7Z_VOL + if (endMarker) + { + /* + CStartHeader sh; + sh.NextHeaderOffset = (UInt32)(Int32)-1; + sh.NextHeaderSize = (UInt32)(Int32)-1; + sh.NextHeaderCRC = 0; + WriteStartHeader(sh); + */ + } + else + #endif + { + if (!Stream) + return E_FAIL; + RINOK(WriteSignature()); + RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos)); + } + return S_OK; +} + +void COutArchive::Close() +{ + SeqStream.Release(); + Stream.Release(); +} + +HRESULT COutArchive::SkipPrefixArchiveHeader() +{ + #ifdef _7Z_VOL + if (_endMarker) + return S_OK; + #endif + return Stream->Seek(24, STREAM_SEEK_CUR, NULL); +} + +UInt64 COutArchive::GetPos() const +{ + if (_countMode) + return _countSize; + if (_writeToStream) + return _outByte.GetProcessedSize(); + return _outByte2.GetPos(); +} + +void COutArchive::WriteBytes(const void *data, size_t size) +{ + if (_countMode) + _countSize += size; + else if (_writeToStream) + { + _outByte.WriteBytes(data, size); + _crc = CrcUpdate(_crc, data, size); + } + else + _outByte2.WriteBytes(data, size); +} + +void COutArchive::WriteByte(Byte b) +{ + if (_countMode) + _countSize++; + else if (_writeToStream) + { + _outByte.WriteByte(b); + _crc = CRC_UPDATE_BYTE(_crc, b); + } + else + _outByte2.WriteByte(b); +} + +void COutArchive::WriteUInt32(UInt32 value) +{ + for (int i = 0; i < 4; i++) + { + WriteByte((Byte)value); + value >>= 8; + } +} + +void COutArchive::WriteUInt64(UInt64 value) +{ + for (int i = 0; i < 8; i++) + { + WriteByte((Byte)value); + value >>= 8; + } +} + +void COutArchive::WriteNumber(UInt64 value) +{ + Byte firstByte = 0; + Byte mask = 0x80; + int i; + for (i = 0; i < 8; i++) + { + if (value < ((UInt64(1) << ( 7 * (i + 1))))) + { + firstByte |= Byte(value >> (8 * i)); + break; + } + firstByte |= mask; + mask >>= 1; + } + WriteByte(firstByte); + for (;i > 0; i--) + { + WriteByte((Byte)value); + value >>= 8; + } +} + +static UInt32 GetBigNumberSize(UInt64 value) +{ + int i; + for (i = 1; i < 9; i++) + if (value < (((UInt64)1 << (i * 7)))) + break; + return i; +} + +#ifdef _7Z_VOL +UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props) +{ + UInt32 result = GetBigNumberSize(dataSize) * 2 + 41; + if (nameLength != 0) + { + nameLength = (nameLength + 1) * 2; + result += nameLength + GetBigNumberSize(nameLength) + 2; + } + if (props) + { + result += 20; + } + if (result >= 128) + result++; + result += kSignatureSize + 2 + kFinishHeaderSize; + return result; +} + +UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props) +{ + UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props); + int testSize; + if (volSize > headersSizeBase) + testSize = volSize - headersSizeBase; + else + testSize = 1; + UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props); + UInt64 pureSize = 1; + if (volSize > headersSize) + pureSize = volSize - headersSize; + return pureSize; +} +#endif + +void COutArchive::WriteFolder(const CFolder &folder) +{ + WriteNumber(folder.Coders.Size()); + int i; + for (i = 0; i < folder.Coders.Size(); i++) + { + const CCoderInfo &coder = folder.Coders[i]; + { + size_t propsSize = coder.Props.GetCapacity(); + + UInt64 id = coder.MethodID; + int 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); + bool isComplex = !coder.IsSimpleCoder(); + b |= (isComplex ? 0x10 : 0); + b |= ((propsSize != 0) ? 0x20 : 0 ); + WriteByte(b); + WriteBytes(longID, idSize); + if (isComplex) + { + WriteNumber(coder.NumInStreams); + WriteNumber(coder.NumOutStreams); + } + if (propsSize == 0) + continue; + WriteNumber(propsSize); + WriteBytes(coder.Props, propsSize); + } + } + for (i = 0; i < folder.BindPairs.Size(); i++) + { + const CBindPair &bindPair = folder.BindPairs[i]; + WriteNumber(bindPair.InIndex); + WriteNumber(bindPair.OutIndex); + } + if (folder.PackStreams.Size() > 1) + for (i = 0; i < folder.PackStreams.Size(); i++) + { + WriteNumber(folder.PackStreams[i]); + } +} + +void COutArchive::WriteBoolVector(const CBoolVector &boolVector) +{ + Byte b = 0; + Byte mask = 0x80; + for (int i = 0; i < boolVector.Size(); i++) + { + if (boolVector[i]) + b |= mask; + mask >>= 1; + if (mask == 0) + { + WriteByte(b); + mask = 0x80; + b = 0; + } + } + if (mask != 0x80) + WriteByte(b); +} + + +void COutArchive::WriteHashDigests( + const CRecordVector<bool> &digestsDefined, + const CRecordVector<UInt32> &digests) +{ + int numDefined = 0; + int i; + for (i = 0; i < digestsDefined.Size(); i++) + if (digestsDefined[i]) + numDefined++; + if (numDefined == 0) + return; + + WriteByte(NID::kCRC); + if (numDefined == digestsDefined.Size()) + WriteByte(1); + else + { + WriteByte(0); + WriteBoolVector(digestsDefined); + } + for (i = 0; i < digests.Size(); i++) + if (digestsDefined[i]) + WriteUInt32(digests[i]); +} + +void COutArchive::WritePackInfo( + UInt64 dataOffset, + const CRecordVector<UInt64> &packSizes, + const CRecordVector<bool> &packCRCsDefined, + const CRecordVector<UInt32> &packCRCs) +{ + if (packSizes.IsEmpty()) + return; + WriteByte(NID::kPackInfo); + WriteNumber(dataOffset); + WriteNumber(packSizes.Size()); + WriteByte(NID::kSize); + for (int i = 0; i < packSizes.Size(); i++) + WriteNumber(packSizes[i]); + + WriteHashDigests(packCRCsDefined, packCRCs); + + WriteByte(NID::kEnd); +} + +void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders) +{ + if (folders.IsEmpty()) + return; + + WriteByte(NID::kUnpackInfo); + + WriteByte(NID::kFolder); + WriteNumber(folders.Size()); + { + WriteByte(0); + for (int i = 0; i < folders.Size(); i++) + WriteFolder(folders[i]); + } + + WriteByte(NID::kCodersUnpackSize); + int i; + for (i = 0; i < folders.Size(); i++) + { + const CFolder &folder = folders[i]; + for (int j = 0; j < folder.UnpackSizes.Size(); j++) + WriteNumber(folder.UnpackSizes[j]); + } + + CRecordVector<bool> unpackCRCsDefined; + CRecordVector<UInt32> unpackCRCs; + for (i = 0; i < folders.Size(); i++) + { + const CFolder &folder = folders[i]; + unpackCRCsDefined.Add(folder.UnpackCRCDefined); + unpackCRCs.Add(folder.UnpackCRC); + } + WriteHashDigests(unpackCRCsDefined, unpackCRCs); + + WriteByte(NID::kEnd); +} + +void COutArchive::WriteSubStreamsInfo( + const CObjectVector<CFolder> &folders, + const CRecordVector<CNum> &numUnpackStreamsInFolders, + const CRecordVector<UInt64> &unpackSizes, + const CRecordVector<bool> &digestsDefined, + const CRecordVector<UInt32> &digests) +{ + WriteByte(NID::kSubStreamsInfo); + + int i; + for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) + { + if (numUnpackStreamsInFolders[i] != 1) + { + WriteByte(NID::kNumUnpackStream); + for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) + WriteNumber(numUnpackStreamsInFolders[i]); + break; + } + } + + + bool needFlag = true; + CNum index = 0; + for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) + for (CNum j = 0; j < numUnpackStreamsInFolders[i]; j++) + { + if (j + 1 != numUnpackStreamsInFolders[i]) + { + if (needFlag) + WriteByte(NID::kSize); + needFlag = false; + WriteNumber(unpackSizes[index]); + } + index++; + } + + CRecordVector<bool> digestsDefined2; + CRecordVector<UInt32> digests2; + + int digestIndex = 0; + for (i = 0; i < folders.Size(); i++) + { + int numSubStreams = (int)numUnpackStreamsInFolders[i]; + if (numSubStreams == 1 && folders[i].UnpackCRCDefined) + digestIndex++; + else + for (int j = 0; j < numSubStreams; j++, digestIndex++) + { + digestsDefined2.Add(digestsDefined[digestIndex]); + digests2.Add(digests[digestIndex]); + } + } + WriteHashDigests(digestsDefined2, digests2); + WriteByte(NID::kEnd); +} + +void COutArchive::SkipAlign(unsigned /* pos */, unsigned /* alignSize */) +{ + return; +} + +/* +7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field. + +void COutArchive::SkipAlign(unsigned pos, unsigned alignSize) +{ + pos += (unsigned)GetPos(); + pos &= (alignSize - 1); + if (pos == 0) + return; + unsigned skip = alignSize - pos; + if (skip < 2) + skip += alignSize; + skip -= 2; + WriteByte(NID::kDummy); + WriteByte((Byte)skip); + for (unsigned i = 0; i < skip; i++) + WriteByte(0); +} +*/ + +static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; } + +void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize) +{ + const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v); + const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2; + SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize); + + WriteByte(type); + WriteNumber(dataSize); + if (numDefined == v.Size()) + WriteByte(1); + else + { + WriteByte(0); + WriteBoolVector(v); + } + WriteByte(0); +} + +void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type) +{ + int numDefined = 0; + + int i; + for (i = 0; i < v.Defined.Size(); i++) + if (v.Defined[i]) + numDefined++; + + if (numDefined == 0) + return; + + WriteAlignedBoolHeader(v.Defined, numDefined, type, 8); + + for (i = 0; i < v.Defined.Size(); i++) + if (v.Defined[i]) + WriteUInt64(v.Values[i]); +} + +HRESULT COutArchive::EncodeStream( + DECL_EXTERNAL_CODECS_LOC_VARS + CEncoder &encoder, const CByteBuffer &data, + CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders) +{ + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr<ISequentialInStream> stream = streamSpec; + streamSpec->Init(data, data.GetCapacity()); + CFolder folderItem; + folderItem.UnpackCRCDefined = true; + folderItem.UnpackCRC = CrcCalc(data, data.GetCapacity()); + UInt64 dataSize64 = data.GetCapacity(); + RINOK(encoder.Encode( + EXTERNAL_CODECS_LOC_VARS + stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL)) + folders.Add(folderItem); + return S_OK; +} + +void COutArchive::WriteHeader( + const CArchiveDatabase &db, + const CHeaderOptions &headerOptions, + UInt64 &headerOffset) +{ + int i; + + UInt64 packedSize = 0; + for (i = 0; i < db.PackSizes.Size(); i++) + packedSize += db.PackSizes[i]; + + headerOffset = packedSize; + + WriteByte(NID::kHeader); + + // Archive Properties + + if (db.Folders.Size() > 0) + { + WriteByte(NID::kMainStreamsInfo); + WritePackInfo(0, db.PackSizes, + db.PackCRCsDefined, + db.PackCRCs); + + WriteUnpackInfo(db.Folders); + + CRecordVector<UInt64> unpackSizes; + CRecordVector<bool> digestsDefined; + CRecordVector<UInt32> digests; + for (i = 0; i < db.Files.Size(); i++) + { + const CFileItem &file = db.Files[i]; + if (!file.HasStream) + continue; + unpackSizes.Add(file.Size); + digestsDefined.Add(file.CrcDefined); + digests.Add(file.Crc); + } + + WriteSubStreamsInfo( + db.Folders, + db.NumUnpackStreamsVector, + unpackSizes, + digestsDefined, + digests); + WriteByte(NID::kEnd); + } + + if (db.Files.IsEmpty()) + { + WriteByte(NID::kEnd); + return; + } + + WriteByte(NID::kFilesInfo); + WriteNumber(db.Files.Size()); + + { + /* ---------- Empty Streams ---------- */ + CBoolVector emptyStreamVector; + emptyStreamVector.Reserve(db.Files.Size()); + int numEmptyStreams = 0; + for (i = 0; i < db.Files.Size(); i++) + if (db.Files[i].HasStream) + emptyStreamVector.Add(false); + else + { + emptyStreamVector.Add(true); + numEmptyStreams++; + } + if (numEmptyStreams > 0) + { + WriteByte(NID::kEmptyStream); + WriteNumber(Bv_GetSizeInBytes(emptyStreamVector)); + WriteBoolVector(emptyStreamVector); + + CBoolVector emptyFileVector, antiVector; + emptyFileVector.Reserve(numEmptyStreams); + antiVector.Reserve(numEmptyStreams); + CNum numEmptyFiles = 0, numAntiItems = 0; + for (i = 0; i < db.Files.Size(); i++) + { + const CFileItem &file = db.Files[i]; + if (!file.HasStream) + { + emptyFileVector.Add(!file.IsDir); + if (!file.IsDir) + numEmptyFiles++; + bool isAnti = db.IsItemAnti(i); + antiVector.Add(isAnti); + if (isAnti) + numAntiItems++; + } + } + + if (numEmptyFiles > 0) + { + WriteByte(NID::kEmptyFile); + WriteNumber(Bv_GetSizeInBytes(emptyFileVector)); + WriteBoolVector(emptyFileVector); + } + + if (numAntiItems > 0) + { + WriteByte(NID::kAnti); + WriteNumber(Bv_GetSizeInBytes(antiVector)); + WriteBoolVector(antiVector); + } + } + } + + + { + /* ---------- Names ---------- */ + + int numDefined = 0; + size_t namesDataSize = 0; + for (int i = 0; i < db.Files.Size(); i++) + { + const UString &name = db.Files[i].Name; + if (!name.IsEmpty()) + numDefined++; + namesDataSize += (name.Length() + 1) * 2; + } + + if (numDefined > 0) + { + namesDataSize++; + SkipAlign(2 + GetBigNumberSize(namesDataSize), 2); + + WriteByte(NID::kName); + WriteNumber(namesDataSize); + WriteByte(0); + for (int i = 0; i < db.Files.Size(); i++) + { + const UString &name = db.Files[i].Name; + for (int t = 0; t <= name.Length(); t++) + { + wchar_t c = name[t]; + WriteByte((Byte)c); + WriteByte((Byte)(c >> 8)); + } + } + } + } + + if (headerOptions.WriteCTime) WriteUInt64DefVector(db.CTime, NID::kCTime); + if (headerOptions.WriteATime) WriteUInt64DefVector(db.ATime, NID::kATime); + if (headerOptions.WriteMTime) WriteUInt64DefVector(db.MTime, NID::kMTime); + WriteUInt64DefVector(db.StartPos, NID::kStartPos); + + { + /* ---------- Write Attrib ---------- */ + CBoolVector boolVector; + boolVector.Reserve(db.Files.Size()); + int numDefined = 0; + for (i = 0; i < db.Files.Size(); i++) + { + bool defined = db.Files[i].AttribDefined; + boolVector.Add(defined); + if (defined) + numDefined++; + } + if (numDefined > 0) + { + WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttributes, 4); + for (i = 0; i < db.Files.Size(); i++) + { + const CFileItem &file = db.Files[i]; + if (file.AttribDefined) + WriteUInt32(file.Attrib); + } + } + } + + WriteByte(NID::kEnd); // for files + WriteByte(NID::kEnd); // for headers +} + +HRESULT COutArchive::WriteDatabase( + DECL_EXTERNAL_CODECS_LOC_VARS + const CArchiveDatabase &db, + const CCompressionMethodMode *options, + const CHeaderOptions &headerOptions) +{ + if (!db.CheckNumFiles()) + return E_FAIL; + + UInt64 headerOffset; + UInt32 headerCRC; + UInt64 headerSize; + if (db.IsEmpty()) + { + headerSize = 0; + headerOffset = 0; + headerCRC = CrcCalc(0, 0); + } + else + { + bool encodeHeaders = false; + if (options != 0) + if (options->IsEmpty()) + options = 0; + if (options != 0) + if (options->PasswordIsDefined || headerOptions.CompressMainHeader) + encodeHeaders = true; + + _outByte.SetStream(SeqStream); + _outByte.Init(); + _crc = CRC_INIT_VAL; + _countMode = encodeHeaders; + _writeToStream = true; + _countSize = 0; + WriteHeader(db, headerOptions, headerOffset); + + if (encodeHeaders) + { + CByteBuffer buf; + buf.SetCapacity(_countSize); + _outByte2.Init((Byte *)buf, _countSize); + + _countMode = false; + _writeToStream = false; + WriteHeader(db, headerOptions, headerOffset); + + if (_countSize != _outByte2.GetPos()) + return E_FAIL; + + CCompressionMethodMode encryptOptions; + encryptOptions.PasswordIsDefined = options->PasswordIsDefined; + encryptOptions.Password = options->Password; + CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions); + CRecordVector<UInt64> packSizes; + CObjectVector<CFolder> folders; + RINOK(EncodeStream( + EXTERNAL_CODECS_LOC_VARS + encoder, buf, + packSizes, folders)); + + _writeToStream = true; + + if (folders.Size() == 0) + throw 1; + + WriteID(NID::kEncodedHeader); + WritePackInfo(headerOffset, packSizes, + CRecordVector<bool>(), CRecordVector<UInt32>()); + WriteUnpackInfo(folders); + WriteByte(NID::kEnd); + for (int i = 0; i < packSizes.Size(); i++) + headerOffset += packSizes[i]; + } + RINOK(_outByte.Flush()); + headerCRC = CRC_GET_DIGEST(_crc); + headerSize = _outByte.GetProcessedSize(); + } + #ifdef _7Z_VOL + if (_endMarker) + { + CFinishHeader h; + h.NextHeaderSize = headerSize; + h.NextHeaderCRC = headerCRC; + h.NextHeaderOffset = + UInt64(0) - (headerSize + + 4 + kFinishHeaderSize); + h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset; + h.AdditionalStartBlockSize = 0; + RINOK(WriteFinishHeader(h)); + return WriteFinishSignature(); + } + else + #endif + { + CStartHeader h; + h.NextHeaderSize = headerSize; + h.NextHeaderCRC = headerCRC; + h.NextHeaderOffset = headerOffset; + RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL)); + return WriteStartHeader(h); + } +} + +void CArchiveDatabase::GetFile(int index, CFileItem &file, CFileItem2 &file2) const +{ + file = Files[index]; + file2.CTimeDefined = CTime.GetItem(index, file2.CTime); + file2.ATimeDefined = ATime.GetItem(index, file2.ATime); + file2.MTimeDefined = MTime.GetItem(index, file2.MTime); + file2.StartPosDefined = StartPos.GetItem(index, file2.StartPos); + file2.IsAnti = IsItemAnti(index); +} + +void CArchiveDatabase::AddFile(const CFileItem &file, const CFileItem2 &file2) +{ + int index = Files.Size(); + CTime.SetItem(index, file2.CTimeDefined, file2.CTime); + ATime.SetItem(index, file2.ATimeDefined, file2.ATime); + MTime.SetItem(index, file2.MTimeDefined, file2.MTime); + StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos); + SetItemAnti(index, file2.IsAnti); + Files.Add(file); +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.h new file mode 100644 index 000000000..7b1b528e6 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zOut.h @@ -0,0 +1,152 @@ +// 7zOut.h + +#ifndef __7Z_OUT_H +#define __7Z_OUT_H + +#include "7zCompressionMode.h" +#include "7zEncode.h" +#include "7zHeader.h" +#include "7zItem.h" + +#include "../../Common/OutBuffer.h" + +namespace NArchive { +namespace N7z { + +class CWriteBufferLoc +{ + Byte *_data; + size_t _size; + size_t _pos; +public: + CWriteBufferLoc(): _size(0), _pos(0) {} + void Init(Byte *data, size_t size) + { + _data = data; + _size = size; + _pos = 0; + } + void WriteBytes(const void *data, size_t size) + { + if (size > _size - _pos) + throw 1; + memcpy(_data + _pos, data, size); + _pos += size; + } + void WriteByte(Byte b) + { + if (_size == _pos) + throw 1; + _data[_pos++] = b; + } + size_t GetPos() const { return _pos; } +}; + +struct CHeaderOptions +{ + bool CompressMainHeader; + bool WriteCTime; + bool WriteATime; + bool WriteMTime; + + CHeaderOptions(): + CompressMainHeader(true), + WriteCTime(false), + WriteATime(false), + WriteMTime(true) + {} +}; + +class COutArchive +{ + UInt64 _prefixHeaderPos; + + HRESULT WriteDirect(const void *data, UInt32 size); + + UInt64 GetPos() const; + void WriteBytes(const void *data, size_t size); + void WriteBytes(const CByteBuffer &data) { WriteBytes(data, data.GetCapacity()); } + void WriteByte(Byte b); + void WriteUInt32(UInt32 value); + void WriteUInt64(UInt64 value); + void WriteNumber(UInt64 value); + void WriteID(UInt64 value) { WriteNumber(value); } + + void WriteFolder(const CFolder &folder); + HRESULT WriteFileHeader(const CFileItem &itemInfo); + void WriteBoolVector(const CBoolVector &boolVector); + void WriteHashDigests( + const CRecordVector<bool> &digestsDefined, + const CRecordVector<UInt32> &hashDigests); + + void WritePackInfo( + UInt64 dataOffset, + const CRecordVector<UInt64> &packSizes, + const CRecordVector<bool> &packCRCsDefined, + const CRecordVector<UInt32> &packCRCs); + + void WriteUnpackInfo(const CObjectVector<CFolder> &folders); + + void WriteSubStreamsInfo( + const CObjectVector<CFolder> &folders, + const CRecordVector<CNum> &numUnpackStreamsInFolders, + const CRecordVector<UInt64> &unpackSizes, + const CRecordVector<bool> &digestsDefined, + const CRecordVector<UInt32> &hashDigests); + + void SkipAlign(unsigned pos, unsigned alignSize); + void WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize); + void WriteUInt64DefVector(const CUInt64DefVector &v, Byte type); + + HRESULT EncodeStream( + DECL_EXTERNAL_CODECS_LOC_VARS + CEncoder &encoder, const CByteBuffer &data, + CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders); + void WriteHeader( + const CArchiveDatabase &db, + const CHeaderOptions &headerOptions, + UInt64 &headerOffset); + + bool _countMode; + bool _writeToStream; + size_t _countSize; + UInt32 _crc; + COutBuffer _outByte; + CWriteBufferLoc _outByte2; + + #ifdef _7Z_VOL + bool _endMarker; + #endif + + HRESULT WriteSignature(); + #ifdef _7Z_VOL + HRESULT WriteFinishSignature(); + #endif + HRESULT WriteStartHeader(const CStartHeader &h); + #ifdef _7Z_VOL + HRESULT WriteFinishHeader(const CFinishHeader &h); + #endif + CMyComPtr<IOutStream> Stream; +public: + + COutArchive() { _outByte.Create(1 << 16); } + CMyComPtr<ISequentialOutStream> SeqStream; + HRESULT Create(ISequentialOutStream *stream, bool endMarker); + void Close(); + HRESULT SkipPrefixArchiveHeader(); + HRESULT WriteDatabase( + DECL_EXTERNAL_CODECS_LOC_VARS + const CArchiveDatabase &db, + const CCompressionMethodMode *options, + const CHeaderOptions &headerOptions); + + #ifdef _7Z_VOL + static UInt32 GetVolHeadersSize(UInt64 dataSize, int nameLength = 0, bool props = false); + static UInt64 GetVolPureSize(UInt64 volSize, int nameLength = 0, bool props = false); + #endif + +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.cpp new file mode 100644 index 000000000..fd4af49c7 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.cpp @@ -0,0 +1,164 @@ +// 7zProperties.cpp + +#include "StdAfx.h" + +#include "7zProperties.h" +#include "7zHeader.h" +#include "7zHandler.h" + +// #define _MULTI_PACK + +namespace NArchive { +namespace N7z { + +struct CPropMap +{ + UInt64 FilePropID; + STATPROPSTG StatPROPSTG; +}; + +CPropMap kPropMap[] = +{ + { NID::kName, { NULL, kpidPath, VT_BSTR } }, + { NID::kSize, { NULL, kpidSize, VT_UI8 } }, + { NID::kPackInfo, { NULL, kpidPackSize, VT_UI8 } }, + + #ifdef _MULTI_PACK + { 100, { L"Pack0", kpidPackedSize0, VT_UI8 } }, + { 101, { L"Pack1", kpidPackedSize1, VT_UI8 } }, + { 102, { L"Pack2", kpidPackedSize2, VT_UI8 } }, + { 103, { L"Pack3", kpidPackedSize3, VT_UI8 } }, + { 104, { L"Pack4", kpidPackedSize4, VT_UI8 } }, + #endif + + { NID::kCTime, { NULL, kpidCTime, VT_FILETIME } }, + { NID::kMTime, { NULL, kpidMTime, VT_FILETIME } }, + { NID::kATime, { NULL, kpidATime, VT_FILETIME } }, + { NID::kWinAttributes, { NULL, kpidAttrib, VT_UI4 } }, + { NID::kStartPos, { NULL, kpidPosition, VT_UI4 } }, + + { NID::kCRC, { NULL, kpidCRC, VT_UI4 } }, + + { NID::kAnti, { NULL, kpidIsAnti, VT_BOOL } } + + #ifndef _SFX + , + { 97, { NULL,kpidEncrypted, VT_BOOL } }, + { 98, { NULL,kpidMethod, VT_BSTR } }, + { 99, { NULL,kpidBlock, VT_UI4 } } + #endif +}; + +static const int kPropMapSize = sizeof(kPropMap) / sizeof(kPropMap[0]); + +static int FindPropInMap(UInt64 filePropID) +{ + for (int i = 0; i < kPropMapSize; i++) + if (kPropMap[i].FilePropID == filePropID) + return i; + return -1; +} + +static void CopyOneItem(CRecordVector<UInt64> &src, + CRecordVector<UInt64> &dest, UInt32 item) +{ + for (int i = 0; i < src.Size(); i++) + if (src[i] == item) + { + dest.Add(item); + src.Delete(i); + return; + } +} + +static void RemoveOneItem(CRecordVector<UInt64> &src, UInt32 item) +{ + for (int i = 0; i < src.Size(); i++) + if (src[i] == item) + { + src.Delete(i); + return; + } +} + +static void InsertToHead(CRecordVector<UInt64> &dest, UInt32 item) +{ + for (int i = 0; i < dest.Size(); i++) + if (dest[i] == item) + { + dest.Delete(i); + break; + } + dest.Insert(0, item); +} + +void CHandler::FillPopIDs() +{ + _fileInfoPopIDs.Clear(); + + #ifdef _7Z_VOL + if(_volumes.Size() < 1) + return; + const CVolume &volume = _volumes.Front(); + const CArchiveDatabaseEx &_db = volume.Database; + #endif + + CRecordVector<UInt64> fileInfoPopIDs = _db.ArchiveInfo.FileInfoPopIDs; + + RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream); + RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile); + + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kName); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kAnti); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kSize); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kPackInfo); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCTime); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kMTime); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kATime); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kWinAttributes); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCRC); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kComment); + _fileInfoPopIDs += fileInfoPopIDs; + + #ifndef _SFX + _fileInfoPopIDs.Add(97); + _fileInfoPopIDs.Add(98); + _fileInfoPopIDs.Add(99); + #endif + #ifdef _MULTI_PACK + _fileInfoPopIDs.Add(100); + _fileInfoPopIDs.Add(101); + _fileInfoPopIDs.Add(102); + _fileInfoPopIDs.Add(103); + _fileInfoPopIDs.Add(104); + #endif + + #ifndef _SFX + InsertToHead(_fileInfoPopIDs, NID::kMTime); + InsertToHead(_fileInfoPopIDs, NID::kPackInfo); + InsertToHead(_fileInfoPopIDs, NID::kSize); + InsertToHead(_fileInfoPopIDs, NID::kName); + #endif +} + +STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) +{ + *numProperties = _fileInfoPopIDs.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) +{ + if ((int)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; +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.h new file mode 100644 index 000000000..661817954 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zProperties.h @@ -0,0 +1,22 @@ +// 7zProperties.h + +#ifndef __7Z_PROPERTIES_H +#define __7Z_PROPERTIES_H + +#include "../../PropID.h" + +namespace NArchive { +namespace N7z { + +enum +{ + kpidPackedSize0 = kpidUserDefined, + kpidPackedSize1, + kpidPackedSize2, + kpidPackedSize3, + kpidPackedSize4 +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zRegister.cpp new file mode 100644 index 000000000..6e9bf6b99 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zRegister.cpp @@ -0,0 +1,18 @@ +// 7zRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "7zHandler.h" +static IInArchive *CreateArc() { return new NArchive::N7z::CHandler; } +#ifndef EXTRACT_ONLY +static IOutArchive *CreateArcOut() { return new NArchive::N7z::CHandler; } +#else +#define CreateArcOut 0 +#endif + +static CArcInfo g_ArcInfo = + { L"7z", L"7z", 0, 7, {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}, 6, false, CreateArc, CreateArcOut }; + +REGISTER_ARC(7z) diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.cpp new file mode 100644 index 000000000..06969636d --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.cpp @@ -0,0 +1,24 @@ +// 7zSpecStream.cpp + +#include "StdAfx.h" + +#include "7zSpecStream.h" + +STDMETHODIMP CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 realProcessedSize; + HRESULT result = _stream->Read(data, size, &realProcessedSize); + _size += realProcessedSize; + if (processedSize != 0) + *processedSize = realProcessedSize; + return result; +} + +STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize( + UInt64 subStream, UInt64 *value) +{ + if (_getSubStreamSize == NULL) + return E_NOTIMPL; + return _getSubStreamSize->GetSubStreamSize(subStream, value); +} + diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.h new file mode 100644 index 000000000..2e26efd5c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zSpecStream.h @@ -0,0 +1,35 @@ +// 7zSpecStream.h + +#ifndef __7Z_SPEC_STREAM_H +#define __7Z_SPEC_STREAM_H + +#include "../../IStream.h" +#include "../../ICoder.h" +#include "../../../Common/MyCom.h" + +class CSequentialInStreamSizeCount2: + public ISequentialInStream, + public ICompressGetSubStreamSize, + public CMyUnknownImp +{ + CMyComPtr<ISequentialInStream> _stream; + CMyComPtr<ICompressGetSubStreamSize> _getSubStreamSize; + UInt64 _size; +public: + void Init(ISequentialInStream *stream) + { + _stream = stream; + _getSubStreamSize = 0; + _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize); + _size = 0; + } + UInt64 GetSize() const { return _size; } + + MY_UNKNOWN_IMP1(ICompressGetSubStreamSize) + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + + STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value); +}; + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.cpp new file mode 100644 index 000000000..ee7f55c04 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.cpp @@ -0,0 +1,1177 @@ +// 7zUpdate.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" + +#include "../../Common/CreateCoder.h" + +#include "../../Compress/CopyCoder.h" + +#include "../Common/ItemNameUtils.h" +#include "../Common/OutStreamWithCRC.h" + +#include "7zDecode.h" +#include "7zEncode.h" +#include "7zFolderInStream.h" +#include "7zHandler.h" +#include "7zOut.h" +#include "7zUpdate.h" + +namespace NArchive { +namespace N7z { + +static const UInt64 k_LZMA = 0x030101; +static const UInt64 k_BCJ = 0x03030103; +static const UInt64 k_BCJ2 = 0x0303011B; + +static const wchar_t *kMatchFinderForBCJ2_LZMA = L"BT2"; +static const UInt32 kDictionaryForBCJ2_LZMA = 1 << 20; +static const UInt32 kAlgorithmForBCJ2_LZMA = 1; +static const UInt32 kNumFastBytesForBCJ2_LZMA = 64; + +#ifdef MY_CPU_X86_OR_AMD64 +#define USE_86_FILTER +#endif + +static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream, + UInt64 position, UInt64 size, ICompressProgressInfo *progress) +{ + RINOK(inStream->Seek(position, STREAM_SEEK_SET, 0)); + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec); + streamSpec->SetStream(inStream); + streamSpec->Init(size); + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); + 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 +{ + int slashPos = GetReverseSlashPos(Name); + int dotPos = Name.ReverseFind(L'.'); + if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0)) + return Name.Length(); + return dotPos + 1; +} + +UString CUpdateItem::GetExtension() const +{ + return Name.Mid(GetExtensionPos()); +} + +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + +#define RINOZ_COMP(a, b) RINOZ(MyCompare(a, b)) + +static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2) +{ + size_t c1 = a1.GetCapacity(); + size_t c2 = a2.GetCapacity(); + RINOZ_COMP(c1, c2); + for (size_t i = 0; i < c1; i++) + RINOZ_COMP(a1[i], a2[i]); + return 0; +} + +static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2) +{ + RINOZ_COMP(c1.NumInStreams, c2.NumInStreams); + RINOZ_COMP(c1.NumOutStreams, c2.NumOutStreams); + RINOZ_COMP(c1.MethodID, c2.MethodID); + return CompareBuffers(c1.Props, c2.Props); +} + +static int CompareBindPairs(const CBindPair &b1, const CBindPair &b2) +{ + RINOZ_COMP(b1.InIndex, b2.InIndex); + return MyCompare(b1.OutIndex, b2.OutIndex); +} + +static int CompareFolders(const CFolder &f1, const CFolder &f2) +{ + int s1 = f1.Coders.Size(); + int s2 = f2.Coders.Size(); + RINOZ_COMP(s1, s2); + int i; + for (i = 0; i < s1; i++) + RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i])); + s1 = f1.BindPairs.Size(); + s2 = f2.BindPairs.Size(); + RINOZ_COMP(s1, s2); + for (i = 0; i < s1; i++) + RINOZ(CompareBindPairs(f1.BindPairs[i], f2.BindPairs[i])); + return 0; +} + +/* +static int CompareFiles(const CFileItem &f1, const CFileItem &f2) +{ + return MyStringCompareNoCase(f1.Name, f2.Name); +} +*/ + +struct CFolderRepack +{ + int FolderIndex; + int Group; + CNum NumCopyFiles; +}; + +static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void *param) +{ + RINOZ_COMP(p1->Group, p2->Group); + int i1 = p1->FolderIndex; + int i2 = p2->FolderIndex; + const CArchiveDatabaseEx &db = *(const CArchiveDatabaseEx *)param; + 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]]); + */ +} + +//////////////////////////////////////////////////////////// + +static int CompareEmptyItems(const int *p1, const int *p2, void *param) +{ + const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param; + const CUpdateItem &u1 = updateItems[*p1]; + const CUpdateItem &u2 = updateItems[*p2]; + if (u1.IsDir != u2.IsDir) + return (u1.IsDir) ? 1 : -1; + if (u1.IsDir) + { + if (u1.IsAnti != u2.IsAnti) + return (u1.IsAnti ? 1 : -1); + int n = MyStringCompareNoCase(u1.Name, u2.Name); + return -n; + } + if (u1.IsAnti != u2.IsAnti) + return (u1.IsAnti ? 1 : -1); + return MyStringCompareNoCase(u1.Name, u2.Name); +} + +static const char *g_Exts = + " lzma 7z ace arc arj bz bz2 deb lzo lzx gz pak rpm sit tgz tbz tbz2 tgz cab ha lha lzh rar zoo" + " zip jar ear war msi" + " 3gp avi mov mpeg mpg mpe wmv" + " aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav" + " swf " + " chm hxi hxs" + " gif jpeg jpg jp2 png tiff bmp ico psd psp" + " awg ps eps cgm dxf svg vrml wmf emf ai md" + " cad dwg pps key sxi" + " max 3ds" + " iso bin nrg mdf img pdi tar cpio xpi" + " vfd vhd vud vmc vsv" + " vmdk dsk nvram vmem vmsd vmsn vmss vmtm" + " inl inc idl acf asa h hpp hxx c cpp cxx rc java cs pas bas vb cls ctl frm dlg def" + " f77 f f90 f95" + " asm sql manifest dep " + " mak clw csproj vcproj sln dsp dsw " + " class " + " bat cmd" + " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml" + " awk sed hta js php php3 php4 php5 phptml pl pm py pyo rb sh tcl vbs" + " text txt tex ans asc srt reg ini doc docx mcw dot rtf hlp xls xlr xlt xlw ppt pdf" + " sxc sxd sxi sxg sxw stc sti stw stm odt ott odg otg odp otp ods ots odf" + " abw afp cwk lwp wpd wps wpt wrf wri" + " abf afm bdf fon mgf otf pcf pfa snf ttf" + " dbf mdb nsf ntf wdb db fdb gdb" + " exe dll ocx vbx sfx sys tlb awx com obj lib out o so " + " pdb pch idb ncb opt"; + +int GetExtIndex(const char *ext) +{ + int extIndex = 1; + const char *p = g_Exts; + for (;;) + { + char c = *p++; + if (c == 0) + return extIndex; + if (c == ' ') + continue; + int pos = 0; + for (;;) + { + char c2 = ext[pos++]; + if (c2 == 0 && (c == 0 || c == ' ')) + return extIndex; + if (c != c2) + break; + c = *p++; + } + extIndex++; + for (;;) + { + if (c == 0) + return extIndex; + if (c == ' ') + break; + c = *p++; + } + } +} + +struct CRefItem +{ + const CUpdateItem *UpdateItem; + UInt32 Index; + UInt32 ExtensionPos; + UInt32 NamePos; + int ExtensionIndex; + CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType): + UpdateItem(&ui), + Index(index), + ExtensionPos(0), + NamePos(0), + ExtensionIndex(0) + { + if (sortByType) + { + int slashPos = GetReverseSlashPos(ui.Name); + NamePos = ((slashPos >= 0) ? (slashPos + 1) : 0); + int dotPos = ui.Name.ReverseFind(L'.'); + if (dotPos < 0 || (dotPos < slashPos && slashPos >= 0)) + ExtensionPos = ui.Name.Length(); + else + { + ExtensionPos = dotPos + 1; + UString us = ui.Name.Mid(ExtensionPos); + if (!us.IsEmpty()) + { + us.MakeLower(); + int i; + AString s; + for (i = 0; i < us.Length(); i++) + { + wchar_t c = us[i]; + if (c >= 0x80) + break; + s += (char)c; + } + if (i == us.Length()) + ExtensionIndex = GetExtIndex(s); + else + ExtensionIndex = 0; + } + } + } + } +}; + +static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param) +{ + const CRefItem &a1 = *p1; + const CRefItem &a2 = *p2; + const CUpdateItem &u1 = *a1.UpdateItem; + const CUpdateItem &u2 = *a2.UpdateItem; + int n; + if (u1.IsDir != u2.IsDir) + return (u1.IsDir) ? 1 : -1; + if (u1.IsDir) + { + if (u1.IsAnti != u2.IsAnti) + return (u1.IsAnti ? 1 : -1); + n = MyStringCompareNoCase(u1.Name, u2.Name); + return -n; + } + bool sortByType = *(bool *)param; + if (sortByType) + { + RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex); + RINOZ(MyStringCompareNoCase(u1.Name + a1.ExtensionPos, u2.Name + a2.ExtensionPos)); + RINOZ(MyStringCompareNoCase(u1.Name + a1.NamePos, u2.Name + a2.NamePos)); + if (!u1.MTimeDefined && u2.MTimeDefined) return 1; + if (u1.MTimeDefined && !u2.MTimeDefined) return -1; + if (u1.MTimeDefined && u2.MTimeDefined) RINOZ_COMP(u1.MTime, u2.MTime); + RINOZ_COMP(u1.Size, u2.Size); + } + return MyStringCompareNoCase(u1.Name, u2.Name); +} + +struct CSolidGroup +{ + CRecordVector<UInt32> Indices; +}; + +static wchar_t *g_ExeExts[] = +{ + L"dll", + L"exe", + L"ocx", + L"sfx", + L"sys" +}; + +static bool IsExeExt(const UString &ext) +{ + for (int i = 0; i < sizeof(g_ExeExts) / sizeof(g_ExeExts[0]); i++) + if (ext.CompareNoCase(g_ExeExts[i]) == 0) + return true; + return false; +} + +#ifdef USE_86_FILTER + +static inline void GetMethodFull(UInt64 methodID, UInt32 numInStreams, CMethodFull &methodResult) +{ + methodResult.Id = methodID; + methodResult.NumInStreams = numInStreams; + methodResult.NumOutStreams = 1; +} + +static void MakeExeMethod(const CCompressionMethodMode &method, + bool bcj2Filter, CCompressionMethodMode &exeMethod) +{ + exeMethod = method; + if (bcj2Filter) + { + CMethodFull methodFull; + GetMethodFull(k_BCJ2, 4, methodFull); + exeMethod.Methods.Insert(0, methodFull); + GetMethodFull(k_LZMA, 1, methodFull); + { + CProp prop; + prop.Id = NCoderPropID::kAlgorithm; + prop.Value = kAlgorithmForBCJ2_LZMA; + methodFull.Props.Add(prop); + } + { + CProp prop; + prop.Id = NCoderPropID::kMatchFinder; + prop.Value = kMatchFinderForBCJ2_LZMA; + methodFull.Props.Add(prop); + } + { + CProp prop; + prop.Id = NCoderPropID::kDictionarySize; + prop.Value = kDictionaryForBCJ2_LZMA; + methodFull.Props.Add(prop); + } + { + CProp prop; + prop.Id = NCoderPropID::kNumFastBytes; + prop.Value = kNumFastBytesForBCJ2_LZMA; + methodFull.Props.Add(prop); + } + { + CProp prop; + prop.Id = NCoderPropID::kNumThreads; + prop.Value = (UInt32)1; + methodFull.Props.Add(prop); + } + + exeMethod.Methods.Add(methodFull); + exeMethod.Methods.Add(methodFull); + CBind bind; + + bind.OutCoder = 0; + bind.InStream = 0; + + bind.InCoder = 1; + bind.OutStream = 0; + exeMethod.Binds.Add(bind); + + bind.InCoder = 2; + bind.OutStream = 1; + exeMethod.Binds.Add(bind); + + bind.InCoder = 3; + bind.OutStream = 2; + exeMethod.Binds.Add(bind); + } + else + { + CMethodFull methodFull; + GetMethodFull(k_BCJ, 1, methodFull); + exeMethod.Methods.Insert(0, methodFull); + CBind bind; + bind.OutCoder = 0; + bind.InStream = 0; + bind.InCoder = 1; + bind.OutStream = 0; + exeMethod.Binds.Add(bind); + } +} + +#endif + +static void FromUpdateItemToFileItem(const CUpdateItem &ui, + CFileItem &file, CFileItem2 &file2) +{ + file.Name = NItemName::MakeLegalName(ui.Name); + if (ui.AttribDefined) + file.SetAttrib(ui.Attrib); + + file2.CTime = ui.CTime; file2.CTimeDefined = ui.CTimeDefined; + file2.ATime = ui.ATime; file2.ATimeDefined = ui.ATimeDefined; + file2.MTime = ui.MTime; file2.MTimeDefined = ui.MTimeDefined; + file2.IsAnti = ui.IsAnti; + file2.StartPosDefined = false; + + file.Size = ui.Size; + file.IsDir = ui.IsDir; + file.HasStream = ui.HasStream(); +} + +class CFolderOutStream2: + public ISequentialOutStream, + public CMyUnknownImp +{ + COutStreamWithCRC *_crcStreamSpec; + CMyComPtr<ISequentialOutStream> _crcStream; + const CArchiveDatabaseEx *_db; + const CBoolVector *_extractStatuses; + CMyComPtr<ISequentialOutStream> _outStream; + UInt32 _startIndex; + int _currentIndex; + bool _fileIsOpen; + UInt64 _rem; + + void OpenFile(); + void CloseFile(); + HRESULT CloseFileAndSetResult(); + HRESULT ProcessEmptyFiles(); +public: + MY_UNKNOWN_IMP + + CFolderOutStream2() + { + _crcStreamSpec = new COutStreamWithCRC; + _crcStream = _crcStreamSpec; + } + + HRESULT Init(const CArchiveDatabaseEx *db, UInt32 startIndex, + const CBoolVector *extractStatuses, ISequentialOutStream *outStream); + void ReleaseOutStream(); + HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; } + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; + +HRESULT CFolderOutStream2::Init(const CArchiveDatabaseEx *db, UInt32 startIndex, + const CBoolVector *extractStatuses, ISequentialOutStream *outStream) +{ + _db = db; + _startIndex = startIndex; + _extractStatuses = extractStatuses; + _outStream = outStream; + + _currentIndex = 0; + _fileIsOpen = false; + return ProcessEmptyFiles(); +} + +void CFolderOutStream2::ReleaseOutStream() +{ + _outStream.Release(); + _crcStreamSpec->ReleaseStream(); +} + +void CFolderOutStream2::OpenFile() +{ + _crcStreamSpec->SetStream((*_extractStatuses)[_currentIndex] ? _outStream : NULL); + _crcStreamSpec->Init(true); + _fileIsOpen = true; + _rem = _db->Files[_startIndex + _currentIndex].Size; +} + +void CFolderOutStream2::CloseFile() +{ + _crcStreamSpec->ReleaseStream(); + _fileIsOpen = false; + _currentIndex++; +} + +HRESULT CFolderOutStream2::CloseFileAndSetResult() +{ + const CFileItem &file = _db->Files[_startIndex + _currentIndex]; + CloseFile(); + return (file.IsDir || !file.CrcDefined || file.Crc == _crcStreamSpec->GetCRC()) ? S_OK: S_FALSE; +} + +HRESULT CFolderOutStream2::ProcessEmptyFiles() +{ + while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0) + { + OpenFile(); + RINOK(CloseFileAndSetResult()); + } + return S_OK; +} + +STDMETHODIMP CFolderOutStream2::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 don't support partial extracting + return E_FAIL; + } + OpenFile(); + } + } + return S_OK; +} + +class CThreadDecoder: public CVirtThread +{ +public: + HRESULT Result; + CMyComPtr<IInStream> InStream; + + CFolderOutStream2 *FosSpec; + CMyComPtr<ISequentialOutStream> Fos; + + UInt64 StartPos; + const UInt64 *PackSizes; + const CFolder *Folder; + #ifndef _NO_CRYPTO + CMyComPtr<ICryptoGetTextPassword> GetTextPassword; + #endif + + DECL_EXTERNAL_CODECS_VARS + 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; + } + virtual void Execute(); +}; + +void CThreadDecoder::Execute() +{ + try + { + #ifndef _NO_CRYPTO + bool passwordIsDefined; + #endif + Result = Decoder.Decode( + EXTERNAL_CODECS_VARS + InStream, + StartPos, + PackSizes, + *Folder, + Fos, + NULL + #ifndef _NO_CRYPTO + , GetTextPassword, passwordIsDefined + #endif + #ifndef _7ZIP_ST + , MtMode, NumThreads + #endif + ); + } + catch(...) + { + Result = E_FAIL; + } + if (Result == S_OK) + Result = FosSpec->CheckFinishedState(); + FosSpec->ReleaseOutStream(); +} + +bool static Is86FilteredFolder(const CFolder &f) +{ + for (int i = 0; i < f.Coders.Size(); i++) + { + CMethodId m = f.Coders[i].MethodID; + if (m == k_BCJ || m == k_BCJ2) + return true; + } + return false; +} + +#ifndef _NO_CRYPTO + +class CCryptoGetTextPassword: + public ICryptoGetTextPassword, + public CMyUnknownImp +{ +public: + UString Password; + + MY_UNKNOWN_IMP + STDMETHOD(CryptoGetTextPassword)(BSTR *password); +}; + +STDMETHODIMP CCryptoGetTextPassword::CryptoGetTextPassword(BSTR *password) +{ + return StringToBstr(Password, password); +} + +#endif + +static const int kNumGroupsMax = 4; + +#ifdef USE_86_FILTER +static bool Is86Group(int group) { return (group & 1) != 0; } +#endif +static bool IsEncryptedGroup(int group) { return (group & 2) != 0; } +static int GetGroupIndex(bool encrypted, int bcjFiltered) + { return (encrypted ? 2 : 0) + (bcjFiltered ? 1 : 0); } + +HRESULT Update( + DECL_EXTERNAL_CODECS_LOC_VARS + IInStream *inStream, + const CArchiveDatabaseEx *db, + const CObjectVector<CUpdateItem> &updateItems, + COutArchive &archive, + CArchiveDatabase &newDatabase, + ISequentialOutStream *seqOutStream, + IArchiveUpdateCallback *updateCallback, + const CUpdateOptions &options + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getDecoderPassword + #endif + ) +{ + UInt64 numSolidFiles = options.NumSolidFiles; + if (numSolidFiles == 0) + numSolidFiles = 1; + /* + CMyComPtr<IOutStream> outStream; + RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream)); + if (!outStream) + return E_NOTIMPL; + */ + + UInt64 startBlockSize = db != 0 ? db->ArchiveInfo.StartPosition: 0; + if (startBlockSize > 0 && !options.RemoveSfxBlock) + { + RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL)); + } + + CRecordVector<int> fileIndexToUpdateIndexMap; + CRecordVector<CFolderRepack> folderRefs; + UInt64 complexity = 0; + UInt64 inSizeForReduce2 = 0; + bool needEncryptedRepack = false; + if (db != 0) + { + fileIndexToUpdateIndexMap.Reserve(db->Files.Size()); + int i; + for (i = 0; i < db->Files.Size(); i++) + fileIndexToUpdateIndexMap.Add(-1); + + for (i = 0; i < updateItems.Size(); i++) + { + int index = updateItems[i].IndexInArchive; + if (index != -1) + fileIndexToUpdateIndexMap[index] = i; + } + + for (i = 0; i < db->Folders.Size(); 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]; + if (file.HasStream) + { + indexInFolder++; + int updateIndex = fileIndexToUpdateIndexMap[fi]; + if (updateIndex >= 0 && !updateItems[updateIndex].NewData) + { + numCopyItems++; + repackSize += file.Size; + } + } + } + + if (numCopyItems == 0) + continue; + + CFolderRepack rep; + rep.FolderIndex = i; + rep.NumCopyFiles = numCopyItems; + const CFolder &f = db->Folders[i]; + bool isEncrypted = f.IsEncrypted(); + rep.Group = GetGroupIndex(isEncrypted, Is86FilteredFolder(f)); + folderRefs.Add(rep); + if (numCopyItems == numUnpackStreams) + complexity += db->GetFolderFullPackSize(i); + else + { + complexity += repackSize; + if (repackSize > inSizeForReduce2) + inSizeForReduce2 = repackSize; + if (isEncrypted) + needEncryptedRepack = true; + } + } + folderRefs.Sort(CompareFolderRepacks, (void *)db); + } + + UInt64 inSizeForReduce = 0; + int i; + for (i = 0; i < updateItems.Size(); i++) + { + const CUpdateItem &ui = updateItems[i]; + if (ui.NewData) + { + complexity += ui.Size; + if (numSolidFiles != 1) + inSizeForReduce += ui.Size; + else if (ui.Size > inSizeForReduce) + inSizeForReduce = ui.Size; + } + } + + if (inSizeForReduce2 > inSizeForReduce) + inSizeForReduce = inSizeForReduce2; + + const UInt32 kMinReduceSize = (1 << 16); + if (inSizeForReduce < kMinReduceSize) + inSizeForReduce = kMinReduceSize; + + RINOK(updateCallback->SetTotal(complexity)); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(updateCallback, true); + + CThreadDecoder threadDecoder; + if (!folderRefs.IsEmpty()) + { + #ifdef EXTERNAL_CODECS + threadDecoder._codecsInfo = codecsInfo; + threadDecoder._externalCodecs = *externalCodecs; + #endif + RINOK(threadDecoder.Create()); + } + + CObjectVector<CSolidGroup> groups; + for (i = 0; i < kNumGroupsMax; i++) + groups.Add(CSolidGroup()); + + { + // ---------- Split files to 2 groups ---------- + + bool useFilters = options.UseFilters; + const CCompressionMethodMode &method = *options.Method; + if (method.Methods.Size() != 1 || method.Binds.Size() != 0) + useFilters = false; + for (i = 0; i < updateItems.Size(); i++) + { + const CUpdateItem &ui = updateItems[i]; + if (!ui.NewData || !ui.HasStream()) + continue; + bool filteredGroup = false; + if (useFilters) + { + int dotPos = ui.Name.ReverseFind(L'.'); + if (dotPos >= 0) + filteredGroup = IsExeExt(ui.Name.Mid(dotPos + 1)); + } + groups[GetGroupIndex(method.PasswordIsDefined, filteredGroup)].Indices.Add(i); + } + } + + #ifndef _NO_CRYPTO + + CCryptoGetTextPassword *getPasswordSpec = NULL; + if (needEncryptedRepack) + { + getPasswordSpec = new CCryptoGetTextPassword; + threadDecoder.GetTextPassword = getPasswordSpec; + + if (options.Method->PasswordIsDefined) + getPasswordSpec->Password = options.Method->Password; + else + { + if (!getDecoderPassword) + return E_NOTIMPL; + CMyComBSTR password; + RINOK(getDecoderPassword->CryptoGetTextPassword(&password)); + getPasswordSpec->Password = password; + } + } + + #endif + + // ---------- Compress ---------- + + RINOK(archive.Create(seqOutStream, false)); + RINOK(archive.SkipPrefixArchiveHeader()); + + int folderRefIndex = 0; + lps->ProgressOffset = 0; + + for (int groupIndex = 0; groupIndex < kNumGroupsMax; groupIndex++) + { + const CSolidGroup &group = groups[groupIndex]; + + CCompressionMethodMode method; + #ifdef USE_86_FILTER + if (Is86Group(groupIndex)) + MakeExeMethod(*options.Method, options.MaxFilter, method); + else + #endif + method = *options.Method; + + if (IsEncryptedGroup(groupIndex)) + { + if (!method.PasswordIsDefined) + { + #ifndef _NO_CRYPTO + if (getPasswordSpec) + method.Password = getPasswordSpec->Password; + #endif + method.PasswordIsDefined = true; + } + } + else + { + method.PasswordIsDefined = false; + method.Password.Empty(); + } + + CEncoder encoder(method); + + for (; folderRefIndex < folderRefs.Size(); folderRefIndex++) + { + const CFolderRepack &rep = folderRefs[folderRefIndex]; + if (rep.Group != groupIndex) + break; + int folderIndex = rep.FolderIndex; + + if (rep.NumCopyFiles == db->NumUnpackStreamsVector[folderIndex]) + { + UInt64 packSize = db->GetFolderFullPackSize(folderIndex); + RINOK(WriteRange(inStream, archive.SeqStream, + db->GetFolderStreamPos(folderIndex, 0), packSize, progress)); + lps->ProgressOffset += packSize; + + const CFolder &folder = db->Folders[folderIndex]; + CNum startIndex = db->FolderStartPackStreamIndex[folderIndex]; + for (int j = 0; j < folder.PackStreams.Size(); j++) + { + newDatabase.PackSizes.Add(db->PackSizes[startIndex + j]); + // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]); + // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]); + } + newDatabase.Folders.Add(folder); + } + else + { + CStreamBinder sb; + RINOK(sb.CreateEvents()); + CMyComPtr<ISequentialOutStream> sbOutStream; + CMyComPtr<ISequentialInStream> sbInStream; + sb.CreateStreams(&sbInStream, &sbOutStream); + CBoolVector extractStatuses; + + CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex]; + CNum indexInFolder = 0; + + for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) + { + bool needExtract = false; + if (db->Files[fi].HasStream) + { + indexInFolder++; + int updateIndex = fileIndexToUpdateIndexMap[fi]; + if (updateIndex >= 0 && !updateItems[updateIndex].NewData) + needExtract = true; + } + extractStatuses.Add(needExtract); + } + + RINOK(threadDecoder.FosSpec->Init(db, db->FolderStartFileIndex[folderIndex], &extractStatuses, sbOutStream)); + sbOutStream.Release(); + + threadDecoder.InStream = inStream; + threadDecoder.Folder = &db->Folders[folderIndex]; + threadDecoder.StartPos = db->GetFolderStreamPos(folderIndex, 0); + threadDecoder.PackSizes = &db->PackSizes[db->FolderStartPackStreamIndex[folderIndex]]; + + threadDecoder.Start(); + + int startPackIndex = newDatabase.PackSizes.Size(); + CFolder newFolder; + RINOK(encoder.Encode( + EXTERNAL_CODECS_LOC_VARS + sbInStream, NULL, &inSizeForReduce, newFolder, + archive.SeqStream, newDatabase.PackSizes, progress)); + + threadDecoder.WaitFinish(); + + RINOK(threadDecoder.Result); + + for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) + lps->OutSize += newDatabase.PackSizes[startPackIndex]; + lps->InSize += newFolder.GetUnpackSize(); + + newDatabase.Folders.Add(newFolder); + } + + newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles); + + CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex]; + + CNum indexInFolder = 0; + for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) + { + CFileItem file; + CFileItem2 file2; + db->GetFile(fi, file, file2); + if (file.HasStream) + { + indexInFolder++; + int updateIndex = fileIndexToUpdateIndexMap[fi]; + if (updateIndex >= 0) + { + const CUpdateItem &ui = updateItems[updateIndex]; + if (ui.NewData) + continue; + if (ui.NewProps) + { + CFileItem uf; + FromUpdateItemToFileItem(ui, uf, file2); + uf.Size = file.Size; + uf.Crc = file.Crc; + uf.CrcDefined = file.CrcDefined; + uf.HasStream = file.HasStream; + file = uf; + } + newDatabase.AddFile(file, file2); + } + } + } + } + + int numFiles = group.Indices.Size(); + if (numFiles == 0) + continue; + CRecordVector<CRefItem> refItems; + refItems.Reserve(numFiles); + bool sortByType = (numSolidFiles > 1); + for (i = 0; i < numFiles; i++) + refItems.Add(CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType)); + refItems.Sort(CompareUpdateItems, (void *)&sortByType); + + CRecordVector<UInt32> indices; + indices.Reserve(numFiles); + + for (i = 0; i < numFiles; i++) + { + UInt32 index = refItems[i].Index; + indices.Add(index); + /* + const CUpdateItem &ui = updateItems[index]; + CFileItem file; + if (ui.NewProps) + FromUpdateItemToFileItem(ui, file); + else + file = db.Files[ui.IndexInArchive]; + if (file.IsAnti || file.IsDir) + return E_FAIL; + newDatabase.Files.Add(file); + */ + } + + for (i = 0; i < numFiles;) + { + UInt64 totalSize = 0; + int numSubFiles; + UString prevExtension; + for (numSubFiles = 0; i + numSubFiles < numFiles && + numSubFiles < numSolidFiles; numSubFiles++) + { + const CUpdateItem &ui = updateItems[indices[i + numSubFiles]]; + totalSize += ui.Size; + if (totalSize > options.NumSolidBytes) + break; + if (options.SolidExtension) + { + UString ext = ui.GetExtension(); + if (numSubFiles == 0) + prevExtension = ext; + else + if (ext.CompareNoCase(prevExtension) != 0) + break; + } + } + if (numSubFiles < 1) + numSubFiles = 1; + + CFolderInStream *inStreamSpec = new CFolderInStream; + CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec); + inStreamSpec->Init(updateCallback, &indices[i], numSubFiles); + + CFolder folderItem; + + int startPackIndex = newDatabase.PackSizes.Size(); + RINOK(encoder.Encode( + EXTERNAL_CODECS_LOC_VARS + solidInStream, NULL, &inSizeForReduce, folderItem, + archive.SeqStream, newDatabase.PackSizes, progress)); + + for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) + lps->OutSize += newDatabase.PackSizes[startPackIndex]; + + lps->InSize += folderItem.GetUnpackSize(); + // for () + // newDatabase.PackCRCsDefined.Add(false); + // newDatabase.PackCRCs.Add(0); + + newDatabase.Folders.Add(folderItem); + + CNum numUnpackStreams = 0; + for (int subIndex = 0; subIndex < numSubFiles; subIndex++) + { + const CUpdateItem &ui = updateItems[indices[i + subIndex]]; + CFileItem file; + CFileItem2 file2; + if (ui.NewProps) + FromUpdateItemToFileItem(ui, file, file2); + else + db->GetFile(ui.IndexInArchive, file, file2); + if (file2.IsAnti || file.IsDir) + return E_FAIL; + + /* + CFileItem &file = newDatabase.Files[ + startFileIndexInDatabase + i + subIndex]; + */ + if (!inStreamSpec->Processed[subIndex]) + { + continue; + // file.Name += L".locked"; + } + + file.Crc = inStreamSpec->CRCs[subIndex]; + file.Size = inStreamSpec->Sizes[subIndex]; + if (file.Size != 0) + { + file.CrcDefined = true; + file.HasStream = true; + numUnpackStreams++; + } + else + { + file.CrcDefined = false; + file.HasStream = false; + } + newDatabase.AddFile(file, file2); + } + // numUnpackStreams = 0 is very bad case for locked files + // v3.13 doesn't understand it. + newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams); + i += numSubFiles; + } + } + + if (folderRefIndex != folderRefs.Size()) + return E_FAIL; + + /* + folderRefs.ClearAndFree(); + fileIndexToUpdateIndexMap.ClearAndFree(); + groups.ClearAndFree(); + */ + + { + // ---------- Write Folders & Empty Files ---------- + + CRecordVector<int> emptyRefs; + for (i = 0; i < updateItems.Size(); i++) + { + const CUpdateItem &ui = updateItems[i]; + if (ui.NewData) + { + if (ui.HasStream()) + continue; + } + else if (ui.IndexInArchive != -1 && db->Files[ui.IndexInArchive].HasStream) + continue; + emptyRefs.Add(i); + } + emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems); + for (i = 0; i < emptyRefs.Size(); i++) + { + const CUpdateItem &ui = updateItems[emptyRefs[i]]; + CFileItem file; + CFileItem2 file2; + if (ui.NewProps) + FromUpdateItemToFileItem(ui, file, file2); + else + db->GetFile(ui.IndexInArchive, file, file2); + newDatabase.AddFile(file, file2); + } + } + + newDatabase.ReserveDown(); + return S_OK; +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.h new file mode 100644 index 000000000..31e362246 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/7zUpdate.h @@ -0,0 +1,88 @@ +// 7zUpdate.h + +#ifndef __7Z_UPDATE_H +#define __7Z_UPDATE_H + +#include "7zCompressionMode.h" +#include "7zIn.h" +#include "7zOut.h" + +#include "../IArchive.h" + +namespace NArchive { +namespace N7z { + +struct CUpdateItem +{ + int IndexInArchive; + int IndexInClient; + + UInt64 CTime; + UInt64 ATime; + UInt64 MTime; + + UInt64 Size; + UString Name; + + UInt32 Attrib; + + bool NewData; + bool NewProps; + + bool IsAnti; + bool IsDir; + + bool AttribDefined; + bool CTimeDefined; + bool ATimeDefined; + bool MTimeDefined; + + bool HasStream() const { return !IsDir && !IsAnti && Size != 0; } + + CUpdateItem(): + IsAnti(false), + IsDir(false), + AttribDefined(false), + CTimeDefined(false), + ATimeDefined(false), + MTimeDefined(false) + {} + void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); }; + + int GetExtensionPos() const; + UString GetExtension() const; +}; + +struct CUpdateOptions +{ + const CCompressionMethodMode *Method; + const CCompressionMethodMode *HeaderMethod; + bool UseFilters; + bool MaxFilter; + + CHeaderOptions HeaderOptions; + + UInt64 NumSolidFiles; + UInt64 NumSolidBytes; + bool SolidExtension; + bool RemoveSfxBlock; + bool VolumeMode; +}; + +HRESULT Update( + DECL_EXTERNAL_CODECS_LOC_VARS + IInStream *inStream, + const CArchiveDatabaseEx *db, + const CObjectVector<CUpdateItem> &updateItems, + COutArchive &archive, + CArchiveDatabase &newDatabase, + ISequentialOutStream *seqOutStream, + IArchiveUpdateCallback *updateCallback, + const CUpdateOptions &options + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getDecoderPassword + #endif + ); +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.cpp b/src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.cpp new file mode 100644 index 000000000..d0feea85c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.cpp @@ -0,0 +1,3 @@ +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.h new file mode 100644 index 000000000..2e4be10b2 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/7z/StdAfx.h @@ -0,0 +1,9 @@ +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/MyWindows.h" +#include "../../../Common/NewHandler.h" + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/ApmHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/ApmHandler.cpp new file mode 100644 index 000000000..a3b5e19b9 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/ApmHandler.cpp @@ -0,0 +1,356 @@ +// ApmHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "Common/ComTry.h" +#include "Common/IntToString.h" +#include "Common/MyString.h" + +#include "Windows/PropVariant.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#define Get16(p) GetBe16(p) +#define Get32(p) GetBe32(p) + +using namespace NWindows; + +namespace NArchive { +namespace NApm { + +struct CItem +{ + UInt32 StartBlock; + UInt32 NumBlocks; + char Name[32]; + char Type[32]; + /* + UInt32 DataStartBlock; + UInt32 NumDataBlocks; + UInt32 Status; + UInt32 BootStartBlock; + UInt32 BootSize; + UInt32 BootAddr; + UInt32 BootEntry; + UInt32 BootChecksum; + char Processor[16]; + */ + + bool Parse(const Byte *p, UInt32 &numBlocksInMap) + { + if (p[0] != 0x50 || p[1] != 0x4D || p[2] != 0 || p[3] != 0) + return false; + numBlocksInMap = Get32(p + 4); + StartBlock = Get32(p + 8); + NumBlocks = Get32(p + 0xC); + memcpy(Name, p + 0x10, 32); + memcpy(Type, p + 0x30, 32); + /* + DataStartBlock = Get32(p + 0x50); + NumDataBlocks = Get32(p + 0x54); + Status = Get32(p + 0x58); + BootStartBlock = Get32(p + 0x5C); + BootSize = Get32(p + 0x60); + BootAddr = Get32(p + 0x64); + if (Get32(p + 0x68) != 0) + return false; + BootEntry = Get32(p + 0x6C); + if (Get32(p + 0x70) != 0) + return false; + BootChecksum = Get32(p + 0x74); + memcpy(Processor, p + 0x78, 16); + */ + return true; + } +}; + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CMyComPtr<IInStream> _stream; + CRecordVector<CItem> _items; + + int _blockSizeLog; + UInt32 _numBlocks; + + HRESULT ReadTables(IInStream *stream); + UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; } + UInt64 GetItemSize(const CItem &item) { return BlocksToBytes(item.NumBlocks); } +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +static inline int GetLog(UInt32 num) +{ + for (int i = 0; i < 31; i++) + if (((UInt32)1 << i) == num) + return i; + return -1; +} + +HRESULT CHandler::ReadTables(IInStream *stream) +{ + const UInt32 kSectorSize = 512; + Byte buf[kSectorSize]; + { + RINOK(ReadStream_FALSE(stream, buf, kSectorSize)); + if (buf[0] != 0x45 || buf[1] != 0x52) + return S_FALSE; + _blockSizeLog = GetLog(Get16(buf + 2)); + if (_blockSizeLog < 9 || _blockSizeLog > 14) + return S_FALSE; + _numBlocks = Get32(buf + 4); + for (int i = 8; i < 16; i++) + if (buf[i] != 0) + return S_FALSE; + } + + unsigned numSkips = (unsigned)1 << (_blockSizeLog - 9); + for (unsigned j = 1; j < numSkips; j++) + { + RINOK(ReadStream_FALSE(stream, buf, kSectorSize)); + } + + UInt32 numBlocksInMap = 0; + for (unsigned i = 0;;) + { + RINOK(ReadStream_FALSE(stream, buf, kSectorSize)); + + CItem item; + + UInt32 numBlocksInMap2; + if (!item.Parse(buf, numBlocksInMap2)) + return S_FALSE; + if (i == 0) + { + numBlocksInMap = numBlocksInMap2; + if (numBlocksInMap > (1 << 8)) + return S_FALSE; + } + else if (numBlocksInMap2 != numBlocksInMap) + return S_FALSE; + + UInt32 finish = item.StartBlock + item.NumBlocks; + if (finish < item.StartBlock) + return S_FALSE; + _numBlocks = MyMax(_numBlocks, finish); + + _items.Add(item); + for (unsigned j = 1; j < numSkips; j++) + { + RINOK(ReadStream_FALSE(stream, buf, kSectorSize)); + } + if (++i == numBlocksInMap) + break; + } + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + RINOK(ReadTables(stream)); + _stream = stream; + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _items.Clear(); + _stream.Release(); + return S_OK; +} + +STATPROPSTG kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidOffset, VT_UI8} +}; + +STATPROPSTG kArcProps[] = +{ + { NULL, kpidClusterSize, VT_UI4}, + { NULL, kpidPhySize, VT_UI8} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +static AString GetString(const char *s) +{ + AString res; + for (int i = 0; i < 32 && s[i] != 0; i++) + res += s[i]; + return res; +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch(propID) + { + case kpidMainSubfile: + { + int mainIndex = -1; + for (int i = 0; i < _items.Size(); i++) + { + AString s = GetString(_items[i].Type); + if (s != "Apple_Free" && + s != "Apple_partition_map") + { + if (mainIndex >= 0) + { + mainIndex = -1; + break; + } + mainIndex = i; + } + } + if (mainIndex >= 0) + prop = (UInt32)mainIndex; + break; + } + case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break; + case kpidPhySize: prop = BlocksToBytes(_numBlocks); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + const CItem &item = _items[index]; + switch(propID) + { + case kpidPath: + { + AString s = GetString(item.Name); + if (s.IsEmpty()) + { + char s2[32]; + ConvertUInt32ToString(index, s2); + s = s2; + } + AString type = GetString(item.Type); + if (type == "Apple_HFS") + type = "hfs"; + if (!type.IsEmpty()) + { + s += '.'; + s += type; + } + prop = s; + break; + } + case kpidSize: + case kpidPackSize: + prop = GetItemSize(item); + break; + case kpidOffset: prop = BlocksToBytes(item.StartBlock); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += GetItemSize(_items[allFilesMode ? i : indices[i]]); + extractCallback->SetTotal(totalSize); + + totalSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream(streamSpec); + streamSpec->SetStream(_stream); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr<ISequentialOutStream> outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + UInt64 size = GetItemSize(item); + totalSize += size; + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + + RINOK(_stream->Seek(BlocksToBytes(item.StartBlock), STREAM_SEEK_SET, NULL)); + streamSpec->Init(size); + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + outStream.Release(); + RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == size ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + const CItem &item = _items[index]; + return CreateLimitedInStream(_stream, BlocksToBytes(item.StartBlock), GetItemSize(item), stream); + COM_TRY_END +} + +static IInArchive *CreateArc() { return new CHandler; } + +static CArcInfo g_ArcInfo = + { L"APM", L"", 0, 0xD4, { 0x50, 0x4D, 0, 0, 0, 0, 0 }, 7, false, CreateArc, 0 }; + +REGISTER_ARC(Apm) + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/ArchiveExports.cpp b/src/libs/7zip/win/CPP/7zip/Archive/ArchiveExports.cpp new file mode 100644 index 000000000..c7908b591 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/ArchiveExports.cpp @@ -0,0 +1,135 @@ +// ArchiveExports.cpp + +#include "StdAfx.h" + +#include "../../Common/ComTry.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/RegisterArc.h" + +static const unsigned int kNumArcsMax = 48; +static unsigned int g_NumArcs = 0; +static unsigned int g_DefaultArcIndex = 0; +static const CArcInfo *g_Arcs[kNumArcsMax]; +void RegisterArc(const CArcInfo *arcInfo) +{ + if (g_NumArcs < kNumArcsMax) + { + const wchar_t *p = arcInfo->Name; + if (p[0] == '7' && p[1] == 'z' && p[2] == 0) + g_DefaultArcIndex = g_NumArcs; + g_Arcs[g_NumArcs++] = arcInfo; + } +} + +DEFINE_GUID(CLSID_CArchiveHandler, +0x23170F69, 0x40C1, 0x278A, 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 int size, PROPVARIANT *value) +{ + if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != 0) + value->vt = VT_BSTR; + return S_OK; +} + +static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value) +{ + return SetPropString((const char *)&guid, sizeof(GUID), value); +} + +int FindFormatCalssId(const GUID *clsID) +{ + GUID cls = *clsID; + CLS_ARC_ID_ITEM(cls) = 0; + if (cls != CLSID_CArchiveHandler) + return -1; + Byte id = CLS_ARC_ID_ITEM(*clsID); + for (unsigned i = 0; i < g_NumArcs; i++) + if (g_Arcs[i]->ClassId == id) + return (int)i; + return -1; +} + +STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject) +{ + COM_TRY_BEGIN + { + int needIn = (*iid == IID_IInArchive); + int needOut = (*iid == IID_IOutArchive); + if (!needIn && !needOut) + return E_NOINTERFACE; + int formatIndex = FindFormatCalssId(clsid); + if (formatIndex < 0) + return CLASS_E_CLASSNOTAVAILABLE; + + const CArcInfo &arc = *g_Arcs[formatIndex]; + if (needIn) + { + *outObject = arc.CreateInArchive(); + ((IInArchive *)*outObject)->AddRef(); + } + else + { + if (!arc.CreateOutArchive) + return CLASS_E_CLASSNOTAVAILABLE; + *outObject = arc.CreateOutArchive(); + ((IOutArchive *)*outObject)->AddRef(); + } + } + COM_TRY_END + return S_OK; +} + +STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + if (formatIndex >= g_NumArcs) + return E_INVALIDARG; + const CArcInfo &arc = *g_Arcs[formatIndex]; + NWindows::NCOM::CPropVariant prop; + switch(propID) + { + case NArchive::kName: + prop = arc.Name; + break; + case NArchive::kClassID: + { + GUID clsId = CLSID_CArchiveHandler; + CLS_ARC_ID_ITEM(clsId) = arc.ClassId; + return SetPropGUID(clsId, value); + } + case NArchive::kExtension: + if (arc.Ext != 0) + prop = arc.Ext; + break; + case NArchive::kAddExtension: + if (arc.AddExt != 0) + prop = arc.AddExt; + break; + case NArchive::kUpdate: + prop = (bool)(arc.CreateOutArchive != 0); + break; + case NArchive::kKeepName: + prop = arc.KeepName; + break; + case NArchive::kStartSignature: + return SetPropString((const char *)arc.Signature, arc.SignatureSize, value); + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value) +{ + return GetHandlerProperty2(g_DefaultArcIndex, propID, value); +} + +STDAPI GetNumberOfFormats(UINT32 *numFormats) +{ + *numFormats = g_NumArcs; + return S_OK; +} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/ArjHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/ArjHandler.cpp new file mode 100644 index 000000000..4dd686ec0 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/ArjHandler.cpp @@ -0,0 +1,798 @@ +// ArjHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "Common/ComTry.h" +#include "Common/StringConvert.h" + +#include "Windows/PropVariant.h" +#include "Windows/Time.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/ArjDecoder1.h" +#include "../Compress/ArjDecoder2.h" +#include "../Compress/CopyCoder.h" + +#include "Common/ItemNameUtils.h" +#include "Common/OutStreamWithCRC.h" + +using namespace NWindows; + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + +namespace NArchive { +namespace NArj { + +const int kBlockSizeMin = 30; +const int kBlockSizeMax = 2600; + +namespace NSignature +{ + const Byte kSig0 = 0x60; + const Byte kSig1 = 0xEA; +} + +namespace NFileHeader +{ + namespace NCompressionMethod + { + enum + { + kStored = 0, + kCompressed1a = 1, + kCompressed1b = 2, + kCompressed1c = 3, + kCompressed2 = 4, + kNoDataNoCRC = 8, + kNoData = 9 + }; + } + + namespace NFileType + { + enum + { + kBinary = 0, + k7BitText = 1, + kArchiveHeader = 2, + kDirectory = 3, + kVolumeLablel = 4, + kChapterLabel = 5 + }; + } + + namespace NFlags + { + const Byte kGarbled = 1; + const Byte kVolume = 4; + const Byte kExtFile = 8; + const Byte kPathSym = 0x10; + const Byte kBackup = 0x20; + } + + namespace NHostOS + { + enum EEnum + { + kMSDOS = 0, // filesystem used by MS-DOS, OS/2, Win32 + // pkarj 2.50 (FAT / VFAT / FAT32 file systems) + kPRIMOS, + kUnix, + kAMIGA, + kMac, + kOS_2, + kAPPLE_GS, + kAtari_ST, + kNext, + kVAX_VMS, + kWIN95 + }; + } +} + +struct CArchiveHeader +{ + // Byte ArchiverVersion; + // Byte ExtractVersion; + Byte HostOS; + // Byte Flags; + // Byte SecuryVersion; + // Byte FileType; + // Byte Reserved; + UInt32 CTime; + UInt32 MTime; + UInt32 ArchiveSize; + // UInt32 SecurityEnvelopeFilePosition; + // UInt16 FilespecPositionInFilename; + // UInt16 LengthOfSecurityEnvelopeSata; + // Byte EncryptionVersion; + // Byte LastChapter; + AString Name; + AString Comment; + + HRESULT Parse(const Byte *p, unsigned size); +}; + +static HRESULT ReadString(const Byte *p, unsigned &size, AString &res) +{ + AString s; + for (unsigned i = 0; i < size;) + { + char c = (char)p[i++]; + if (c == 0) + { + size = i; + res = s; + return S_OK; + } + s += c; + } + return S_FALSE; +} + +HRESULT CArchiveHeader::Parse(const Byte *p, unsigned size) +{ + if (size < kBlockSizeMin) + return S_FALSE; + Byte firstHeaderSize = p[0]; + if (firstHeaderSize > size) + return S_FALSE; + // ArchiverVersion = p[1]; + // ExtractVersion = p[2]; + HostOS = p[3]; + // Flags = p[4]; + // SecuryVersion = p[5]; + if (p[6] != NFileHeader::NFileType::kArchiveHeader) + return S_FALSE; + // Reserved = p[7]; + CTime = Get32(p + 8); + MTime = Get32(p + 12); + ArchiveSize = Get32(p + 16); + // SecurityEnvelopeFilePosition = Get32(p + 20); + // UInt16 filespecPositionInFilename = Get16(p + 24); + // LengthOfSecurityEnvelopeSata = Get16(p + 26); + // EncryptionVersion = p[28]; + // LastChapter = p[29]; + unsigned pos = firstHeaderSize; + unsigned size1 = size - pos; + RINOK(ReadString(p + pos, size1, Name)); + pos += size1; + size1 = size - pos; + RINOK(ReadString(p + pos, size1, Comment)); + pos += size1; + return S_OK; +} + +struct CItem +{ + AString Name; + AString Comment; + + UInt32 MTime; + UInt32 PackSize; + UInt32 Size; + UInt32 FileCRC; + UInt32 SplitPos; + + Byte Version; + Byte ExtractVersion; + Byte HostOS; + Byte Flags; + Byte Method; + Byte FileType; + + // UInt16 FilespecPositionInFilename; + UInt16 FileAccessMode; + // Byte FirstChapter; + // Byte LastChapter; + + UInt64 DataPosition; + + bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kGarbled) != 0; } + bool IsDir() const { return (FileType == NFileHeader::NFileType::kDirectory); } + bool IsSplitAfter() const { return (Flags & NFileHeader::NFlags::kVolume) != 0; } + bool IsSplitBefore() const { return (Flags & NFileHeader::NFlags::kExtFile) != 0; } + UInt32 GetWinAttributes() const + { + UInt32 winAtrributes; + switch(HostOS) + { + case NFileHeader::NHostOS::kMSDOS: + case NFileHeader::NHostOS::kWIN95: + winAtrributes = FileAccessMode; + break; + default: + winAtrributes = 0; + } + if (IsDir()) + winAtrributes |= FILE_ATTRIBUTE_DIRECTORY; + return winAtrributes; + } + + HRESULT Parse(const Byte *p, unsigned size); +}; + +HRESULT CItem::Parse(const Byte *p, unsigned size) +{ + if (size < kBlockSizeMin) + return S_FALSE; + + Byte firstHeaderSize = p[0]; + + Version = p[1]; + ExtractVersion = p[2]; + HostOS = p[3]; + Flags = p[4]; + Method = p[5]; + FileType = p[6]; + // Reserved = p[7]; + MTime = Get32(p + 8); + PackSize = Get32(p + 12); + Size = Get32(p + 16); + FileCRC = Get32(p + 20); + // FilespecPositionInFilename = Get16(p + 24); + FileAccessMode = Get16(p + 26); + // FirstChapter = p[28]; + // FirstChapter = p[29]; + + SplitPos = 0; + if (IsSplitBefore() && firstHeaderSize >= 34) + SplitPos = Get32(p + 30); + + unsigned pos = firstHeaderSize; + unsigned size1 = size - pos; + RINOK(ReadString(p + pos, size1, Name)); + pos += size1; + size1 = size - pos; + RINOK(ReadString(p + pos, size1, Comment)); + pos += size1; + + return S_OK; +} + +struct CInArchiveException +{ + enum CCauseType + { + kUnexpectedEndOfArchive = 0, + kCRCError, + kIncorrectArchive + } + Cause; + CInArchiveException(CCauseType cause): Cause(cause) {}; +}; + +class CInArchive +{ + UInt32 _blockSize; + Byte _block[kBlockSizeMax + 4]; + + HRESULT ReadBlock(bool &filled); + HRESULT ReadSignatureAndBlock(bool &filled); + HRESULT SkipExtendedHeaders(); + + HRESULT SafeReadBytes(void *data, UInt32 size); + +public: + CArchiveHeader Header; + + IInStream *Stream; + IArchiveOpenCallback *Callback; + UInt64 NumFiles; + UInt64 NumBytes; + + HRESULT Open(const UInt64 *searchHeaderSizeLimit); + HRESULT GetNextItem(bool &filled, CItem &item); +}; + +static inline bool TestMarkerCandidate(const Byte *p, unsigned maxSize) +{ + if (p[0] != NSignature::kSig0 || p[1] != NSignature::kSig1) + return false; + UInt32 blockSize = Get16(p + 2); + p += 4; + if (p[6] != NFileHeader::NFileType::kArchiveHeader || + p[0] > blockSize || + maxSize < 2 + 2 + blockSize + 4 || + blockSize < kBlockSizeMin || blockSize > kBlockSizeMax || + p[28] > 8) // EncryptionVersion + return false; + // return (Get32(p + blockSize) == CrcCalc(p, blockSize)); + return true; +} + +static HRESULT FindAndReadMarker(ISequentialInStream *stream, const UInt64 *searchHeaderSizeLimit, UInt64 &position) +{ + position = 0; + + const int kMarkerSizeMin = 2 + 2 + kBlockSizeMin + 4; + const int kMarkerSizeMax = 2 + 2 + kBlockSizeMax + 4; + + CByteBuffer byteBuffer; + const UInt32 kBufSize = 1 << 16; + byteBuffer.SetCapacity(kBufSize); + Byte *buf = byteBuffer; + + size_t processedSize = kMarkerSizeMax; + RINOK(ReadStream(stream, buf, &processedSize)); + if (processedSize < kMarkerSizeMin) + return S_FALSE; + if (TestMarkerCandidate(buf, (unsigned)processedSize)) + return S_OK; + + UInt32 numBytesPrev = (UInt32)processedSize - 1; + memmove(buf, buf + 1, numBytesPrev); + UInt64 curTestPos = 1; + for (;;) + { + if (searchHeaderSizeLimit != NULL) + if (curTestPos > *searchHeaderSizeLimit) + return S_FALSE; + processedSize = kBufSize - numBytesPrev; + RINOK(ReadStream(stream, buf + numBytesPrev, &processedSize)); + UInt32 numBytesInBuffer = numBytesPrev + (UInt32)processedSize; + if (numBytesInBuffer < kMarkerSizeMin) + return S_FALSE; + UInt32 numTests = numBytesInBuffer - kMarkerSizeMin + 1; + UInt32 pos; + for (pos = 0; pos < numTests; pos++) + { + for (; buf[pos] != NSignature::kSig0 && pos < numTests; pos++); + if (pos == numTests) + break; + if (TestMarkerCandidate(buf + pos, numBytesInBuffer - pos)) + { + position = curTestPos + pos; + return S_OK; + } + } + curTestPos += pos; + numBytesPrev = numBytesInBuffer - numTests; + memmove(buf, buf + numTests, numBytesPrev); + } +} + +HRESULT CInArchive::SafeReadBytes(void *data, UInt32 size) +{ + size_t processed = size; + RINOK(ReadStream(Stream, data, &processed)); + if (processed != size) + throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive); + return S_OK; +} + +HRESULT CInArchive::ReadBlock(bool &filled) +{ + filled = false; + Byte buf[2]; + RINOK(SafeReadBytes(buf, 2)); + _blockSize = Get16(buf); + if (_blockSize == 0) + return S_OK; + if (_blockSize > kBlockSizeMax) + throw CInArchiveException(CInArchiveException::kIncorrectArchive); + RINOK(SafeReadBytes(_block, _blockSize + 4)); + NumBytes += _blockSize + 6; + if (Get32(_block + _blockSize) != CrcCalc(_block, _blockSize)) + throw CInArchiveException(CInArchiveException::kCRCError); + filled = true; + return S_OK; +} + +HRESULT CInArchive::ReadSignatureAndBlock(bool &filled) +{ + Byte id[2]; + RINOK(SafeReadBytes(id, 2)); + if (id[0] != NSignature::kSig0 || id[1] != NSignature::kSig1) + throw CInArchiveException(CInArchiveException::kIncorrectArchive); + return ReadBlock(filled); +} + +HRESULT CInArchive::SkipExtendedHeaders() +{ + for (UInt32 i = 0;; i++) + { + bool filled; + RINOK(ReadBlock(filled)); + if (!filled) + return S_OK; + if (Callback && (i & 0xFF) == 0) + RINOK(Callback->SetCompleted(&NumFiles, &NumBytes)); + } +} + +HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit) +{ + UInt64 position = 0; + RINOK(FindAndReadMarker(Stream, searchHeaderSizeLimit, position)); + RINOK(Stream->Seek(position, STREAM_SEEK_SET, NULL)); + bool filled; + RINOK(ReadSignatureAndBlock(filled)); + if (!filled) + return S_FALSE; + RINOK(Header.Parse(_block, _blockSize)); + return SkipExtendedHeaders(); +} + +HRESULT CInArchive::GetNextItem(bool &filled, CItem &item) +{ + RINOK(ReadSignatureAndBlock(filled)); + if (!filled) + return S_OK; + filled = false; + RINOK(item.Parse(_block, _blockSize)); + /* + UInt32 extraData; + if ((header.Flags & NFileHeader::NFlags::kExtFile) != 0) + extraData = GetUi32(_block + pos); + */ + + RINOK(SkipExtendedHeaders()); + filled = true; + return S_OK; +} + +class CHandler: + public IInArchive, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP1(IInArchive) + + INTERFACE_IInArchive(;) + + HRESULT Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *callback); +private: + CInArchive _archive; + CObjectVector<CItem> _items; + CMyComPtr<IInStream> _stream; +}; + +const wchar_t *kHostOS[] = +{ + L"MSDOS", + L"PRIMOS", + L"UNIX", + L"AMIGA", + L"MAC", + L"OS/2", + L"APPLE GS", + L"ATARI ST", + L"NEXT", + L"VAX VMS", + L"WIN95" +}; + +const wchar_t *kUnknownOS = L"Unknown"; + +const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]); + +STATPROPSTG kArcProps[] = +{ + { NULL, kpidName, VT_BSTR}, + { NULL, kpidCTime, VT_BSTR}, + { NULL, kpidMTime, VT_BSTR}, + { NULL, kpidHostOS, VT_BSTR}, + { NULL, kpidComment, VT_BSTR} +}; + +STATPROPSTG kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidIsDir, VT_BOOL}, + { NULL, kpidSize, VT_UI4}, + { NULL, kpidPosition, VT_UI8}, + { NULL, kpidPackSize, VT_UI4}, + { NULL, kpidMTime, VT_FILETIME}, + { NULL, kpidAttrib, VT_UI4}, + { NULL, kpidEncrypted, VT_BOOL}, + { NULL, kpidCRC, VT_UI4}, + { NULL, kpidMethod, VT_UI1}, + { NULL, kpidHostOS, VT_BSTR}, + { NULL, kpidComment, VT_BSTR} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +static void SetTime(UInt32 dosTime, NWindows::NCOM::CPropVariant &prop) +{ + if (dosTime == 0) + return; + FILETIME localFileTime, utc; + if (NTime::DosTimeToFileTime(dosTime, localFileTime)) + { + if (!LocalFileTimeToFileTime(&localFileTime, &utc)) + utc.dwHighDateTime = utc.dwLowDateTime = 0; + } + else + utc.dwHighDateTime = utc.dwLowDateTime = 0; + prop = utc; +} + +static void SetHostOS(Byte hostOS, NWindows::NCOM::CPropVariant &prop) +{ + prop = hostOS < kNumHostOSes ? kHostOS[hostOS] : kUnknownOS; +} + +static void SetUnicodeString(const AString &s, NWindows::NCOM::CPropVariant &prop) +{ + if (!s.IsEmpty()) + prop = MultiByteToUnicodeString(s, CP_OEMCP); +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch(propID) + { + case kpidName: SetUnicodeString(_archive.Header.Name, prop); break; + case kpidCTime: SetTime(_archive.Header.CTime, prop); break; + case kpidMTime: SetTime(_archive.Header.MTime, prop); break; + case kpidHostOS: SetHostOS(_archive.Header.HostOS, prop); break; + case kpidComment: SetUnicodeString(_archive.Header.Comment, prop); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem &item = _items[index]; + switch(propID) + { + case kpidPath: prop = NItemName::GetOSName(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break; + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: prop = item.Size; break; + case kpidPackSize: prop = item.PackSize; break; + case kpidPosition: if (item.IsSplitBefore() || item.IsSplitAfter()) prop = (UInt64)item.SplitPos; break; + case kpidAttrib: prop = item.GetWinAttributes(); break; + case kpidEncrypted: prop = item.IsEncrypted(); break; + case kpidCRC: prop = item.FileCRC; break; + case kpidMethod: prop = item.Method; break; + case kpidHostOS: SetHostOS(item.HostOS, prop); break; + case kpidMTime: SetTime(item.MTime, prop); break; + case kpidComment: SetUnicodeString(item.Comment, prop); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +HRESULT CHandler::Open2(IInStream *inStream, const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *callback) +{ + Close(); + + UInt64 endPos = 0; + if (callback != NULL) + { + RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); + RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); + } + + _archive.Stream = inStream; + _archive.Callback = callback; + _archive.NumFiles = _archive.NumBytes = 0; + + RINOK(_archive.Open(maxCheckStartPosition)); + if (callback != NULL) + RINOK(callback->SetTotal(NULL, &endPos)); + for (;;) + { + CItem item; + bool filled; + + + RINOK(_archive.GetNextItem(filled, item)); + + RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &item.DataPosition)); + + if (!filled) + break; + _items.Add(item); + + if (inStream->Seek(item.PackSize, STREAM_SEEK_CUR, NULL) != S_OK) + throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive); + + _archive.NumFiles = _items.Size(); + _archive.NumBytes = item.DataPosition; + + if (callback != NULL && _items.Size() % 100 == 0) + { + RINOK(callback->SetCompleted(&_archive.NumFiles, &_archive.NumBytes)); + } + } + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + HRESULT res; + try + { + res = Open2(inStream, maxCheckStartPosition, callback); + if (res == S_OK) + { + _stream = inStream; + return S_OK; + } + } + catch(const CInArchiveException &) { res = S_FALSE; } + Close(); + return res; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _items.Clear(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + UInt64 totalUnpacked = 0, totalPacked = 0; + bool allFilesMode = (numItems == (UInt32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const CItem &item = _items[allFilesMode ? i : indices[i]]; + totalUnpacked += item.Size; + totalPacked += item.PackSize; + } + extractCallback->SetTotal(totalUnpacked); + + totalUnpacked = totalPacked = 0; + UInt64 curUnpacked, curPacked; + + CMyComPtr<ICompressCoder> arj1Decoder; + CMyComPtr<ICompressCoder> arj2Decoder; + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream(inStreamSpec); + inStreamSpec->SetStream(_stream); + + for (i = 0; i < numItems; i++, totalUnpacked += curUnpacked, totalPacked += curPacked) + { + lps->InSize = totalPacked; + lps->OutSize = totalUnpacked; + RINOK(lps->SetCur()); + + curUnpacked = curPacked = 0; + + CMyComPtr<ISequentialOutStream> realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + if (item.IsDir()) + { + // if (!testMode) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + } + continue; + } + + if (!testMode && !realOutStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)); + curUnpacked = item.Size; + curPacked = item.PackSize; + + { + COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; + CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + realOutStream.Release(); + outStreamSpec->Init(); + + inStreamSpec->Init(item.PackSize); + + UInt64 pos; + _stream->Seek(item.DataPosition, STREAM_SEEK_SET, &pos); + + HRESULT result = S_OK; + Int32 opRes = NExtract::NOperationResult::kOK; + + if (item.IsEncrypted()) + opRes = NExtract::NOperationResult::kUnSupportedMethod; + else + { + switch(item.Method) + { + case NFileHeader::NCompressionMethod::kStored: + { + result = copyCoder->Code(inStream, outStream, NULL, NULL, progress); + if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize) + result = S_FALSE; + break; + } + case NFileHeader::NCompressionMethod::kCompressed1a: + case NFileHeader::NCompressionMethod::kCompressed1b: + case NFileHeader::NCompressionMethod::kCompressed1c: + { + if (!arj1Decoder) + arj1Decoder = new NCompress::NArj::NDecoder1::CCoder; + result = arj1Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress); + break; + } + case NFileHeader::NCompressionMethod::kCompressed2: + { + if (!arj2Decoder) + arj2Decoder = new NCompress::NArj::NDecoder2::CCoder; + result = arj2Decoder->Code(inStream, outStream, NULL, &curUnpacked, progress); + break; + } + default: + opRes = NExtract::NOperationResult::kUnSupportedMethod; + } + } + if (opRes == NExtract::NOperationResult::kOK) + { + if (result == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else + { + RINOK(result); + opRes = (outStreamSpec->GetCRC() == item.FileCRC) ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kCRCError; + } + } + outStream.Release(); + RINOK(extractCallback->SetOperationResult(opRes)); + } + } + return S_OK; + COM_TRY_END +} + +static IInArchive *CreateArc() { return new CHandler; } + +static CArcInfo g_ArcInfo = + { L"Arj", L"arj", 0, 4, { 0x60, 0xEA }, 2, false, CreateArc, 0 }; + +REGISTER_ARC(Arj) + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Bz2Handler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Bz2Handler.cpp new file mode 100644 index 000000000..98cbcc182 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Bz2Handler.cpp @@ -0,0 +1,423 @@ +// Bz2Handler.cpp + +#include "StdAfx.h" + +#include "Common/ComTry.h" + +#include "Windows/PropVariant.h" + +#ifndef _7ZIP_ST +#include "../../Windows/System.h" +#endif + +#include "../Common/CreateCoder.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/BZip2Decoder.h" +#include "../Compress/BZip2Encoder.h" +#include "../Compress/CopyCoder.h" + +#include "Common/DummyOutStream.h" +#include "Common/ParseProperties.h" + +using namespace NWindows; + +namespace NArchive { +namespace NBz2 { + +static const UInt32 kNumPassesX1 = 1; +static const UInt32 kNumPassesX7 = 2; +static const UInt32 kNumPassesX9 = 7; + +static const UInt32 kDicSizeX1 = 100000; +static const UInt32 kDicSizeX3 = 500000; +static const UInt32 kDicSizeX5 = 900000; + +class CHandler: + public IInArchive, + public IArchiveOpenSeq, + public IOutArchive, + public ISetProperties, + public CMyUnknownImp +{ + CMyComPtr<IInStream> _stream; + CMyComPtr<ISequentialInStream> _seqStream; + UInt64 _packSize; + UInt64 _startPosition; + bool _packSizeDefined; + + UInt32 _level; + UInt32 _dicSize; + UInt32 _numPasses; + #ifndef _7ZIP_ST + UInt32 _numThreads; + #endif + + void InitMethodProperties() + { + _level = 5; + _dicSize = + _numPasses = 0xFFFFFFFF; + #ifndef _7ZIP_ST + _numThreads = NWindows::NSystem::GetNumberOfProcessors();; + #endif + } + +public: + MY_UNKNOWN_IMP4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties) + + INTERFACE_IInArchive(;) + INTERFACE_IOutArchive(;) + STDMETHOD(OpenSeq)(ISequentialInStream *stream); + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProps); + + CHandler() { InitMethodProperties(); } +}; + +STATPROPSTG kProps[] = +{ + { NULL, kpidPackSize, VT_UI8} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + NCOM::CPropVariant prop; + switch(propID) + { + case kpidPhySize: if (_packSizeDefined) prop = _packSize; break; + } + prop.Detach(value); + return S_OK; +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = 1; + return S_OK; +} + +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +{ + NWindows::NCOM::CPropVariant prop; + switch(propID) + { + case kpidPackSize: if (_packSizeDefined) prop = _packSize; break; + } + prop.Detach(value); + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + try + { + Close(); + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPosition)); + const int kSignatureSize = 3; + Byte buf[kSignatureSize]; + RINOK(ReadStream_FALSE(stream, buf, kSignatureSize)); + if (buf[0] != 'B' || buf[1] != 'Z' || buf[2] != 'h') + return S_FALSE; + + UInt64 endPosition; + RINOK(stream->Seek(0, STREAM_SEEK_END, &endPosition)); + _packSize = endPosition - _startPosition; + _packSizeDefined = true; + _stream = stream; + _seqStream = stream; + } + catch(...) { return S_FALSE; } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) +{ + Close(); + _seqStream = stream; + return S_OK; +} + +STDMETHODIMP CHandler::Close() +{ + _packSizeDefined = false; + _seqStream.Release(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + if (_stream) + extractCallback->SetTotal(_packSize); + UInt64 currentTotalPacked = 0; + RINOK(extractCallback->SetCompleted(¤tTotalPacked)); + CMyComPtr<ISequentialOutStream> realOutStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); + if (!testMode && !realOutStream) + return S_OK; + + extractCallback->PrepareOperation(askMode); + + NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder; + CMyComPtr<ICompressCoder> decoder = decoderSpec; + + if (_stream) + { + RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL)); + } + + decoderSpec->SetInStream(_seqStream); + + #ifndef _7ZIP_ST + RINOK(decoderSpec->SetNumberOfThreads(_numThreads)); + #endif + + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + + realOutStream.Release(); + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, true); + + HRESULT result = S_OK; + + bool firstItem = true; + for (;;) + { + lps->InSize = currentTotalPacked; + lps->OutSize = outStreamSpec->GetSize(); + + RINOK(lps->SetCur()); + + bool isBz2; + result = decoderSpec->CodeResume(outStream, isBz2, progress); + + if (result != S_OK) + break; + if (!isBz2) + { + if (firstItem) + result = S_FALSE; + break; + } + firstItem = false; + + _packSize = currentTotalPacked = decoderSpec->GetInputProcessedSize(); + _packSizeDefined = true; + } + decoderSpec->ReleaseInStream(); + outStream.Release(); + + Int32 retResult; + if (result == S_OK) + retResult = NExtract::NOperationResult::kOK; + else if (result == S_FALSE) + retResult = NExtract::NOperationResult::kDataError; + else + return result; + return extractCallback->SetOperationResult(retResult); + + COM_TRY_END +} + +static HRESULT UpdateArchive( + UInt64 unpackSize, + ISequentialOutStream *outStream, + int indexInClient, + UInt32 dictionary, + UInt32 numPasses, + #ifndef _7ZIP_ST + UInt32 numThreads, + #endif + IArchiveUpdateCallback *updateCallback) +{ + RINOK(updateCallback->SetTotal(unpackSize)); + UInt64 complexity = 0; + RINOK(updateCallback->SetCompleted(&complexity)); + + CMyComPtr<ISequentialInStream> fileInStream; + + RINOK(updateCallback->GetStream(indexInClient, &fileInStream)); + + CLocalProgress *localProgressSpec = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec; + localProgressSpec->Init(updateCallback, true); + + NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder; + CMyComPtr<ICompressCoder> encoder = encoderSpec; + { + NWindows::NCOM::CPropVariant properties[] = + { + dictionary, + numPasses + #ifndef _7ZIP_ST + , numThreads + #endif + }; + PROPID propIDs[] = + { + NCoderPropID::kDictionarySize, + NCoderPropID::kNumPasses + #ifndef _7ZIP_ST + , NCoderPropID::kNumThreads + #endif + }; + RINOK(encoderSpec->SetCoderProperties(propIDs, properties, sizeof(propIDs) / sizeof(propIDs[0]))); + } + + RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); + + return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); +} + +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) +{ + *type = NFileTimeType::kUnix; + return S_OK; +} + +STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback) +{ + if (numItems != 1) + return E_INVALIDARG; + + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); + + if (IntToBool(newProps)) + { + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)); + if (prop.vt == VT_BOOL) + { + if (prop.boolVal != VARIANT_FALSE) + return E_INVALIDARG; + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + } + + if (IntToBool(newData)) + { + UInt64 size; + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidSize, &prop)); + if (prop.vt != VT_UI8) + return E_INVALIDARG; + size = prop.uhVal.QuadPart; + } + + UInt32 dicSize = _dicSize; + if (dicSize == 0xFFFFFFFF) + dicSize = (_level >= 5 ? kDicSizeX5 : + (_level >= 3 ? kDicSizeX3 : + kDicSizeX1)); + + UInt32 numPasses = _numPasses; + if (numPasses == 0xFFFFFFFF) + numPasses = (_level >= 9 ? kNumPassesX9 : + (_level >= 7 ? kNumPassesX7 : + kNumPassesX1)); + + return UpdateArchive( + size, outStream, 0, dicSize, numPasses, + #ifndef _7ZIP_ST + _numThreads, + #endif + updateCallback); + } + if (indexInArchive != 0) + return E_INVALIDARG; + if (_stream) + RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL)); + return NCompress::CopyStream(_stream, outStream, NULL); +} + +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProps) +{ + InitMethodProperties(); + #ifndef _7ZIP_ST + const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); + _numThreads = numProcessors; + #endif + + for (int i = 0; i < numProps; i++) + { + UString name = names[i]; + name.MakeUpper(); + if (name.IsEmpty()) + return E_INVALIDARG; + const PROPVARIANT &prop = values[i]; + if (name[0] == L'X') + { + UInt32 level = 9; + RINOK(ParsePropValue(name.Mid(1), prop, level)); + _level = level; + } + else if (name[0] == L'D') + { + UInt32 dicSize = kDicSizeX5; + RINOK(ParsePropDictionaryValue(name.Mid(1), prop, dicSize)); + _dicSize = dicSize; + } + else if (name.Left(4) == L"PASS") + { + UInt32 num = kNumPassesX9; + RINOK(ParsePropValue(name.Mid(4), prop, num)); + _numPasses = num; + } + else if (name.Left(2) == L"MT") + { + #ifndef _7ZIP_ST + RINOK(ParseMtProp(name.Mid(2), prop, numProcessors, _numThreads)); + #endif + } + else + return E_INVALIDARG; + } + return S_OK; +} + +static IInArchive *CreateArc() { return new CHandler; } +#ifndef EXTRACT_ONLY +static IOutArchive *CreateArcOut() { return new CHandler; } +#else +#define CreateArcOut 0 +#endif + +static CArcInfo g_ArcInfo = + { L"bzip2", L"bz2 bzip2 tbz2 tbz", L"* * .tar .tar", 2, { 'B', 'Z', 'h' }, 3, true, CreateArc, CreateArcOut }; + +REGISTER_ARC(BZip2) + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.cpp new file mode 100644 index 000000000..12c73eb5f --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.cpp @@ -0,0 +1,189 @@ +// CabBlockInStream.cpp + +#include "StdAfx.h" + +#include "../../../../C/Alloc.h" + +#include "Common/Defs.h" + +#include "../../Common/StreamUtils.h" + +#include "CabBlockInStream.h" + +namespace NArchive { +namespace NCab { + +static const UInt32 kBlockSize = (1 << 16); + +bool CCabBlockInStream::Create() +{ + if (!_buffer) + _buffer = (Byte *)::MyAlloc(kBlockSize); + return (_buffer != 0); +} + +CCabBlockInStream::~CCabBlockInStream() +{ + MyFree(_buffer); +} + +class CCheckSum2 +{ + UInt32 m_Value; + int m_Pos; + Byte m_Hist[4]; +public: + CCheckSum2(): m_Value(0){}; + void Init() { m_Value = 0; m_Pos = 0; } + void Update(const void *data, UInt32 size); + void FinishDataUpdate() + { + for (int i = 0; i < m_Pos; i++) + m_Value ^= ((UInt32)(m_Hist[i])) << (8 * (m_Pos - i - 1)); + } + void UpdateUInt32(UInt32 v) { m_Value ^= v; } + UInt32 GetResult() const { return m_Value; } +}; + +void CCheckSum2::Update(const void *data, UInt32 size) +{ + UInt32 checkSum = m_Value; + const Byte *dataPointer = (const Byte *)data; + + while (size != 0 && m_Pos != 0) + { + m_Hist[m_Pos] = *dataPointer++; + m_Pos = (m_Pos + 1) & 3; + size--; + if (m_Pos == 0) + for (int i = 0; i < 4; i++) + checkSum ^= ((UInt32)m_Hist[i]) << (8 * i); + } + + int numWords = size / 4; + + while (numWords-- != 0) + { + UInt32 temp = *dataPointer++; + temp |= ((UInt32)(*dataPointer++)) << 8; + temp |= ((UInt32)(*dataPointer++)) << 16; + temp |= ((UInt32)(*dataPointer++)) << 24; + checkSum ^= temp; + } + m_Value = checkSum; + + size &= 3; + + while (size != 0) + { + m_Hist[m_Pos] = *dataPointer++; + m_Pos = (m_Pos + 1) & 3; + size--; + } +} + +static const UInt32 kDataBlockHeaderSize = 8; + +class CTempCabInBuffer2 +{ +public: + Byte Buffer[kDataBlockHeaderSize]; + UInt32 Pos; + Byte ReadByte() + { + return Buffer[Pos++]; + } + UInt32 ReadUInt32() + { + UInt32 value = 0; + for (int i = 0; i < 4; i++) + value |= (((UInt32)ReadByte()) << (8 * i)); + return value; + } + UInt16 ReadUInt16() + { + UInt16 value = 0; + for (int i = 0; i < 2; i++) + value |= (((UInt16)ReadByte()) << (8 * i)); + return value; + } +}; + +HRESULT CCabBlockInStream::PreRead(UInt32 &packSize, UInt32 &unpackSize) +{ + CTempCabInBuffer2 inBuffer; + inBuffer.Pos = 0; + RINOK(ReadStream_FALSE(_stream, inBuffer.Buffer, kDataBlockHeaderSize)) + + UInt32 checkSum = inBuffer.ReadUInt32(); + packSize = inBuffer.ReadUInt16(); + unpackSize = inBuffer.ReadUInt16(); + if (ReservedSize != 0) + { + RINOK(ReadStream_FALSE(_stream, _buffer, ReservedSize)); + } + _pos = 0; + CCheckSum2 checkSumCalc; + checkSumCalc.Init(); + UInt32 packSize2 = packSize; + if (MsZip && _size == 0) + { + if (packSize < 2) + return S_FALSE; // bad block; + Byte sig[2]; + RINOK(ReadStream_FALSE(_stream, sig, 2)); + if (sig[0] != 0x43 || sig[1] != 0x4B) + return S_FALSE; + packSize2 -= 2; + checkSumCalc.Update(sig, 2); + } + + if (kBlockSize - _size < packSize2) + return S_FALSE; + + UInt32 curSize = packSize2; + if (curSize != 0) + { + size_t processedSizeLoc = curSize; + RINOK(ReadStream(_stream, _buffer + _size, &processedSizeLoc)); + checkSumCalc.Update(_buffer + _size, (UInt32)processedSizeLoc); + _size += (UInt32)processedSizeLoc; + if (processedSizeLoc != curSize) + return S_FALSE; + } + TotalPackSize = _size; + + checkSumCalc.FinishDataUpdate(); + + bool dataError; + if (checkSum == 0) + dataError = false; + else + { + checkSumCalc.UpdateUInt32(packSize | (((UInt32)unpackSize) << 16)); + dataError = (checkSumCalc.GetResult() != checkSum); + } + DataError |= dataError; + return dataError ? S_FALSE : S_OK; +} + +STDMETHODIMP CCabBlockInStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize != 0) + *processedSize = 0; + if (size == 0) + return S_OK; + if (_size != 0) + { + size = MyMin(_size, size); + memmove(data, _buffer + _pos, size); + _pos += size; + _size -= size; + if (processedSize != 0) + *processedSize = size; + return S_OK; + } + return S_OK; // no blocks data +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.h b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.h new file mode 100644 index 000000000..1db3835b4 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabBlockInStream.h @@ -0,0 +1,44 @@ +// CabBlockInStream.cpp + +#ifndef __CABBLOCKINSTREAM_H +#define __CABBLOCKINSTREAM_H + +#include "Common/MyCom.h" +#include "../../IStream.h" + +namespace NArchive { +namespace NCab { + +class CCabBlockInStream: + public ISequentialInStream, + public CMyUnknownImp +{ + CMyComPtr<ISequentialInStream> _stream; + Byte *_buffer; + UInt32 _pos; + UInt32 _size; + +public: + UInt32 TotalPackSize; + UInt32 ReservedSize; + bool DataError; + bool MsZip; + + CCabBlockInStream(): _buffer(0), ReservedSize(0), MsZip(false), DataError(false), TotalPackSize(0) {} + ~CCabBlockInStream(); + bool Create(); + void SetStream(ISequentialInStream *stream) { _stream = stream; } + + void InitForNewFolder() { TotalPackSize = 0; } + void InitForNewBlock() { _size = 0; } + + MY_UNKNOWN_IMP + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + + HRESULT PreRead(UInt32 &packSize, UInt32 &unpackSize); +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.cpp new file mode 100644 index 000000000..20f670d35 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.cpp @@ -0,0 +1,929 @@ +// CabHandler.cpp + +#include "StdAfx.h" + +#include "../../../../C/Alloc.h" + +#include "Common/Buffer.h" +#include "Common/ComTry.h" +#include "Common/Defs.h" +#include "Common/IntToString.h" +#include "Common/StringConvert.h" +#include "Common/UTFConvert.h" + +#include "Windows/PropVariant.h" +#include "Windows/Time.h" + +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/CopyCoder.h" +#include "../../Compress/DeflateDecoder.h" +#include "../../Compress/LzxDecoder.h" +#include "../../Compress/QuantumDecoder.h" + +#include "../Common/ItemNameUtils.h" + +#include "CabBlockInStream.h" +#include "CabHandler.h" + +using namespace NWindows; + +namespace NArchive { +namespace NCab { + +// #define _CAB_DETAILS + +#ifdef _CAB_DETAILS +enum +{ + kpidBlockReal = kpidUserDefined +}; +#endif + +static STATPROPSTG kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidMTime, VT_FILETIME}, + { NULL, kpidAttrib, VT_UI4}, + { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidBlock, VT_I4} + #ifdef _CAB_DETAILS + , + { L"BlockReal", kpidBlockReal, VT_UI4}, + { NULL, kpidOffset, VT_UI4}, + { NULL, kpidVolume, VT_UI4} + #endif +}; + +static const char *kMethods[] = +{ + "None", + "MSZip", + "Quantum", + "LZX" +}; + +static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]); +static const char *kUnknownMethod = "Unknown"; + +static STATPROPSTG kArcProps[] = +{ + { NULL, kpidMethod, VT_BSTR}, + // { NULL, kpidSolid, VT_BOOL}, + { NULL, kpidNumBlocks, VT_UI4}, + { NULL, kpidNumVolumes, VT_UI4} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch(propID) + { + case kpidMethod: + { + AString resString; + CRecordVector<Byte> ids; + int i; + for (int v = 0; v < m_Database.Volumes.Size(); v++) + { + const CDatabaseEx &de = m_Database.Volumes[v]; + for (i = 0; i < de.Folders.Size(); i++) + ids.AddToUniqueSorted(de.Folders[i].GetCompressionMethod()); + } + for (i = 0; i < ids.Size(); i++) + { + Byte id = ids[i]; + AString method = (id < kNumMethods) ? kMethods[id] : kUnknownMethod; + if (!resString.IsEmpty()) + resString += ' '; + resString += method; + } + prop = resString; + break; + } + // case kpidSolid: prop = _database.IsSolid(); break; + case kpidNumBlocks: + { + UInt32 numFolders = 0; + for (int v = 0; v < m_Database.Volumes.Size(); v++) + numFolders += m_Database.Volumes[v].Folders.Size(); + prop = numFolders; + break; + } + case kpidNumVolumes: + { + prop = (UInt32)m_Database.Volumes.Size(); + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + + const CMvItem &mvItem = m_Database.Items[index]; + const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; + int itemIndex = mvItem.ItemIndex; + const CItem &item = db.Items[itemIndex]; + switch(propID) + { + case kpidPath: + { + UString unicodeName; + if (item.IsNameUTF()) + ConvertUTF8ToUnicode(item.Name, unicodeName); + else + unicodeName = MultiByteToUnicodeString(item.Name, CP_ACP); + prop = (const wchar_t *)NItemName::WinNameToOSName(unicodeName); + break; + } + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: prop = item.Size; break; + case kpidAttrib: prop = item.GetWinAttributes(); break; + + case kpidMTime: + { + FILETIME localFileTime, utcFileTime; + if (NTime::DosTimeToFileTime(item.Time, localFileTime)) + { + if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime)) + utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; + } + else + utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; + prop = utcFileTime; + break; + } + + case kpidMethod: + { + UInt32 realFolderIndex = item.GetFolderIndex(db.Folders.Size()); + const CFolder &folder = db.Folders[realFolderIndex]; + int methodIndex = folder.GetCompressionMethod(); + AString method = (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod; + if (methodIndex == NHeader::NCompressionMethodMajor::kLZX || + methodIndex == NHeader::NCompressionMethodMajor::kQuantum) + { + method += ':'; + char temp[32]; + ConvertUInt64ToString(folder.CompressionTypeMinor, temp); + method += temp; + } + prop = method; + break; + } + case kpidBlock: prop = (Int32)m_Database.GetFolderIndex(&mvItem); break; + + #ifdef _CAB_DETAILS + + case kpidBlockReal: prop = (UInt32)item.FolderIndex; break; + case kpidOffset: prop = (UInt32)item.Offset; break; + case kpidVolume: prop = (UInt32)mvItem.VolumeIndex; break; + + #endif + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +/* +class CProgressImp: public CProgressVirt +{ + CMyComPtr<IArchiveOpenCallback> m_OpenArchiveCallback; +public: + STDMETHOD(SetTotal)(const UInt64 *numFiles); + STDMETHOD(SetCompleted)(const UInt64 *numFiles); + void Init(IArchiveOpenCallback *openArchiveCallback) + { m_OpenArchiveCallback = openArchiveCallback; } +}; + +STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles) +{ + if (m_OpenArchiveCallback) + return m_OpenArchiveCallback->SetCompleted(numFiles, NULL); + return S_OK; +} + +STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles) +{ + if (m_OpenArchiveCallback) + return m_OpenArchiveCallback->SetCompleted(numFiles, NULL); + return S_OK; +} +*/ + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + Close(); + HRESULT res = S_FALSE; + CInArchive archive; + CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; + callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + + CMyComPtr<IInStream> nextStream = inStream; + bool prevChecked = false; + UInt64 numItems = 0; + try + { + while (nextStream != 0) + { + CDatabaseEx db; + db.Stream = nextStream; + res = archive.Open(maxCheckStartPosition, db); + if (res == S_OK) + { + if (!m_Database.Volumes.IsEmpty()) + { + const CDatabaseEx &dbPrev = m_Database.Volumes[prevChecked ? m_Database.Volumes.Size() - 1 : 0]; + if (dbPrev.ArchiveInfo.SetID != db.ArchiveInfo.SetID || + dbPrev.ArchiveInfo.CabinetNumber + (prevChecked ? 1: - 1) != + db.ArchiveInfo.CabinetNumber) + res = S_FALSE; + } + } + if (res == S_OK) + m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : 0, db); + else if (res != S_FALSE) + return res; + else + { + if (m_Database.Volumes.IsEmpty()) + return S_FALSE; + if (prevChecked) + break; + prevChecked = true; + } + + numItems += db.Items.Size(); + RINOK(callback->SetCompleted(&numItems, NULL)); + + nextStream = 0; + for (;;) + { + const COtherArchive *otherArchive = 0; + if (!prevChecked) + { + const CInArchiveInfo &ai = m_Database.Volumes.Front().ArchiveInfo; + if (ai.IsTherePrev()) + otherArchive = &ai.PrevArc; + else + prevChecked = true; + } + if (otherArchive == 0) + { + const CInArchiveInfo &ai = m_Database.Volumes.Back().ArchiveInfo; + if (ai.IsThereNext()) + otherArchive = &ai.NextArc; + } + if (!otherArchive) + break; + const UString fullName = MultiByteToUnicodeString(otherArchive->FileName, CP_ACP); + if (!openVolumeCallback) + break; + + HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream); + if (result == S_OK) + break; + if (result != S_FALSE) + return result; + if (prevChecked) + break; + prevChecked = true; + } + } + if (res == S_OK) + { + m_Database.FillSortAndShrink(); + if (!m_Database.Check()) + res = S_FALSE; + } + } + catch(...) + { + res = S_FALSE; + } + if (res != S_OK) + { + Close(); + return res; + } + COM_TRY_END + return S_OK; +} + +STDMETHODIMP CHandler::Close() +{ + m_Database.Clear(); + return S_OK; +} + +class CFolderOutStream: + public ISequentialOutStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +private: + const CMvDatabaseEx *m_Database; + const CRecordVector<bool> *m_ExtractStatuses; + + Byte *TempBuf; + UInt32 TempBufSize; + int NumIdenticalFiles; + bool TempBufMode; + UInt32 m_BufStartFolderOffset; + + int m_StartIndex; + int m_CurrentIndex; + CMyComPtr<IArchiveExtractCallback> m_ExtractCallback; + bool m_TestMode; + + CMyComPtr<ISequentialOutStream> m_RealOutStream; + + bool m_IsOk; + bool m_FileIsOpen; + UInt32 m_RemainFileSize; + UInt64 m_FolderSize; + UInt64 m_PosInFolder; + + void FreeTempBuf() + { + ::MyFree(TempBuf); + TempBuf = NULL; + } + + HRESULT OpenFile(); + HRESULT CloseFileWithResOp(Int32 resOp); + HRESULT CloseFile(); + HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK); +public: + HRESULT WriteEmptyFiles(); + + CFolderOutStream(): TempBuf(NULL) {} + ~CFolderOutStream() { FreeTempBuf(); } + void Init( + const CMvDatabaseEx *database, + const CRecordVector<bool> *extractStatuses, + int startIndex, + UInt64 folderSize, + IArchiveExtractCallback *extractCallback, + bool testMode); + HRESULT FlushCorrupted(); + HRESULT Unsupported(); + + UInt64 GetRemain() const { return m_FolderSize - m_PosInFolder; } + UInt64 GetPosInFolder() const { return m_PosInFolder; } +}; + +void CFolderOutStream::Init( + const CMvDatabaseEx *database, + const CRecordVector<bool> *extractStatuses, + int startIndex, + UInt64 folderSize, + IArchiveExtractCallback *extractCallback, + bool testMode) +{ + m_Database = database; + m_ExtractStatuses = extractStatuses; + m_StartIndex = startIndex; + m_FolderSize = folderSize; + + m_ExtractCallback = extractCallback; + m_TestMode = testMode; + + m_CurrentIndex = 0; + m_PosInFolder = 0; + m_FileIsOpen = false; + m_IsOk = true; + TempBufMode = false; + NumIdenticalFiles = 0; +} + +HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp) +{ + m_RealOutStream.Release(); + m_FileIsOpen = false; + NumIdenticalFiles--; + return m_ExtractCallback->SetOperationResult(resOp); +} + +HRESULT CFolderOutStream::CloseFile() +{ + return CloseFileWithResOp(m_IsOk ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError); +} + +HRESULT CFolderOutStream::OpenFile() +{ + if (NumIdenticalFiles == 0) + { + const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; + const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + int numExtractItems = 0; + int curIndex; + for (curIndex = m_CurrentIndex; curIndex < m_ExtractStatuses->Size(); curIndex++) + { + const CMvItem &mvItem2 = m_Database->Items[m_StartIndex + curIndex]; + const CItem &item2 = m_Database->Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex]; + if (item.Offset != item2.Offset || + item.Size != item2.Size || + item.Size == 0) + break; + 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) + { + FreeTempBuf(); + TempBuf = (Byte *)MyAlloc(item.Size); + TempBufSize = item.Size; + if (TempBuf == NULL) + return E_OUTOFMEMORY; + } + TempBufMode = true; + m_BufStartFolderOffset = item.Offset; + } + else if (numExtractItems == 1) + { + while (NumIdenticalFiles && !(*m_ExtractStatuses)[m_CurrentIndex]) + { + CMyComPtr<ISequentialOutStream> stream; + RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &stream, NExtract::NAskMode::kSkip)); + if (stream) + return E_FAIL; + RINOK(m_ExtractCallback->PrepareOperation(NExtract::NAskMode::kSkip)); + m_CurrentIndex++; + m_FileIsOpen = true; + CloseFile(); + } + } + } + + Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract) : + NExtract::NAskMode::kSkip; + RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode)); + if (!m_RealOutStream && !m_TestMode) + askMode = NExtract::NAskMode::kSkip; + return m_ExtractCallback->PrepareOperation(askMode); +} + +HRESULT CFolderOutStream::WriteEmptyFiles() +{ + if (m_FileIsOpen) + return S_OK; + for (; m_CurrentIndex < m_ExtractStatuses->Size(); m_CurrentIndex++) + { + const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; + const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + UInt64 fileSize = item.Size; + if (fileSize != 0) + return S_OK; + HRESULT result = OpenFile(); + m_RealOutStream.Release(); + RINOK(result); + RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + } + return S_OK; +} + +// This is Write function +HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK) +{ + COM_TRY_BEGIN + UInt32 realProcessed = 0; + if (processedSize != NULL) + *processedSize = 0; + while (size != 0) + { + if (m_FileIsOpen) + { + UInt32 numBytesToWrite = MyMin(m_RemainFileSize, size); + HRESULT res = S_OK; + if (numBytesToWrite > 0) + { + if (!isOK) + m_IsOk = false; + if (m_RealOutStream) + { + UInt32 processedSizeLocal = 0; + res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal); + numBytesToWrite = processedSizeLocal; + } + if (TempBufMode && TempBuf) + memcpy(TempBuf + (m_PosInFolder - m_BufStartFolderOffset), data, numBytesToWrite); + } + realProcessed += numBytesToWrite; + if (processedSize != NULL) + *processedSize = realProcessed; + data = (const void *)((const Byte *)data + numBytesToWrite); + size -= numBytesToWrite; + m_RemainFileSize -= numBytesToWrite; + m_PosInFolder += numBytesToWrite; + if (res != S_OK) + return res; + if (m_RemainFileSize == 0) + { + RINOK(CloseFile()); + + while (NumIdenticalFiles) + { + HRESULT result = OpenFile(); + m_FileIsOpen = true; + m_CurrentIndex++; + if (result == S_OK && m_RealOutStream && TempBuf) + result = WriteStream(m_RealOutStream, TempBuf, (size_t)(m_PosInFolder - m_BufStartFolderOffset)); + + if (!TempBuf && TempBufMode && m_RealOutStream) + { + RINOK(CloseFileWithResOp(NExtract::NOperationResult::kUnSupportedMethod)); + } + else + { + RINOK(CloseFile()); + } + RINOK(result); + } + TempBufMode = false; + } + if (realProcessed > 0) + break; // with this break this function works as Write-Part + } + else + { + if (m_CurrentIndex >= m_ExtractStatuses->Size()) + return E_FAIL; + + const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; + const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + + m_RemainFileSize = item.Size; + + UInt32 fileOffset = item.Offset; + if (fileOffset < m_PosInFolder) + return E_FAIL; + if (fileOffset > m_PosInFolder) + { + UInt32 numBytesToWrite = MyMin(fileOffset - (UInt32)m_PosInFolder, size); + realProcessed += numBytesToWrite; + if (processedSize != NULL) + *processedSize = realProcessed; + data = (const void *)((const Byte *)data + numBytesToWrite); + size -= numBytesToWrite; + m_PosInFolder += numBytesToWrite; + } + if (fileOffset == m_PosInFolder) + { + RINOK(OpenFile()); + m_FileIsOpen = true; + m_CurrentIndex++; + m_IsOk = true; + } + } + } + return WriteEmptyFiles(); + COM_TRY_END +} + +STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + return Write2(data, size, processedSize, true); +} + +HRESULT CFolderOutStream::FlushCorrupted() +{ + const UInt32 kBufferSize = (1 << 10); + Byte buffer[kBufferSize]; + for (int i = 0; i < kBufferSize; i++) + buffer[i] = 0; + for (;;) + { + UInt64 remain = GetRemain(); + if (remain == 0) + return S_OK; + UInt32 size = (UInt32)MyMin(remain, (UInt64)kBufferSize); + UInt32 processedSizeLocal = 0; + RINOK(Write2(buffer, size, &processedSizeLocal, false)); + } +} + +HRESULT CFolderOutStream::Unsupported() +{ + while(m_CurrentIndex < m_ExtractStatuses->Size()) + { + HRESULT result = OpenFile(); + if (result != S_FALSE && result != S_OK) + return result; + m_RealOutStream.Release(); + RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + m_CurrentIndex++; + } + return S_OK; +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testModeSpec, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)-1); + if (allFilesMode) + numItems = m_Database.Items.Size(); + if(numItems == 0) + return S_OK; + bool testMode = (testModeSpec != 0); + UInt64 totalUnPacked = 0; + + UInt32 i; + int lastFolder = -2; + UInt64 lastFolderSize = 0; + for(i = 0; i < numItems; i++) + { + int 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()) + continue; + int folderIndex = m_Database.GetFolderIndex(&mvItem); + if (folderIndex != lastFolder) + totalUnPacked += lastFolderSize; + lastFolder = folderIndex; + lastFolderSize = item.GetEndOffset(); + } + totalUnPacked += lastFolderSize; + + extractCallback->SetTotal(totalUnPacked); + + totalUnPacked = 0; + + UInt64 totalPacked = 0; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + NCompress::NDeflate::NDecoder::CCOMCoder *deflateDecoderSpec = NULL; + CMyComPtr<ICompressCoder> deflateDecoder; + + NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL; + CMyComPtr<ICompressCoder> lzxDecoder; + + NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL; + CMyComPtr<ICompressCoder> quantumDecoder; + + CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream(); + CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec; + if (!cabBlockInStreamSpec->Create()) + return E_OUTOFMEMORY; + + CRecordVector<bool> extractStatuses; + for(i = 0; i < numItems;) + { + int index = allFilesMode ? i : indices[i]; + + const CMvItem &mvItem = m_Database.Items[index]; + const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; + int itemIndex = mvItem.ItemIndex; + const CItem &item = db.Items[itemIndex]; + + i++; + if (item.IsDir()) + { + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + CMyComPtr<ISequentialOutStream> realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + RINOK(extractCallback->PrepareOperation(askMode)); + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + int folderIndex = m_Database.GetFolderIndex(&mvItem); + if (folderIndex < 0) + { + // If we need previous archive + Int32 askMode= testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + CMyComPtr<ISequentialOutStream> realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + RINOK(extractCallback->PrepareOperation(askMode)); + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError)); + continue; + } + int startIndex2 = m_Database.FolderStartFileIndex[folderIndex]; + int 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]; + const CMvItem &mvItem = m_Database.Items[indexNext]; + const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + if (item.IsDir()) + continue; + int newFolderIndex = m_Database.GetFolderIndex(&mvItem); + + if (newFolderIndex != folderIndex) + break; + for (; startIndex < indexNext; startIndex++) + extractStatuses.Add(false); + extractStatuses.Add(true); + startIndex++; + curUnpack = item.GetEndOffset(); + } + + lps->OutSize = totalUnPacked; + lps->InSize = totalPacked; + RINOK(lps->SetCur()); + + CFolderOutStream *cabFolderOutStream = new CFolderOutStream; + CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream); + + const CFolder &folder = db.Folders[item.GetFolderIndex(db.Folders.Size())]; + + cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2, + curUnpack, extractCallback, testMode); + + cabBlockInStreamSpec->MsZip = false; + switch(folder.GetCompressionMethod()) + { + case NHeader::NCompressionMethodMajor::kNone: + break; + case NHeader::NCompressionMethodMajor::kMSZip: + if(deflateDecoderSpec == NULL) + { + deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder; + deflateDecoder = deflateDecoderSpec; + } + cabBlockInStreamSpec->MsZip = true; + break; + case NHeader::NCompressionMethodMajor::kLZX: + if(lzxDecoderSpec == NULL) + { + lzxDecoderSpec = new NCompress::NLzx::CDecoder; + lzxDecoder = lzxDecoderSpec; + } + RINOK(lzxDecoderSpec->SetParams(folder.CompressionTypeMinor)); + break; + case NHeader::NCompressionMethodMajor::kQuantum: + if(quantumDecoderSpec == NULL) + { + quantumDecoderSpec = new NCompress::NQuantum::CDecoder; + quantumDecoder = quantumDecoderSpec; + } + quantumDecoderSpec->SetParams(folder.CompressionTypeMinor); + break; + default: + { + RINOK(cabFolderOutStream->Unsupported()); + totalUnPacked += curUnpack; + continue; + } + } + + cabBlockInStreamSpec->InitForNewFolder(); + + HRESULT res = S_OK; + + { + int volIndex = mvItem.VolumeIndex; + int locFolderIndex = item.GetFolderIndex(db.Folders.Size()); + bool keepHistory = false; + bool keepInputBuffer = false; + for (UInt32 f = 0; cabFolderOutStream->GetRemain() != 0;) + { + if (volIndex >= m_Database.Volumes.Size()) + { + res = S_FALSE; + break; + } + + const CDatabaseEx &db = m_Database.Volumes[volIndex]; + const CFolder &folder = db.Folders[locFolderIndex]; + if (f == 0) + { + cabBlockInStreamSpec->SetStream(db.Stream); + cabBlockInStreamSpec->ReservedSize = db.ArchiveInfo.GetDataBlockReserveSize(); + RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL)); + } + if (f == folder.NumDataBlocks) + { + volIndex++; + locFolderIndex = 0; + f = 0; + continue; + } + f++; + + cabBlockInStreamSpec->DataError = false; + + if (!keepInputBuffer) + cabBlockInStreamSpec->InitForNewBlock(); + + UInt32 packSize, unpackSize; + res = cabBlockInStreamSpec->PreRead(packSize, unpackSize); + if (res == S_FALSE) + break; + RINOK(res); + keepInputBuffer = (unpackSize == 0); + if (keepInputBuffer) + continue; + + UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFolder(); + totalPacked += packSize; + + lps->OutSize = totalUnPacked2; + lps->InSize = totalPacked; + RINOK(lps->SetCur()); + + UInt64 unpackRemain = cabFolderOutStream->GetRemain(); + + const UInt32 kBlockSizeMax = (1 << 15); + if (unpackRemain > kBlockSizeMax) + unpackRemain = kBlockSizeMax; + if (unpackRemain > unpackSize) + unpackRemain = unpackSize; + + switch(folder.GetCompressionMethod()) + { + case NHeader::NCompressionMethodMajor::kNone: + res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + break; + case NHeader::NCompressionMethodMajor::kMSZip: + deflateDecoderSpec->SetKeepHistory(keepHistory); + res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + break; + case NHeader::NCompressionMethodMajor::kLZX: + lzxDecoderSpec->SetKeepHistory(keepHistory); + res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + break; + case NHeader::NCompressionMethodMajor::kQuantum: + quantumDecoderSpec->SetKeepHistory(keepHistory); + 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()); + } + } + if (res != S_OK || cabFolderOutStream->GetRemain() != 0) + { + RINOK(cabFolderOutStream->FlushCorrupted()); + } + totalUnPacked += curUnpack; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = m_Database.Items.Size(); + return S_OK; +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.h new file mode 100644 index 000000000..1edcd11e2 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHandler.h @@ -0,0 +1,28 @@ +// CabHandler.h + +#ifndef __CAB_HANDLER_H +#define __CAB_HANDLER_H + +#include "Common/MyCom.h" +#include "../IArchive.h" +#include "CabIn.h" + +namespace NArchive { +namespace NCab { + +class CHandler: + public IInArchive, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP1(IInArchive) + + INTERFACE_IInArchive(;) + +private: + CMvDatabaseEx m_Database; +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.cpp new file mode 100644 index 000000000..0cba1b0b7 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.cpp @@ -0,0 +1,15 @@ +// CabHeader.cpp + +#include "StdAfx.h" + +#include "CabHeader.h" + +namespace NArchive { +namespace NCab { +namespace NHeader { + +Byte kMarker[kMarkerSize] = {'M', 'S', 'C', 'F', 0, 0, 0, 0 }; + +// struct CSignatureInitializer { CSignatureInitializer() { kMarker[0]--; }; } g_SignatureInitializer; + +}}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.h b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.h new file mode 100644 index 000000000..0f0d2af35 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabHeader.h @@ -0,0 +1,44 @@ +// Archive/Cab/Header.h + +#ifndef __ARCHIVE_CAB_HEADER_H +#define __ARCHIVE_CAB_HEADER_H + +#include "Common/Types.h" + +namespace NArchive { +namespace NCab { +namespace NHeader { + +const unsigned kMarkerSize = 8; +extern Byte kMarker[kMarkerSize]; + +namespace NArchive +{ + namespace NFlags + { + const int kPrevCabinet = 0x0001; + const int kNextCabinet = 0x0002; + const int kReservePresent = 0x0004; + } +} + +namespace NCompressionMethodMajor +{ + const Byte kNone = 0; + const Byte kMSZip = 1; + const Byte kQuantum = 2; + const Byte kLZX = 3; +} + +const int kFileNameIsUTFAttributeMask = 0x80; + +namespace NFolderIndex +{ + const int kContinuedFromPrev = 0xFFFD; + const int kContinuedToNext = 0xFFFE; + const int kContinuedPrevAndNext = 0xFFFF; +} + +}}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.cpp new file mode 100644 index 000000000..c0bffa2d2 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.cpp @@ -0,0 +1,272 @@ +// Archive/CabIn.cpp + +#include "StdAfx.h" + +#include "../Common/FindSignature.h" + +#include "CabIn.h" + +namespace NArchive { +namespace NCab { + +Byte CInArchive::Read8() +{ + Byte b; + if (!inBuffer.ReadByte(b)) + throw CInArchiveException(CInArchiveException::kUnsupported); + return b; +} + +UInt16 CInArchive::Read16() +{ + UInt16 value = 0; + for (int i = 0; i < 2; i++) + { + Byte b = Read8(); + value |= (UInt16(b) << (8 * i)); + } + return value; +} + +UInt32 CInArchive::Read32() +{ + UInt32 value = 0; + for (int i = 0; i < 4; i++) + { + Byte b = Read8(); + value |= (UInt32(b) << (8 * i)); + } + return value; +} + +AString CInArchive::SafeReadName() +{ + AString name; + for (;;) + { + Byte b = Read8(); + if (b == 0) + return name; + name += (char)b; + } +} + +void CInArchive::ReadOtherArchive(COtherArchive &oa) +{ + oa.FileName = SafeReadName(); + oa.DiskName = SafeReadName(); +} + +void CInArchive::Skip(UInt32 size) +{ + while (size-- != 0) + Read8(); +} + +HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db) +{ + IInStream *stream = db.Stream; + db.Clear(); + RINOK(stream->Seek(0, STREAM_SEEK_SET, &db.StartPosition)); + + RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize, + searchHeaderSizeLimit, db.StartPosition)); + + RINOK(stream->Seek(db.StartPosition + NHeader::kMarkerSize, STREAM_SEEK_SET, NULL)); + if (!inBuffer.Create(1 << 17)) + return E_OUTOFMEMORY; + inBuffer.SetStream(stream); + inBuffer.Init(); + + CInArchiveInfo &ai = db.ArchiveInfo; + + ai.Size = Read32(); + if (Read32() != 0) + return S_FALSE; + ai.FileHeadersOffset = Read32(); + if (Read32() != 0) + return S_FALSE; + + ai.VersionMinor = Read8(); + ai.VersionMajor = Read8(); + ai.NumFolders = Read16(); + ai.NumFiles = Read16(); + ai.Flags = Read16(); + if (ai.Flags > 7) + return S_FALSE; + ai.SetID = Read16(); + ai.CabinetNumber = Read16(); + + if (ai.ReserveBlockPresent()) + { + ai.PerCabinetAreaSize = Read16(); + ai.PerFolderAreaSize = Read8(); + ai.PerDataBlockAreaSize = Read8(); + + Skip(ai.PerCabinetAreaSize); + } + + { + if (ai.IsTherePrev()) + ReadOtherArchive(ai.PrevArc); + if (ai.IsThereNext()) + ReadOtherArchive(ai.NextArc); + } + + int i; + for (i = 0; i < ai.NumFolders; i++) + { + CFolder folder; + + folder.DataStart = Read32(); + folder.NumDataBlocks = Read16(); + folder.CompressionTypeMajor = Read8(); + folder.CompressionTypeMinor = Read8(); + + Skip(ai.PerFolderAreaSize); + db.Folders.Add(folder); + } + + RINOK(stream->Seek(db.StartPosition + ai.FileHeadersOffset, STREAM_SEEK_SET, NULL)); + + inBuffer.SetStream(stream); + inBuffer.Init(); + for (i = 0; i < ai.NumFiles; i++) + { + CItem item; + item.Size = Read32(); + item.Offset = Read32(); + item.FolderIndex = Read16(); + UInt16 pureDate = Read16(); + UInt16 pureTime = Read16(); + item.Time = ((UInt32(pureDate) << 16)) | pureTime; + item.Attributes = Read16(); + item.Name = SafeReadName(); + int folderIndex = item.GetFolderIndex(db.Folders.Size()); + if (folderIndex >= db.Folders.Size()) + return S_FALSE; + db.Items.Add(item); + } + return S_OK; +} + +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + +static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param) +{ + const CMvDatabaseEx &mvDb = *(const CMvDatabaseEx *)param; + const CDatabaseEx &db1 = mvDb.Volumes[p1->VolumeIndex]; + const CDatabaseEx &db2 = mvDb.Volumes[p2->VolumeIndex]; + const CItem &item1 = db1.Items[p1->ItemIndex]; + const CItem &item2 = db2.Items[p2->ItemIndex];; + bool isDir1 = item1.IsDir(); + bool isDir2 = item2.IsDir(); + if (isDir1 && !isDir2) + return -1; + if (isDir2 && !isDir1) + return 1; + int f1 = mvDb.GetFolderIndex(p1); + int f2 = mvDb.GetFolderIndex(p2); + RINOZ(MyCompare(f1, f2)); + RINOZ(MyCompare(item1.Offset, item2.Offset)); + RINOZ(MyCompare(item1.Size, item2.Size)); + RINOZ(MyCompare(p1->VolumeIndex, p2->VolumeIndex)); + return MyCompare(p1->ItemIndex, p2->ItemIndex); +} + +bool CMvDatabaseEx::AreItemsEqual(int i1, int i2) +{ + const CMvItem *p1 = &Items[i1]; + const CMvItem *p2 = &Items[i2]; + const CDatabaseEx &db1 = Volumes[p1->VolumeIndex]; + const CDatabaseEx &db2 = Volumes[p2->VolumeIndex]; + const CItem &item1 = db1.Items[p1->ItemIndex]; + const CItem &item2 = db2.Items[p2->ItemIndex];; + return GetFolderIndex(p1) == GetFolderIndex(p2) && + item1.Offset == item2.Offset && + item1.Size == item2.Size && + item1.Name == item2.Name; +} + +void CMvDatabaseEx::FillSortAndShrink() +{ + Items.Clear(); + StartFolderOfVol.Clear(); + FolderStartFileIndex.Clear(); + int offset = 0; + for (int v = 0; v < Volumes.Size(); v++) + { + const CDatabaseEx &db = Volumes[v]; + int curOffset = offset; + if (db.IsTherePrevFolder()) + curOffset--; + StartFolderOfVol.Add(curOffset); + offset += db.GetNumberOfNewFolders(); + + CMvItem mvItem; + mvItem.VolumeIndex = v; + for (int i = 0 ; i < db.Items.Size(); i++) + { + mvItem.ItemIndex = i; + Items.Add(mvItem); + } + } + + Items.Sort(CompareMvItems, (void *)this); + int j = 1; + int i; + for (i = 1; i < Items.Size(); i++) + if (!AreItemsEqual(i, i -1)) + Items[j++] = Items[i]; + Items.DeleteFrom(j); + + for (i = 0; i < Items.Size(); i++) + { + int folderIndex = GetFolderIndex(&Items[i]); + if (folderIndex >= FolderStartFileIndex.Size()) + FolderStartFileIndex.Add(i); + } +} + +bool CMvDatabaseEx::Check() +{ + for (int v = 1; v < Volumes.Size(); v++) + { + const CDatabaseEx &db1 = Volumes[v]; + if (db1.IsTherePrevFolder()) + { + const CDatabaseEx &db0 = Volumes[v - 1]; + if (db0.Folders.IsEmpty() || db1.Folders.IsEmpty()) + return false; + const CFolder &f0 = db0.Folders.Back(); + const CFolder &f1 = db1.Folders.Front(); + if (f0.CompressionTypeMajor != f1.CompressionTypeMajor || + f0.CompressionTypeMinor != f1.CompressionTypeMinor) + return false; + } + } + UInt32 beginPos = 0; + UInt64 endPos = 0; + int prevFolder = -2; + for (int i = 0; i < Items.Size(); i++) + { + const CMvItem &mvItem = Items[i]; + int fIndex = GetFolderIndex(&mvItem); + if (fIndex >= FolderStartFileIndex.Size()) + return false; + const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + if (item.IsDir()) + continue; + int folderIndex = GetFolderIndex(&mvItem); + if (folderIndex != prevFolder) + prevFolder = folderIndex; + else if (item.Offset < endPos && + (item.Offset != beginPos || item.GetEndOffset() != endPos)) + return false; + beginPos = item.Offset; + endPos = item.GetEndOffset(); + } + return true; +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.h new file mode 100644 index 000000000..1e9b188b5 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.h @@ -0,0 +1,161 @@ +// Archive/CabIn.h + +#ifndef __ARCHIVE_CAB_IN_H +#define __ARCHIVE_CAB_IN_H + +#include "../../IStream.h" +#include "../../Common/InBuffer.h" +#include "CabHeader.h" +#include "CabItem.h" + +namespace NArchive { +namespace NCab { + +class CInArchiveException +{ +public: + enum CCauseType + { + kUnexpectedEndOfArchive = 0, + kIncorrectArchive, + kUnsupported + } Cause; + CInArchiveException(CCauseType cause) : Cause(cause) {} +}; + +struct COtherArchive +{ + AString FileName; + AString DiskName; +}; + +struct CArchiveInfo +{ + Byte VersionMinor; /* cabinet file format version, minor */ + Byte VersionMajor; /* cabinet file format version, major */ + UInt16 NumFolders; /* number of CFFOLDER entries in this cabinet */ + UInt16 NumFiles; /* number of CFFILE entries in this cabinet */ + UInt16 Flags; /* cabinet file option indicators */ + UInt16 SetID; /* must be the same for all cabinets in a set */ + UInt16 CabinetNumber; /* number of this cabinet file in a set */ + + bool ReserveBlockPresent() const { return (Flags & NHeader::NArchive::NFlags::kReservePresent) != 0; } + + bool IsTherePrev() const { return (Flags & NHeader::NArchive::NFlags::kPrevCabinet) != 0; } + bool IsThereNext() const { return (Flags & NHeader::NArchive::NFlags::kNextCabinet) != 0; } + + UInt16 PerCabinetAreaSize; // (optional) size of per-cabinet reserved area + Byte PerFolderAreaSize; // (optional) size of per-folder reserved area + Byte PerDataBlockAreaSize; // (optional) size of per-datablock reserved area + + Byte GetDataBlockReserveSize() const { return (Byte)(ReserveBlockPresent() ? PerDataBlockAreaSize : 0); } + + COtherArchive PrevArc; + COtherArchive NextArc; + + CArchiveInfo() + { + Clear(); + } + + void Clear() + { + PerCabinetAreaSize = 0; + PerFolderAreaSize = 0; + PerDataBlockAreaSize = 0; + } +}; + +struct CInArchiveInfo: public CArchiveInfo +{ + UInt32 Size; /* size of this cabinet file in bytes */ + UInt32 FileHeadersOffset; // offset of the first CFFILE entry +}; + + +struct CDatabase +{ + UInt64 StartPosition; + CInArchiveInfo ArchiveInfo; + CObjectVector<CFolder> Folders; + CObjectVector<CItem> Items; + + void Clear() + { + ArchiveInfo.Clear(); + Folders.Clear(); + Items.Clear(); + } + bool IsTherePrevFolder() const + { + for (int i = 0; i < Items.Size(); i++) + if (Items[i].ContinuedFromPrev()) + return true; + return false; + } + int GetNumberOfNewFolders() const + { + int res = Folders.Size(); + if (IsTherePrevFolder()) + res--; + return res; + } + UInt32 GetFileOffset(int index) const { return Items[index].Offset; } + UInt32 GetFileSize(int index) const { return Items[index].Size; } +}; + +struct CDatabaseEx: public CDatabase +{ + CMyComPtr<IInStream> Stream; +}; + +struct CMvItem +{ + int VolumeIndex; + int ItemIndex; +}; + +class CMvDatabaseEx +{ + bool AreItemsEqual(int i1, int i2); +public: + CObjectVector<CDatabaseEx> Volumes; + CRecordVector<CMvItem> Items; + CRecordVector<int> StartFolderOfVol; + CRecordVector<int> FolderStartFileIndex; + + int GetFolderIndex(const CMvItem *mvi) const + { + const CDatabaseEx &db = Volumes[mvi->VolumeIndex]; + return StartFolderOfVol[mvi->VolumeIndex] + + db.Items[mvi->ItemIndex].GetFolderIndex(db.Folders.Size()); + } + void Clear() + { + Volumes.Clear(); + Items.Clear(); + StartFolderOfVol.Clear(); + FolderStartFileIndex.Clear(); + } + void FillSortAndShrink(); + bool Check(); +}; + +class CInArchive +{ + CInBuffer inBuffer; + + Byte Read8(); + UInt16 Read16(); + UInt32 Read32(); + AString SafeReadName(); + void Skip(UInt32 size); + void ReadOtherArchive(COtherArchive &oa); + +public: + HRESULT Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db); +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabItem.h b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabItem.h new file mode 100644 index 000000000..63a1e856c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabItem.h @@ -0,0 +1,63 @@ +// Archive/CabItem.h + +#ifndef __ARCHIVE_CAB_ITEM_H +#define __ARCHIVE_CAB_ITEM_H + +#include "Common/Types.h" +#include "Common/MyString.h" +#include "CabHeader.h" + +namespace NArchive { +namespace NCab { + +struct CFolder +{ + UInt32 DataStart; // offset of the first CFDATA block in this folder + UInt16 NumDataBlocks; // number of CFDATA blocks in this folder + Byte CompressionTypeMajor; + Byte CompressionTypeMinor; + Byte GetCompressionMethod() const { return (Byte)(CompressionTypeMajor & 0xF); } +}; + +struct CItem +{ + AString Name; + UInt32 Offset; + UInt32 Size; + UInt32 Time; + UInt16 FolderIndex; + UInt16 Flags; + UInt16 Attributes; + + UInt64 GetEndOffset() const { return (UInt64)Offset + Size; } + UInt32 GetWinAttributes() const { return (Attributes & ~NHeader::kFileNameIsUTFAttributeMask); } + bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUTFAttributeMask) != 0; } + bool IsDir() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } + + bool ContinuedFromPrev() const + { + return + (FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev) || + (FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext); + } + + bool ContinuedToNext() const + { + return + (FolderIndex == NHeader::NFolderIndex::kContinuedToNext) || + (FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext); + } + + int GetFolderIndex(int numFolders) const + { + if (ContinuedFromPrev()) + return 0; + if (ContinuedToNext()) + return (numFolders - 1); + return FolderIndex; + } +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabRegister.cpp new file mode 100644 index 000000000..15fe4099f --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabRegister.cpp @@ -0,0 +1,13 @@ +// CabRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "CabHandler.h" +static IInArchive *CreateArc() { return new NArchive::NCab::CHandler; } + +static CArcInfo g_ArcInfo = + { L"Cab", L"cab", 0, 8, { 0x4D, 0x53, 0x43, 0x46 }, 4, false, CreateArc, 0 }; + +REGISTER_ARC(Cab) diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Cab/StdAfx.h new file mode 100644 index 000000000..e7fb6986d --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/StdAfx.h @@ -0,0 +1,8 @@ +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/MyWindows.h" + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.cpp new file mode 100644 index 000000000..a9e334b03 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.cpp @@ -0,0 +1,721 @@ +// ChmHandler.cpp + +#include "StdAfx.h" + +#include "Common/ComTry.h" +#include "Common/Defs.h" +#include "Common/StringConvert.h" +#include "Common/UTFConvert.h" + +#include "Windows/PropVariant.h" +#include "Windows/Time.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/CopyCoder.h" +#include "../../Compress/LzxDecoder.h" + +#include "../Common/ItemNameUtils.h" + +#include "ChmHandler.h" + +using namespace NWindows; +using namespace NTime; + +namespace NArchive { +namespace NChm { + +// #define _CHM_DETAILS + +#ifdef _CHM_DETAILS + +enum +{ + kpidSection = kpidUserDefined +}; + +#endif + +STATPROPSTG kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidBlock, VT_UI4} + + #ifdef _CHM_DETAILS + , + { L"Section", kpidSection, VT_UI4}, + { NULL, kpidOffset, VT_UI4} + #endif +}; + +STATPROPSTG kArcProps[] = +{ + { NULL, kpidNumBlocks, VT_UI8} +}; + +IMP_IInArchive_Props + +IMP_IInArchive_ArcProps_NO +/* +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch(propID) + { + case kpidNumBlocks: + { + UInt64 numBlocks = 0; + for (int i = 0; i < m_Database.Sections.Size(); i++) + { + const CSectionInfo &s = m_Database.Sections[i]; + for (int j = 0; j < s.Methods.Size(); j++) + { + const CMethodInfo &m = s.Methods[j]; + if (m.IsLzx()) + numBlocks += m.LzxInfo.ResetTable.GetNumBlocks(); + } + } + prop = numBlocks; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} +*/ + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + if (m_Database.NewFormat) + { + switch(propID) + { + case kpidSize: + prop = (UInt64)m_Database.NewFormatString.Length(); + break; + } + prop.Detach(value); + return S_OK; + } + int entryIndex; + if (m_Database.LowLevel) + entryIndex = index; + else + entryIndex = m_Database.Indices[index]; + const CItem &item = m_Database.Items[entryIndex]; + switch(propID) + { + case kpidPath: + { + UString us; + if (ConvertUTF8ToUnicode(item.Name, us)) + { + if (!m_Database.LowLevel) + { + if (us.Length() > 1) + if (us[0] == L'/') + us.Delete(0); + } + prop = NItemName::GetOSName2(us); + } + break; + } + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: prop = item.Size; break; + case kpidMethod: + { + if (!item.IsDir()) + if (item.Section == 0) + prop = L"Copy"; + else if (item.Section < m_Database.Sections.Size()) + prop = m_Database.Sections[(int)item.Section].GetMethodName(); + break; + } + case kpidBlock: + if (m_Database.LowLevel) + prop = item.Section; + else if (item.Section != 0) + prop = m_Database.GetFolder(index); + break; + + #ifdef _CHM_DETAILS + + case kpidSection: prop = (UInt32)item.Section; break; + case kpidOffset: prop = (UInt32)item.Offset; break; + + #endif + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +class CProgressImp: public CProgressVirt +{ + CMyComPtr<IArchiveOpenCallback> _callback; +public: + STDMETHOD(SetTotal)(const UInt64 *numFiles); + STDMETHOD(SetCompleted)(const UInt64 *numFiles); + CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {}; +}; + +STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles) +{ + if (_callback) + return _callback->SetCompleted(numFiles, NULL); + return S_OK; +} + +STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles) +{ + if (_callback) + return _callback->SetCompleted(numFiles, NULL); + return S_OK; +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + m_Stream.Release(); + try + { + CInArchive archive; + // CProgressImp progressImp(openArchiveCallback); + RINOK(archive.Open(inStream, maxCheckStartPosition, m_Database)); + /* + if (m_Database.LowLevel) + return S_FALSE; + */ + m_Stream = inStream; + } + catch(...) + { + return S_FALSE; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + m_Database.Clear(); + m_Stream.Release(); + return S_OK; +} + +class CChmFolderOutStream: + public ISequentialOutStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP + + HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK); + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + + UInt64 m_FolderSize; + UInt64 m_PosInFolder; + UInt64 m_PosInSection; + const CRecordVector<bool> *m_ExtractStatuses; + int m_StartIndex; + int m_CurrentIndex; + int m_NumFiles; + +private: + const CFilesDatabase *m_Database; + CMyComPtr<IArchiveExtractCallback> m_ExtractCallback; + bool m_TestMode; + + bool m_IsOk; + bool m_FileIsOpen; + UInt64 m_RemainFileSize; + CMyComPtr<ISequentialOutStream> m_RealOutStream; + + HRESULT OpenFile(); + HRESULT WriteEmptyFiles(); +public: + void Init( + const CFilesDatabase *database, + IArchiveExtractCallback *extractCallback, + bool testMode); + HRESULT FlushCorrupted(UInt64 maxSize); +}; + +void CChmFolderOutStream::Init( + const CFilesDatabase *database, + IArchiveExtractCallback *extractCallback, + bool testMode) +{ + m_Database = database; + m_ExtractCallback = extractCallback; + m_TestMode = testMode; + + m_CurrentIndex = 0; + m_FileIsOpen = false; +} + +HRESULT CChmFolderOutStream::OpenFile() +{ + Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract) : + NExtract::NAskMode::kSkip; + m_RealOutStream.Release(); + RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode)); + if (!m_RealOutStream && !m_TestMode) + askMode = NExtract::NAskMode::kSkip; + return m_ExtractCallback->PrepareOperation(askMode); +} + +HRESULT CChmFolderOutStream::WriteEmptyFiles() +{ + if (m_FileIsOpen) + return S_OK; + for (;m_CurrentIndex < m_NumFiles; m_CurrentIndex++) + { + UInt64 fileSize = m_Database->GetFileSize(m_StartIndex + m_CurrentIndex); + if (fileSize != 0) + return S_OK; + HRESULT result = OpenFile(); + m_RealOutStream.Release(); + RINOK(result); + RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + } + return S_OK; +} + +// This is WritePart function +HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK) +{ + UInt32 realProcessed = 0; + if (processedSize != NULL) + *processedSize = 0; + while(size != 0) + { + if (m_FileIsOpen) + { + UInt32 numBytesToWrite = (UInt32)MyMin(m_RemainFileSize, (UInt64)(size)); + HRESULT res = S_OK; + if (numBytesToWrite > 0) + { + if (!isOK) + m_IsOk = false; + if (m_RealOutStream) + { + UInt32 processedSizeLocal = 0; + res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal); + numBytesToWrite = processedSizeLocal; + } + } + realProcessed += numBytesToWrite; + if (processedSize != NULL) + *processedSize = realProcessed; + data = (const void *)((const Byte *)data + numBytesToWrite); + size -= numBytesToWrite; + m_RemainFileSize -= numBytesToWrite; + m_PosInSection += numBytesToWrite; + m_PosInFolder += numBytesToWrite; + if (res != S_OK) + return res; + if (m_RemainFileSize == 0) + { + m_RealOutStream.Release(); + RINOK(m_ExtractCallback->SetOperationResult( + m_IsOk ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError)); + m_FileIsOpen = false; + } + if (realProcessed > 0) + break; // with this break this function works as write part + } + else + { + if (m_CurrentIndex >= m_NumFiles) + return E_FAIL; + int fullIndex = m_StartIndex + m_CurrentIndex; + m_RemainFileSize = m_Database->GetFileSize(fullIndex); + UInt64 fileOffset = m_Database->GetFileOffset(fullIndex); + if (fileOffset < m_PosInSection) + return E_FAIL; + if (fileOffset > m_PosInSection) + { + UInt32 numBytesToWrite = (UInt32)MyMin(fileOffset - m_PosInSection, UInt64(size)); + realProcessed += numBytesToWrite; + if (processedSize != NULL) + *processedSize = realProcessed; + data = (const void *)((const Byte *)data + numBytesToWrite); + size -= numBytesToWrite; + m_PosInSection += numBytesToWrite; + m_PosInFolder += numBytesToWrite; + } + if (fileOffset == m_PosInSection) + { + RINOK(OpenFile()); + m_FileIsOpen = true; + m_CurrentIndex++; + m_IsOk = true; + } + } + } + return WriteEmptyFiles(); +} + +STDMETHODIMP CChmFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + return Write2(data, size, processedSize, true); +} + +HRESULT CChmFolderOutStream::FlushCorrupted(UInt64 maxSize) +{ + const UInt32 kBufferSize = (1 << 10); + Byte buffer[kBufferSize]; + for (int i = 0; i < kBufferSize; i++) + buffer[i] = 0; + if (maxSize > m_FolderSize) + maxSize = m_FolderSize; + while (m_PosInFolder < maxSize) + { + UInt32 size = (UInt32)MyMin(maxSize - m_PosInFolder, (UInt64)kBufferSize); + UInt32 processedSizeLocal = 0; + RINOK(Write2(buffer, size, &processedSizeLocal, false)); + if (processedSizeLocal == 0) + return S_OK; + } + return S_OK; +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testModeSpec, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)-1); + + if (allFilesMode) + numItems = m_Database.NewFormat ? 1: + (m_Database.LowLevel ? + m_Database.Items.Size(): + m_Database.Indices.Size()); + if (numItems == 0) + return S_OK; + bool testMode = (testModeSpec != 0); + + UInt64 currentTotalSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + UInt32 i; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream(streamSpec); + streamSpec->SetStream(m_Stream); + + if (m_Database.LowLevel) + { + UInt64 currentItemSize = 0; + UInt64 totalSize = 0; + if (m_Database.NewFormat) + totalSize = m_Database.NewFormatString.Length(); + else + for (i = 0; i < numItems; i++) + totalSize += m_Database.Items[allFilesMode ? i : indices[i]].Size; + extractCallback->SetTotal(totalSize); + + for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + { + currentItemSize = 0; + lps->InSize = currentTotalSize; // Change it + lps->OutSize = currentTotalSize; + + RINOK(lps->SetCur()); + CMyComPtr<ISequentialOutStream> realOutStream; + Int32 askMode= testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + Int32 index = allFilesMode ? i : indices[i]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + if (m_Database.NewFormat) + { + if (index != 0) + return E_FAIL; + if (!testMode && !realOutStream) + continue; + if (!testMode) + { + UInt32 size = m_Database.NewFormatString.Length(); + RINOK(WriteStream(realOutStream, (const char *)m_Database.NewFormatString, size)); + } + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + const CItem &item = m_Database.Items[index]; + + currentItemSize = item.Size; + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + if (item.Section != 0) + { + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + continue; + } + + if (testMode) + { + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + + RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL)); + streamSpec->Init(item.Size); + + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult((copyCoderSpec->TotalSize == item.Size) ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError)); + } + return S_OK; + } + + UInt64 lastFolderIndex = ((UInt64)0 - 1); + for (i = 0; i < numItems; i++) + { + UInt32 index = allFilesMode ? i : indices[i]; + int entryIndex = m_Database.Indices[index]; + const CItem &item = m_Database.Items[entryIndex]; + UInt64 sectionIndex = item.Section; + if (item.IsDir() || item.Size == 0) + continue; + if (sectionIndex == 0) + { + currentTotalSize += item.Size; + continue; + } + const CSectionInfo §ion = m_Database.Sections[(int)item.Section]; + if (section.IsLzx()) + { + const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo; + UInt64 folderIndex = m_Database.GetFolder(index); + if (lastFolderIndex == folderIndex) + folderIndex++; + lastFolderIndex = m_Database.GetLastFolder(index); + for (; folderIndex <= lastFolderIndex; folderIndex++) + currentTotalSize += lzxInfo.GetFolderSize(); + } + } + + RINOK(extractCallback->SetTotal(currentTotalSize)); + + NCompress::NLzx::CDecoder *lzxDecoderSpec = 0; + CMyComPtr<ICompressCoder> lzxDecoder; + CChmFolderOutStream *chmFolderOutStream = 0; + CMyComPtr<ISequentialOutStream> outStream; + + currentTotalSize = 0; + + CRecordVector<bool> extractStatuses; + for (i = 0; i < numItems;) + { + RINOK(extractCallback->SetCompleted(¤tTotalSize)); + UInt32 index = allFilesMode ? i : indices[i]; + i++; + int entryIndex = m_Database.Indices[index]; + const CItem &item = m_Database.Items[entryIndex]; + UInt64 sectionIndex = item.Section; + Int32 askMode= testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + if (item.IsDir()) + { + CMyComPtr<ISequentialOutStream> realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + RINOK(extractCallback->PrepareOperation(askMode)); + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + + lps->InSize = currentTotalSize; // Change it + lps->OutSize = currentTotalSize; + + if (item.Size == 0 || sectionIndex == 0) + { + CMyComPtr<ISequentialOutStream> realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + Int32 opRes = NExtract::NOperationResult::kOK; + if (!testMode && item.Size != 0) + { + RINOK(m_Stream->Seek(m_Database.ContentOffset + item.Offset, STREAM_SEEK_SET, NULL)); + streamSpec->Init(item.Size); + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize != item.Size) + opRes = NExtract::NOperationResult::kDataError; + } + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(opRes)); + currentTotalSize += item.Size; + continue; + } + + const CSectionInfo §ion = m_Database.Sections[(int)sectionIndex]; + + if (!section.IsLzx()) + { + CMyComPtr<ISequentialOutStream> realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + continue; + } + + const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo; + + if (chmFolderOutStream == 0) + { + chmFolderOutStream = new CChmFolderOutStream; + outStream = chmFolderOutStream; + } + + chmFolderOutStream->Init(&m_Database, extractCallback, testMode); + + if (lzxDecoderSpec == NULL) + { + lzxDecoderSpec = new NCompress::NLzx::CDecoder; + lzxDecoder = lzxDecoderSpec; + } + + UInt64 folderIndex = m_Database.GetFolder(index); + + UInt64 compressedPos = m_Database.ContentOffset + section.Offset; + UInt32 numDictBits = lzxInfo.GetNumDictBits(); + RINOK(lzxDecoderSpec->SetParams(numDictBits)); + + const CItem *lastItem = &item; + extractStatuses.Clear(); + extractStatuses.Add(true); + + for (;; folderIndex++) + { + RINOK(extractCallback->SetCompleted(¤tTotalSize)); + + UInt64 startPos = lzxInfo.GetFolderPos(folderIndex); + UInt64 finishPos = lastItem->Offset + lastItem->Size; + UInt64 limitFolderIndex = lzxInfo.GetFolder(finishPos); + + lastFolderIndex = m_Database.GetLastFolder(index); + UInt64 folderSize = lzxInfo.GetFolderSize(); + UInt64 unPackSize = folderSize; + if (extractStatuses.IsEmpty()) + chmFolderOutStream->m_StartIndex = index + 1; + else + chmFolderOutStream->m_StartIndex = index; + if (limitFolderIndex == folderIndex) + { + for (; i < numItems; i++) + { + UInt32 nextIndex = allFilesMode ? i : indices[i]; + int entryIndex = m_Database.Indices[nextIndex]; + const CItem &nextItem = m_Database.Items[entryIndex]; + if (nextItem.Section != sectionIndex) + break; + UInt64 nextFolderIndex = m_Database.GetFolder(nextIndex); + if (nextFolderIndex != folderIndex) + break; + for (index++; index < nextIndex; index++) + extractStatuses.Add(false); + extractStatuses.Add(true); + index = nextIndex; + lastItem = &nextItem; + if (nextItem.Size != 0) + finishPos = nextItem.Offset + nextItem.Size; + lastFolderIndex = m_Database.GetLastFolder(index); + } + } + unPackSize = MyMin(finishPos - startPos, unPackSize); + + chmFolderOutStream->m_FolderSize = folderSize; + chmFolderOutStream->m_PosInFolder = 0; + chmFolderOutStream->m_PosInSection = startPos; + chmFolderOutStream->m_ExtractStatuses = &extractStatuses; + chmFolderOutStream->m_NumFiles = extractStatuses.Size(); + chmFolderOutStream->m_CurrentIndex = 0; + try + { + UInt64 startBlock = lzxInfo.GetBlockIndexFromFolderIndex(folderIndex); + const CResetTable &rt = lzxInfo.ResetTable; + UInt32 numBlocks = (UInt32)rt.GetNumBlocks(unPackSize); + for (UInt32 b = 0; b < numBlocks; b++) + { + UInt64 completedSize = currentTotalSize + chmFolderOutStream->m_PosInSection - startPos; + RINOK(extractCallback->SetCompleted(&completedSize)); + UInt64 bCur = startBlock + b; + if (bCur >= rt.ResetOffsets.Size()) + return E_FAIL; + UInt64 offset = rt.ResetOffsets[(int)bCur]; + UInt64 compressedSize; + rt.GetCompressedSizeOfBlock(bCur, compressedSize); + UInt64 rem = finishPos - chmFolderOutStream->m_PosInSection; + if (rem > rt.BlockSize) + rem = rt.BlockSize; + RINOK(m_Stream->Seek(compressedPos + offset, STREAM_SEEK_SET, NULL)); + streamSpec->SetStream(m_Stream); + streamSpec->Init(compressedSize); + lzxDecoderSpec->SetKeepHistory(b > 0); + HRESULT res = lzxDecoder->Code(inStream, outStream, NULL, &rem, NULL); + if (res != S_OK) + { + if (res != S_FALSE) + return res; + throw 1; + } + } + } + catch(...) + { + RINOK(chmFolderOutStream->FlushCorrupted(unPackSize)); + } + currentTotalSize += folderSize; + if (folderIndex == lastFolderIndex) + break; + extractStatuses.Clear(); + } + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = m_Database.NewFormat ? 1: + (m_Database.LowLevel ? + m_Database.Items.Size(): + m_Database.Indices.Size()); + return S_OK; +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.h new file mode 100644 index 000000000..440c50f11 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHandler.h @@ -0,0 +1,29 @@ +// ChmHandler.h + +#ifndef __ARCHIVE_CHM_HANDLER_H +#define __ARCHIVE_CHM_HANDLER_H + +#include "Common/MyCom.h" +#include "../IArchive.h" +#include "ChmIn.h" + +namespace NArchive { +namespace NChm { + +class CHandler: + public IInArchive, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP1(IInArchive) + + INTERFACE_IInArchive(;) + +private: + CFilesDatabase m_Database; + CMyComPtr<IInStream> m_Stream; +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.cpp new file mode 100644 index 000000000..e8dc9f3e8 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.cpp @@ -0,0 +1,24 @@ +// Archive/Chm/Header.h + +#include "StdAfx.h" + +#include "ChmHeader.h" + +namespace NArchive{ +namespace NChm{ +namespace NHeader{ + +UInt32 kItsfSignature = 0x46535449 + 1; +UInt32 kItolSignature = 0x4C4F5449 + 1; +static class CSignatureInitializer +{ +public: + CSignatureInitializer() + { + kItsfSignature--; + kItolSignature--; + } +}g_SignatureInitializer; + + +}}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.h b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.h new file mode 100644 index 000000000..9f1bd42b6 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmHeader.h @@ -0,0 +1,28 @@ +// Archive/Chm/Header.h + +#ifndef __ARCHIVE_CHM_HEADER_H +#define __ARCHIVE_CHM_HEADER_H + +#include "Common/Types.h" + +namespace NArchive { +namespace NChm { +namespace NHeader{ + +const UInt32 kItspSignature = 0x50535449; +const UInt32 kPmglSignature = 0x4C474D50; +const UInt32 kLzxcSignature = 0x43585A4C; + +const UInt32 kIfcmSignature = 0x4D434649; +const UInt32 kAollSignature = 0x4C4C4F41; +const UInt32 kCaolSignature = 0x4C4F4143; + +extern UInt32 kItsfSignature; + +extern UInt32 kItolSignature; +const UInt32 kItlsSignature = 0x534C5449; +UInt64 inline GetHxsSignature() { return ((UInt64)kItlsSignature << 32) | kItolSignature; } + +}}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.cpp new file mode 100644 index 000000000..d52b9ba6c --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.cpp @@ -0,0 +1,937 @@ +// Archive/ChmIn.cpp + +#include "StdAfx.h" + +#include "Common/IntToString.h" +#include "Common/UTFConvert.h" + +#include "../../Common/LimitedStreams.h" + +#include "ChmIn.h" + +namespace NArchive { +namespace NChm { + +// define CHM_LOW, if you want to see low level items +// #define CHM_LOW + +static const GUID kChmLzxGuid = { 0x7FC28940, 0x9D31, 0x11D0, { 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C } }; +static const GUID kHelp2LzxGuid = { 0x0A9007C6, 0x4076, 0x11D3, { 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 } }; +static const GUID kDesGuid = { 0x67F6E4A2, 0x60BF, 0x11D3, { 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF } }; + +static bool AreGuidsEqual(REFGUID g1, REFGUID g2) +{ + if (g1.Data1 != g2.Data1 || + g1.Data2 != g2.Data2 || + g1.Data3 != g2.Data3) + return false; + for (int i = 0; i < 8; i++) + if (g1.Data4[i] != g2.Data4[i]) + return false; + return true; +} + +static char GetHex(Byte value) +{ + return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); +} + +static void PrintByte(Byte b, AString &s) +{ + s += GetHex(b >> 4); + s += GetHex(b & 0xF); +} + +static void PrintUInt16(UInt16 v, AString &s) +{ + PrintByte((Byte)(v >> 8), s); + PrintByte((Byte)v, s); +} + +static void PrintUInt32(UInt32 v, AString &s) +{ + PrintUInt16((UInt16)(v >> 16), s); + PrintUInt16((UInt16)v, s); +} + +AString CMethodInfo::GetGuidString() const +{ + AString s; + s += '{'; + PrintUInt32(Guid.Data1, s); + s += '-'; + PrintUInt16(Guid.Data2, s); + s += '-'; + PrintUInt16(Guid.Data3, s); + s += '-'; + PrintByte(Guid.Data4[0], s); + PrintByte(Guid.Data4[1], s); + s += '-'; + for (int i = 2; i < 8; i++) + PrintByte(Guid.Data4[i], s); + s += '}'; + return s; +} + +bool CMethodInfo::IsLzx() const +{ + if (AreGuidsEqual(Guid, kChmLzxGuid)) + return true; + return AreGuidsEqual(Guid, kHelp2LzxGuid); +} + +bool CMethodInfo::IsDes() const +{ + return AreGuidsEqual(Guid, kDesGuid); +} + +UString CMethodInfo::GetName() const +{ + UString s; + if (IsLzx()) + { + s = L"LZX:"; + wchar_t temp[16]; + ConvertUInt32ToString(LzxInfo.GetNumDictBits(), temp); + s += temp; + } + else + { + AString s2; + if (IsDes()) + s2 = "DES"; + else + { + s2 = GetGuidString(); + if (ControlData.GetCapacity() > 0) + { + s2 += ':'; + for (size_t i = 0; i < ControlData.GetCapacity(); i++) + PrintByte(ControlData[i], s2); + } + } + ConvertUTF8ToUnicode(s2, s); + } + return s; +} + +bool CSectionInfo::IsLzx() const +{ + if (Methods.Size() != 1) + return false; + return Methods[0].IsLzx(); +} + +UString CSectionInfo::GetMethodName() const +{ + UString s; + if (!IsLzx()) + { + UString temp; + if (ConvertUTF8ToUnicode(Name, temp)) + s += temp; + s += L": "; + } + for (int i = 0; i < Methods.Size(); i++) + { + if (i != 0) + s += L' '; + s += Methods[i].GetName(); + } + return s; +} + +Byte CInArchive::ReadByte() +{ + Byte b; + if (!_inBuffer.ReadByte(b)) + throw 1; + return b; +} + +void CInArchive::Skip(size_t size) +{ + while (size-- != 0) + ReadByte(); +} + +void CInArchive::ReadBytes(Byte *data, UInt32 size) +{ + for (UInt32 i = 0; i < size; i++) + data[i] = ReadByte(); +} + +UInt16 CInArchive::ReadUInt16() +{ + UInt16 value = 0; + for (int i = 0; i < 2; i++) + value |= ((UInt16)(ReadByte()) << (8 * i)); + return value; +} + +UInt32 CInArchive::ReadUInt32() +{ + UInt32 value = 0; + for (int i = 0; i < 4; i++) + value |= ((UInt32)(ReadByte()) << (8 * i)); + return value; +} + +UInt64 CInArchive::ReadUInt64() +{ + UInt64 value = 0; + for (int i = 0; i < 8; i++) + value |= ((UInt64)(ReadByte()) << (8 * i)); + return value; +} + +UInt64 CInArchive::ReadEncInt() +{ + UInt64 val = 0;; + for (int i = 0; i < 10; i++) + { + Byte b = ReadByte(); + val |= (b & 0x7F); + if (b < 0x80) + return val; + val <<= 7; + } + throw 1; +} + +void CInArchive::ReadGUID(GUID &g) +{ + g.Data1 = ReadUInt32(); + g.Data2 = ReadUInt16(); + g.Data3 = ReadUInt16(); + ReadBytes(g.Data4, 8); +} + +void CInArchive::ReadString(int size, AString &s) +{ + s.Empty(); + while(size-- != 0) + { + char c = (char)ReadByte(); + if (c == 0) + { + Skip(size); + return; + } + s += c; + } +} + +void CInArchive::ReadUString(int size, UString &s) +{ + s.Empty(); + while(size-- != 0) + { + wchar_t c = ReadUInt16(); + if (c == 0) + { + Skip(2 * size); + return; + } + s += c; + } +} + +HRESULT CInArchive::ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size) +{ + RINOK(inStream->Seek(pos, STREAM_SEEK_SET, NULL)); + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> limitedStream(streamSpec); + streamSpec->SetStream(inStream); + streamSpec->Init(size); + _inBuffer.SetStream(limitedStream); + _inBuffer.Init(); + return S_OK; +} + +HRESULT CInArchive::ReadDirEntry(CDatabase &database) +{ + CItem item; + UInt64 nameLength = ReadEncInt(); + if (nameLength == 0 || nameLength >= 0x10000000) + return S_FALSE; + ReadString((int)nameLength, item.Name); + item.Section = ReadEncInt(); + item.Offset = ReadEncInt(); + item.Size = ReadEncInt(); + database.Items.Add(item); + return S_OK; +} + +HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database) +{ + UInt32 headerSize = ReadUInt32(); + if (headerSize != 0x60) + return S_FALSE; + UInt32 unknown1 = ReadUInt32(); + if (unknown1 != 0 && unknown1 != 1) // it's 0 in one .sll file + return S_FALSE; + /* UInt32 timeStamp = */ ReadUInt32(); + // Considered as a big-endian DWORD, it appears to contain seconds (MSB) and + // fractional seconds (second byte). + // The third and fourth bytes may contain even more fractional bits. + // The 4 least significant bits in the last byte are constant. + /* UInt32 lang = */ ReadUInt32(); + GUID g; + ReadGUID(g); // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC} + ReadGUID(g); // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC} + const int kNumSections = 2; + UInt64 sectionOffsets[kNumSections]; + UInt64 sectionSizes[kNumSections]; + int i; + for (i = 0; i < kNumSections; i++) + { + sectionOffsets[i] = ReadUInt64(); + sectionSizes[i] = ReadUInt64(); + } + // if (chmVersion == 3) + database.ContentOffset = ReadUInt64(); + /* + else + database.ContentOffset = _startPosition + 0x58 + */ + + /* + // Section 0 + ReadChunk(inStream, sectionOffsets[0], sectionSizes[0]); + if (sectionSizes[0] != 0x18) + return S_FALSE; + ReadUInt32(); // unknown: 01FE + ReadUInt32(); // unknown: 0 + UInt64 fileSize = ReadUInt64(); + ReadUInt32(); // unknown: 0 + ReadUInt32(); // unknown: 0 + */ + + // Section 1: The Directory Listing + ReadChunk(inStream, sectionOffsets[1], sectionSizes[1]); + if (ReadUInt32() != NHeader::kItspSignature) + return S_FALSE; + if (ReadUInt32() != 1) // version + return S_FALSE; + /* UInt32 dirHeaderSize = */ ReadUInt32(); + ReadUInt32(); // 0x0A (unknown) + UInt32 dirChunkSize = ReadUInt32(); // $1000 + if (dirChunkSize < 32) + return S_FALSE; + /* UInt32 density = */ ReadUInt32(); // "Density" of quickref section, usually 2. + /* UInt32 depth = */ ReadUInt32(); // Depth of the index tree: 1 there is no index, + // 2 if there is one level of PMGI chunks. + + /* UInt32 chunkNumber = */ ReadUInt32(); // Chunk number of root index chunk, -1 if there is none + // (though at least one file has 0 despite there being no + // index chunk, probably a bug.) + /* UInt32 firstPmglChunkNumber = */ ReadUInt32(); // Chunk number of first PMGL (listing) chunk + /* UInt32 lastPmglChunkNumber = */ ReadUInt32(); // Chunk number of last PMGL (listing) chunk + ReadUInt32(); // -1 (unknown) + UInt32 numDirChunks = ReadUInt32(); // Number of directory chunks (total) + /* UInt32 windowsLangId = */ ReadUInt32(); + ReadGUID(g); // {5D02926A-212E-11D0-9DF9-00A0C922E6EC} + ReadUInt32(); // 0x54 (This is the length again) + ReadUInt32(); // -1 (unknown) + ReadUInt32(); // -1 (unknown) + ReadUInt32(); // -1 (unknown) + + for (UInt32 ci = 0; ci < numDirChunks; ci++) + { + UInt64 chunkPos = _inBuffer.GetProcessedSize(); + if (ReadUInt32() == NHeader::kPmglSignature) + { + // The quickref area is written backwards from the end of the chunk. + // One quickref entry exists for every n entries in the file, where n + // is calculated as 1 + (1 << quickref density). So for density = 2, n = 5. + + UInt32 quickrefLength = ReadUInt32(); // Length of free space and/or quickref area at end of directory chunk + if (quickrefLength > dirChunkSize || quickrefLength < 2) + return S_FALSE; + ReadUInt32(); // Always 0 + ReadUInt32(); // Chunk number of previous listing chunk when reading + // directory in sequence (-1 if this is the first listing chunk) + ReadUInt32(); // Chunk number of next listing chunk when reading + // directory in sequence (-1 if this is the last listing chunk) + int numItems = 0; + for (;;) + { + UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos; + UInt32 offsetLimit = dirChunkSize - quickrefLength; + if (offset > offsetLimit) + return S_FALSE; + if (offset == offsetLimit) + break; + RINOK(ReadDirEntry(database)); + numItems++; + } + Skip(quickrefLength - 2); + if (ReadUInt16() != numItems) + return S_FALSE; + } + else + Skip(dirChunkSize - 4); + } + return S_OK; +} + +HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) +{ + if (ReadUInt32() != 1) // version + return S_FALSE; + if (ReadUInt32() != 0x28) // Location of header section table + return S_FALSE; + UInt32 numHeaderSections = ReadUInt32(); + const int kNumHeaderSectionsMax = 5; + if (numHeaderSections != kNumHeaderSectionsMax) + return S_FALSE; + ReadUInt32(); // Length of post-header table + GUID g; + ReadGUID(g); // {0A9007C1-4076-11D3-8789-0000F8105754} + + // header section table + UInt64 sectionOffsets[kNumHeaderSectionsMax]; + UInt64 sectionSizes[kNumHeaderSectionsMax]; + UInt32 i; + for (i = 0; i < numHeaderSections; i++) + { + sectionOffsets[i] = ReadUInt64(); + sectionSizes[i] = ReadUInt64(); + } + + // Post-Header + ReadUInt32(); // 2 + ReadUInt32(); // 0x98: offset to CAOL from beginning of post-header) + // ----- Directory information + ReadUInt64(); // Chunk number of top-level AOLI chunk in directory, or -1 + ReadUInt64(); // Chunk number of first AOLL chunk in directory + ReadUInt64(); // Chunk number of last AOLL chunk in directory + ReadUInt64(); // 0 (unknown) + ReadUInt32(); // $2000 (Directory chunk size of directory) + ReadUInt32(); // Quickref density for main directory, usually 2 + ReadUInt32(); // 0 (unknown) + ReadUInt32(); // Depth of main directory index tree + // 1 there is no index, 2 if there is one level of AOLI chunks. + ReadUInt64(); // 0 (unknown) + UInt64 numDirEntries = ReadUInt64(); // Number of directory entries + // ----- Directory Index Information + ReadUInt64(); // -1 (unknown, probably chunk number of top-level AOLI in directory index) + ReadUInt64(); // Chunk number of first AOLL chunk in directory index + ReadUInt64(); // Chunk number of last AOLL chunk in directory index + ReadUInt64(); // 0 (unknown) + ReadUInt32(); // $200 (Directory chunk size of directory index) + ReadUInt32(); // Quickref density for directory index, usually 2 + ReadUInt32(); // 0 (unknown) + ReadUInt32(); // Depth of directory index index tree. + ReadUInt64(); // Possibly flags -- sometimes 1, sometimes 0. + ReadUInt64(); // Number of directory index entries (same as number of AOLL + // chunks in main directory) + + // (The obvious guess for the following two fields, which recur in a number + // of places, is they are maximum sizes for the directory and directory index. + // However, I have seen no direct evidence that this is the case.) + + ReadUInt32(); // $100000 (Same as field following chunk size in directory) + ReadUInt32(); // $20000 (Same as field following chunk size in directory index) + + ReadUInt64(); // 0 (unknown) + if (ReadUInt32() != NHeader::kCaolSignature) + return S_FALSE; + if (ReadUInt32() != 2) // (Most likely a version number) + return S_FALSE; + UInt32 caolLength = ReadUInt32(); // $50 (Length of the CAOL section, which includes the ITSF section) + if (caolLength >= 0x2C) + { + /* UInt32 c7 = */ ReadUInt16(); // Unknown. Remains the same when identical files are built. + // Does not appear to be a checksum. Many files have + // 'HH' (HTML Help?) here, indicating this may be a compiler ID + // field. But at least one ITOL/ITLS compiler does not set this + // field to a constant value. + ReadUInt16(); // 0 (Unknown. Possibly part of 00A4 field) + ReadUInt32(); // Unknown. Two values have been seen -- $43ED, and 0. + ReadUInt32(); // $2000 (Directory chunk size of directory) + ReadUInt32(); // $200 (Directory chunk size of directory index) + ReadUInt32(); // $100000 (Same as field following chunk size in directory) + ReadUInt32(); // $20000 (Same as field following chunk size in directory index) + ReadUInt32(); // 0 (unknown) + ReadUInt32(); // 0 (Unknown) + if (caolLength == 0x2C) + { + database.ContentOffset = 0; + database.NewFormat = true; + } + else if (caolLength == 0x50) + { + ReadUInt32(); // 0 (Unknown) + if (ReadUInt32() != NHeader::kItsfSignature) + return S_FALSE; + if (ReadUInt32() != 4) // $4 (Version number -- CHM uses 3) + return S_FALSE; + if (ReadUInt32() != 0x20) // $20 (length of ITSF) + return S_FALSE; + UInt32 unknown = ReadUInt32(); + if (unknown != 0 && unknown != 1) // = 0 for some HxW files, 1 in other cases; + return S_FALSE; + database.ContentOffset = _startPosition + ReadUInt64(); + /* UInt32 timeStamp = */ ReadUInt32(); + // A timestamp of some sort. + // Considered as a big-endian DWORD, it appears to contain + // seconds (MSB) and fractional seconds (second byte). + // The third and fourth bytes may contain even more fractional + // bits. The 4 least significant bits in the last byte are constant. + /* UInt32 lang = */ ReadUInt32(); // BE? + } + else + return S_FALSE; + } + + /* + // Section 0 + ReadChunk(inStream, _startPosition + sectionOffsets[0], sectionSizes[0]); + if (sectionSizes[0] != 0x18) + return S_FALSE; + ReadUInt32(); // unknown: 01FE + ReadUInt32(); // unknown: 0 + UInt64 fileSize = ReadUInt64(); + ReadUInt32(); // unknown: 0 + ReadUInt32(); // unknown: 0 + */ + + // Section 1: The Directory Listing + ReadChunk(inStream, _startPosition + sectionOffsets[1], sectionSizes[1]); + if (ReadUInt32() != NHeader::kIfcmSignature) + return S_FALSE; + if (ReadUInt32() != 1) // (probably a version number) + return S_FALSE; + UInt32 dirChunkSize = ReadUInt32(); // $2000 + if (dirChunkSize < 64) + return S_FALSE; + ReadUInt32(); // $100000 (unknown) + ReadUInt32(); // -1 (unknown) + ReadUInt32(); // -1 (unknown) + UInt32 numDirChunks = ReadUInt32(); + ReadUInt32(); // 0 (unknown, probably high word of above) + + for (UInt32 ci = 0; ci < numDirChunks; ci++) + { + UInt64 chunkPos = _inBuffer.GetProcessedSize(); + if (ReadUInt32() == NHeader::kAollSignature) + { + UInt32 quickrefLength = ReadUInt32(); // Length of quickref area at end of directory chunk + if (quickrefLength > dirChunkSize || quickrefLength < 2) + return S_FALSE; + ReadUInt64(); // Directory chunk number + // This must match physical position in file, that is + // the chunk size times the chunk number must be the + // offset from the end of the directory header. + ReadUInt64(); // Chunk number of previous listing chunk when reading + // directory in sequence (-1 if first listing chunk) + ReadUInt64(); // Chunk number of next listing chunk when reading + // directory in sequence (-1 if last listing chunk) + ReadUInt64(); // Number of first listing entry in this chunk + ReadUInt32(); // 1 (unknown -- other values have also been seen here) + ReadUInt32(); // 0 (unknown) + + int numItems = 0; + for (;;) + { + UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos; + UInt32 offsetLimit = dirChunkSize - quickrefLength; + if (offset > offsetLimit) + return S_FALSE; + if (offset == offsetLimit) + break; + if (database.NewFormat) + { + UInt16 nameLength = ReadUInt16(); + if (nameLength == 0) + return S_FALSE; + UString name; + ReadUString((int)nameLength, name); + AString s; + ConvertUnicodeToUTF8(name, s); + Byte b = ReadByte(); + s += ' '; + PrintByte(b, s); + s += ' '; + UInt64 len = ReadEncInt(); + // then number of items ? + // then length ? + // then some data (binary encoding?) + while (len-- != 0) + { + b = ReadByte(); + PrintByte(b, s); + } + database.NewFormatString += s; + database.NewFormatString += "\r\n"; + } + else + { + RINOK(ReadDirEntry(database)); + } + numItems++; + } + Skip(quickrefLength - 2); + if (ReadUInt16() != numItems) + return S_FALSE; + if (numItems > numDirEntries) + return S_FALSE; + numDirEntries -= numItems; + } + else + Skip(dirChunkSize - 4); + } + return numDirEntries == 0 ? S_OK : S_FALSE; +} + +HRESULT CInArchive::DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name) +{ + int index = database.FindItem(name); + if (index < 0) + return S_FALSE; + const CItem &item = database.Items[index]; + _chunkSize = item.Size; + return ReadChunk(inStream, database.ContentOffset + item.Offset, item.Size); +} + + +#define DATA_SPACE "::DataSpace/" +static const char *kNameList = DATA_SPACE "NameList"; +static const char *kStorage = DATA_SPACE "Storage/"; +static const char *kContent = "Content"; +static const char *kControlData = "ControlData"; +static const char *kSpanInfo = "SpanInfo"; +static const char *kTransform = "Transform/"; +static const char *kResetTable = "/InstanceData/ResetTable"; +static const char *kTransformList = "List"; + +static AString GetSectionPrefix(const AString &name) +{ + return AString(kStorage) + name + AString("/"); +} + +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + +static int CompareFiles(const int *p1, const int *p2, void *param) +{ + const CObjectVector<CItem> &items = *(const CObjectVector<CItem> *)param; + const CItem &item1 = items[*p1]; + const CItem &item2 = items[*p2]; + bool isDir1 = item1.IsDir(); + bool isDir2 = item2.IsDir(); + if (isDir1 && !isDir2) + return -1; + if (isDir2) + { + if (isDir1) + return MyCompare(*p1, *p2); + return 1; + } + RINOZ(MyCompare(item1.Section, item2.Section)); + RINOZ(MyCompare(item1.Offset, item2.Offset)); + RINOZ(MyCompare(item1.Size, item2.Size)); + return MyCompare(*p1, *p2); +} + +void CFilesDatabase::SetIndices() +{ + for (int i = 0; i < Items.Size(); i++) + { + const CItem &item = Items[i]; + if (item.IsUserItem() && item.Name.Length() != 1) + Indices.Add(i); + } +} + +void CFilesDatabase::Sort() +{ + Indices.Sort(CompareFiles, (void *)&Items); +} + +bool CFilesDatabase::Check() +{ + UInt64 maxPos = 0; + UInt64 prevSection = 0; + for(int i = 0; i < Indices.Size(); i++) + { + const CItem &item = Items[Indices[i]]; + if (item.Section == 0 || item.IsDir()) + continue; + if (item.Section != prevSection) + { + prevSection = item.Section; + maxPos = 0; + continue; + } + if (item.Offset < maxPos) + return false; + maxPos = item.Offset + item.Size; + if (maxPos < item.Offset) + return false; + } + return true; +} + +HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) +{ + { + // The NameList file + RINOK(DecompressStream(inStream, database, kNameList)); + /* UInt16 length = */ ReadUInt16(); + UInt16 numSections = ReadUInt16(); + for (int i = 0; i < numSections; i++) + { + CSectionInfo section; + UInt16 nameLength = ReadUInt16(); + UString name; + ReadUString(nameLength, name); + if (ReadUInt16() != 0) + return S_FALSE; + if (!ConvertUnicodeToUTF8(name, section.Name)) + return S_FALSE; + database.Sections.Add(section); + } + } + + int i; + for (i = 1; i < database.Sections.Size(); i++) + { + CSectionInfo §ion = database.Sections[i]; + AString sectionPrefix = GetSectionPrefix(section.Name); + { + // Content + int index = database.FindItem(sectionPrefix + kContent); + if (index < 0) + return S_FALSE; + const CItem &item = database.Items[index]; + section.Offset = item.Offset; + section.CompressedSize = item.Size; + } + AString transformPrefix = sectionPrefix + kTransform; + if (database.Help2Format) + { + // Transform List + RINOK(DecompressStream(inStream, database, transformPrefix + kTransformList)); + if ((_chunkSize & 0xF) != 0) + return S_FALSE; + int numGuids = (int)(_chunkSize / 0x10); + if (numGuids < 1) + return S_FALSE; + for (int i = 0; i < numGuids; i++) + { + CMethodInfo method; + ReadGUID(method.Guid); + section.Methods.Add(method); + } + } + else + { + CMethodInfo method; + method.Guid = kChmLzxGuid; + section.Methods.Add(method); + } + + { + // Control Data + RINOK(DecompressStream(inStream, database, sectionPrefix + kControlData)); + for (int mi = 0; mi < section.Methods.Size(); mi++) + { + CMethodInfo &method = section.Methods[mi]; + UInt32 numDWORDS = ReadUInt32(); + if (method.IsLzx()) + { + if (numDWORDS < 5) + return S_FALSE; + if (ReadUInt32() != NHeader::kLzxcSignature) + return S_FALSE; + CLzxInfo &li = method.LzxInfo; + li.Version = ReadUInt32(); + if (li.Version != 2 && li.Version != 3) + return S_FALSE; + li.ResetInterval = ReadUInt32(); + li.WindowSize = ReadUInt32(); + li.CacheSize = ReadUInt32(); + if ( + li.ResetInterval != 1 && + li.ResetInterval != 2 && + li.ResetInterval != 4 && + li.ResetInterval != 8 && + li.ResetInterval != 16 && + li.ResetInterval != 32 && + li.ResetInterval != 64) + return S_FALSE; + if ( + li.WindowSize != 1 && + li.WindowSize != 2 && + li.WindowSize != 4 && + li.WindowSize != 8 && + li.WindowSize != 16 && + li.WindowSize != 32 && + li.WindowSize != 64) + return S_FALSE; + numDWORDS -= 5; + while (numDWORDS-- != 0) + ReadUInt32(); + } + else + { + UInt32 numBytes = numDWORDS * 4; + method.ControlData.SetCapacity(numBytes); + ReadBytes(method.ControlData, numBytes); + } + } + } + + { + // SpanInfo + RINOK(DecompressStream(inStream, database, sectionPrefix + kSpanInfo)); + section.UncompressedSize = ReadUInt64(); + } + + // read ResetTable for LZX + for (int mi = 0; mi < section.Methods.Size(); mi++) + { + CMethodInfo &method = section.Methods[mi]; + if (method.IsLzx()) + { + // ResetTable; + RINOK(DecompressStream(inStream, database, transformPrefix + + method.GetGuidString() + kResetTable)); + CResetTable &rt = method.LzxInfo.ResetTable; + if (_chunkSize < 4) + { + if (_chunkSize != 0) + return S_FALSE; + // ResetTable is empty in .chw files + if (section.UncompressedSize != 0) + return S_FALSE; + rt.UncompressedSize = 0; + rt.CompressedSize = 0; + rt.BlockSize = 0; + } + else + { + UInt32 ver = ReadUInt32(); // 2 unknown (possibly a version number) + if (ver != 2 && ver != 3) + return S_FALSE; + UInt32 numEntries = ReadUInt32(); + if (ReadUInt32() != 8) // Size of table entry (bytes) + return S_FALSE; + if (ReadUInt32() != 0x28) // Length of table header + return S_FALSE; + rt.UncompressedSize = ReadUInt64(); + rt.CompressedSize = ReadUInt64(); + rt.BlockSize = ReadUInt64(); // 0x8000 block size for locations below + if (rt.BlockSize != 0x8000) + return S_FALSE; + rt.ResetOffsets.Reserve(numEntries); + for (UInt32 i = 0; i < numEntries; i++) + rt.ResetOffsets.Add(ReadUInt64()); + } + } + } + } + + database.SetIndices(); + database.Sort(); + return database.Check() ? S_OK : S_FALSE; +} + +HRESULT CInArchive::Open2(IInStream *inStream, + const UInt64 *searchHeaderSizeLimit, + CFilesDatabase &database) +{ + database.Clear(); + + RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_startPosition)); + + database.Help2Format = false; + const UInt32 chmVersion = 3; + { + if (!_inBuffer.Create(1 << 14)) + return E_OUTOFMEMORY; + _inBuffer.SetStream(inStream); + _inBuffer.Init(); + UInt64 value = 0; + const int kSignatureSize = 8; + UInt64 hxsSignature = NHeader::GetHxsSignature(); + UInt64 chmSignature = ((UInt64)chmVersion << 32)| NHeader::kItsfSignature; + UInt64 limit = 1 << 18; + if (searchHeaderSizeLimit) + if (limit > *searchHeaderSizeLimit) + limit = *searchHeaderSizeLimit; + + for (;;) + { + Byte b; + if (!_inBuffer.ReadByte(b)) + return S_FALSE; + value >>= 8; + value |= ((UInt64)b) << ((kSignatureSize - 1) * 8); + if (_inBuffer.GetProcessedSize() >= kSignatureSize) + { + if (value == chmSignature) + break; + if (value == hxsSignature) + { + database.Help2Format = true; + break; + } + if (_inBuffer.GetProcessedSize() > limit) + return S_FALSE; + } + } + _startPosition += _inBuffer.GetProcessedSize() - kSignatureSize; + } + + if (database.Help2Format) + { + RINOK(OpenHelp2(inStream, database)); + if (database.NewFormat) + return S_OK; + } + else + { + RINOK(OpenChm(inStream, database)); + } + + #ifndef CHM_LOW + try + { + HRESULT res = OpenHighLevel(inStream, database); + if (res == S_FALSE) + { + database.HighLevelClear(); + return S_OK; + } + RINOK(res); + database.LowLevel = false; + } + catch(...) + { + return S_OK; + } + #endif + return S_OK; +} + +HRESULT CInArchive::Open(IInStream *inStream, + const UInt64 *searchHeaderSizeLimit, + CFilesDatabase &database) +{ + try + { + HRESULT res = Open2(inStream, searchHeaderSizeLimit, database); + _inBuffer.ReleaseStream(); + return res; + } + catch(...) + { + _inBuffer.ReleaseStream(); + throw; + } +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.h new file mode 100644 index 000000000..4719a484d --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmIn.h @@ -0,0 +1,244 @@ +// Archive/ChmIn.h + +#ifndef __ARCHIVE_CHM_IN_H +#define __ARCHIVE_CHM_IN_H + +#include "Common/Buffer.h" +#include "Common/MyString.h" + +#include "../../IStream.h" +#include "../../Common/InBuffer.h" + +#include "ChmHeader.h" + +namespace NArchive { +namespace NChm { + +struct CItem +{ + UInt64 Section; + UInt64 Offset; + UInt64 Size; + AString Name; + + bool IsFormatRelatedItem() const + { + if (Name.Length() < 2) + return false; + return Name[0] == ':' && Name[1] == ':'; + } + + bool IsUserItem() const + { + if (Name.Length() < 2) + return false; + return Name[0] == '/'; + } + + bool IsDir() const + { + if (Name.Length() == 0) + return false; + return (Name[Name.Length() - 1] == '/'); + } +}; + +struct CDatabase +{ + UInt64 ContentOffset; + CObjectVector<CItem> Items; + AString NewFormatString; + bool Help2Format; + bool NewFormat; + + int FindItem(const AString &name) const + { + for (int i = 0; i < Items.Size(); i++) + if (Items[i].Name == name) + return i; + return -1; + } + + void Clear() + { + NewFormat = false; + NewFormatString.Empty(); + Help2Format = false; + Items.Clear(); + } +}; + +struct CResetTable +{ + UInt64 UncompressedSize; + UInt64 CompressedSize; + UInt64 BlockSize; + CRecordVector<UInt64> ResetOffsets; + bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const + { + if (blockIndex >= ResetOffsets.Size()) + return false; + UInt64 startPos = ResetOffsets[(int)blockIndex]; + if (blockIndex + numBlocks >= ResetOffsets.Size()) + size = CompressedSize - startPos; + else + size = ResetOffsets[(int)(blockIndex + numBlocks)] - startPos; + return true; + } + bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const + { + return GetCompressedSizeOfBlocks(blockIndex, 1, size); + } + UInt64 GetNumBlocks(UInt64 size) const + { + return (size + BlockSize - 1) / BlockSize; + } +}; + +struct CLzxInfo +{ + UInt32 Version; + UInt32 ResetInterval; + UInt32 WindowSize; + UInt32 CacheSize; + CResetTable ResetTable; + + UInt32 GetNumDictBits() const + { + if (Version == 2 || Version == 3) + { + for (int i = 0; i <= 31; i++) + if (((UInt32)1 << i) >= WindowSize) + return 15 + i; + } + 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; }; + bool GetOffsetOfFolder(UInt64 folderIndex, UInt64 &offset) const + { + UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex); + if (blockIndex >= ResetTable.ResetOffsets.Size()) + return false; + offset = ResetTable.ResetOffsets[(int)blockIndex]; + return true; + } + bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const + { + UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex); + return ResetTable.GetCompressedSizeOfBlocks(blockIndex, ResetInterval, size); + } +}; + +struct CMethodInfo +{ + GUID Guid; + CByteBuffer ControlData; + CLzxInfo LzxInfo; + bool IsLzx() const; + bool IsDes() const; + AString GetGuidString() const; + UString GetName() const; +}; + +struct CSectionInfo +{ + UInt64 Offset; + UInt64 CompressedSize; + UInt64 UncompressedSize; + + AString Name; + CObjectVector<CMethodInfo> Methods; + + bool IsLzx() const; + UString GetMethodName() const; +}; + +class CFilesDatabase: public CDatabase +{ +public: + bool LowLevel; + CRecordVector<int> Indices; + CObjectVector<CSectionInfo> Sections; + + UInt64 GetFileSize(int fileIndex) const { return Items[Indices[fileIndex]].Size; } + UInt64 GetFileOffset(int fileIndex) const { return Items[Indices[fileIndex]].Offset; } + + UInt64 GetFolder(int fileIndex) const + { + const CItem &item = Items[Indices[fileIndex]]; + const CSectionInfo §ion = Sections[(int)item.Section]; + if (section.IsLzx()) + return section.Methods[0].LzxInfo.GetFolder(item.Offset); + return 0; + } + + UInt64 GetLastFolder(int fileIndex) const + { + const CItem &item = Items[Indices[fileIndex]]; + const CSectionInfo §ion = Sections[(int)item.Section]; + if (section.IsLzx()) + return section.Methods[0].LzxInfo.GetFolder(item.Offset + item.Size - 1); + return 0; + } + + void HighLevelClear() + { + LowLevel = true; + Indices.Clear(); + Sections.Clear(); + } + + void Clear() + { + CDatabase::Clear(); + HighLevelClear(); + } + void SetIndices(); + void Sort(); + bool Check(); +}; + +class CProgressVirt +{ +public: + STDMETHOD(SetTotal)(const UInt64 *numFiles) PURE; + STDMETHOD(SetCompleted)(const UInt64 *numFiles) PURE; +}; + +class CInArchive +{ + UInt64 _startPosition; + ::CInBuffer _inBuffer; + UInt64 _chunkSize; + + Byte ReadByte(); + void ReadBytes(Byte *data, UInt32 size); + void Skip(size_t size); + UInt16 ReadUInt16(); + UInt32 ReadUInt32(); + UInt64 ReadUInt64(); + UInt64 ReadEncInt(); + void ReadString(int size, AString &s); + void ReadUString(int size, UString &s); + void ReadGUID(GUID &g); + + HRESULT ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size); + + HRESULT ReadDirEntry(CDatabase &database); + HRESULT DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name); + +public: + HRESULT OpenChm(IInStream *inStream, CDatabase &database); + HRESULT OpenHelp2(IInStream *inStream, CDatabase &database); + HRESULT OpenHighLevel(IInStream *inStream, CFilesDatabase &database); + HRESULT Open2(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database); + HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database); +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmRegister.cpp new file mode 100644 index 000000000..e5f38afa4 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/ChmRegister.cpp @@ -0,0 +1,13 @@ +// ChmRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "ChmHandler.h" +static IInArchive *CreateArc() { return new NArchive::NChm::CHandler; } + +static CArcInfo g_ArcInfo = + { L"Chm", L"chm chi chq chw hxs hxi hxr hxq hxw lit", 0, 0xE9, { 'I', 'T', 'S', 'F' }, 4, false, CreateArc, 0 }; + +REGISTER_ARC(Chm) diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Chm/StdAfx.h b/src/libs/7zip/win/CPP/7zip/Archive/Chm/StdAfx.h new file mode 100644 index 000000000..e7fb6986d --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Chm/StdAfx.h @@ -0,0 +1,8 @@ +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/MyWindows.h" + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.cpp new file mode 100644 index 000000000..58f76439f --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.cpp @@ -0,0 +1,239 @@ +// ComHandler.cpp + +#include "StdAfx.h" + +#include "Common/ComTry.h" + +#include "Windows/PropVariant.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/CopyCoder.h" + +#include "ComHandler.h" + +namespace NArchive { +namespace NCom { + +STATPROPSTG kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidIsDir, VT_BOOL}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidPackSize, VT_UI8}, + { NULL, kpidCTime, VT_FILETIME}, + { NULL, kpidMTime, VT_FILETIME} +}; + +STATPROPSTG kArcProps[] = +{ + { NULL, kpidClusterSize, VT_UI4}, + { NULL, kpidSectorSize, VT_UI4} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch(propID) + { + case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break; + case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break; + case kpidMainSubfile: if (_db.MainSubfile >= 0) prop = (UInt32)_db.MainSubfile; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CRef &ref = _db.Refs[index]; + const CItem &item = _db.Items[ref.Did]; + + switch(propID) + { + case kpidPath: prop = _db.GetItemPath(index); break; + case kpidIsDir: prop = item.IsDir(); break; + case kpidCTime: prop = item.CTime; break; + case kpidMTime: prop = item.MTime; break; + case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break; + case kpidSize: if (!item.IsDir()) prop = item.Size; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + try + { + if (_db.Open(inStream) != S_OK) + return S_FALSE; + _stream = inStream; + } + catch(...) { return S_FALSE; } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + _db.Clear(); + _stream.Release(); + return S_OK; +} + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)-1); + if (allFilesMode) + numItems = _db.Refs.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + UInt64 totalSize = 0; + for(i = 0; i < numItems; i++) + { + const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did]; + if (!item.IsDir()) + totalSize += item.Size; + } + RINOK(extractCallback->SetTotal(totalSize)); + + UInt64 totalPackSize; + totalSize = totalPackSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr<ICompressProgressInfo> progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + Int32 index = allFilesMode ? i : indices[i]; + const CItem &item = _db.Items[_db.Refs[index].Did]; + + CMyComPtr<ISequentialOutStream> outStream; + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + + if (item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + + totalPackSize += _db.GetItemPackSize(item.Size); + totalSize += item.Size; + + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + Int32 res = NExtract::NOperationResult::kDataError; + CMyComPtr<ISequentialInStream> inStream; + HRESULT hres = GetStream(index, &inStream); + if (hres == S_FALSE) + res = NExtract::NOperationResult::kDataError; + else if (hres == E_NOTIMPL) + res = NExtract::NOperationResult::kUnSupportedMethod; + else + { + RINOK(hres); + if (inStream) + { + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize == item.Size) + res = NExtract::NOperationResult::kOK; + } + } + outStream.Release(); + RINOK(extractCallback->SetOperationResult(res)); + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _db.Refs.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = 0; + const CItem &item = _db.Items[_db.Refs[index].Did]; + CClusterInStream *streamSpec = new CClusterInStream; + CMyComPtr<ISequentialInStream> streamTemp = streamSpec; + streamSpec->Stream = _stream; + streamSpec->StartOffset = 0; + + bool isLargeStream = _db.IsLargeStream(item.Size); + int bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits; + streamSpec->BlockSizeLog = bsLog; + streamSpec->Size = item.Size; + + UInt32 clusterSize = (UInt32)1 << bsLog; + UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog; + if (numClusters64 >= ((UInt32)1 << 31)) + return E_NOTIMPL; + streamSpec->Vector.Reserve((int)numClusters64); + UInt32 sid = item.Sid; + UInt64 size = item.Size; + + if (size != 0) + { + for (;; size -= clusterSize) + { + if (isLargeStream) + { + if (sid >= _db.FatSize) + return S_FALSE; + streamSpec->Vector.Add(sid + 1); + sid = _db.Fat[sid]; + } + else + { + UInt64 val; + if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32) + return S_FALSE; + streamSpec->Vector.Add((UInt32)val); + sid = _db.Mat[sid]; + } + if (size <= clusterSize) + break; + } + } + if (sid != NFatID::kEndOfChain) + return S_FALSE; + RINOK(streamSpec->InitAndSeek()); + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.h b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.h new file mode 100644 index 000000000..f2b7de96d --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComHandler.h @@ -0,0 +1,28 @@ +// ComHandler.h + +#ifndef __ARCHIVE_COM_HANDLER_H +#define __ARCHIVE_COM_HANDLER_H + +#include "Common/MyCom.h" +#include "../IArchive.h" +#include "ComIn.h" + +namespace NArchive { +namespace NCom { + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CMyComPtr<IInStream> _stream; + CDatabase _db; +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.cpp new file mode 100644 index 000000000..2203ca531 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.cpp @@ -0,0 +1,389 @@ +// Archive/ComIn.cpp + +#include "StdAfx.h" + +#include "../../../../C/Alloc.h" +#include "../../../../C/CpuArch.h" + +#include "Common/IntToString.h" +#include "Common/MyCom.h" + +#include "../../Common/StreamUtils.h" + +#include "ComIn.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + +namespace NArchive{ +namespace NCom{ + +static const UInt32 kSignatureSize = 8; +static const Byte kSignature[kSignatureSize] = { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }; + +void CUInt32Buf::Free() +{ + MyFree(_buf); + _buf = 0; +} + +bool CUInt32Buf::Allocate(UInt32 numItems) +{ + Free(); + if (numItems == 0) + return true; + size_t newSize = (size_t)numItems * sizeof(UInt32); + if (newSize / sizeof(UInt32) != numItems) + return false; + _buf = (UInt32 *)MyAlloc(newSize); + return (_buf != 0); +} + +static HRESULT ReadSector(IInStream *inStream, Byte *buf, int sectorSizeBits, UInt32 sid) +{ + RINOK(inStream->Seek((((UInt64)sid + 1) << sectorSizeBits), STREAM_SEEK_SET, NULL)); + return ReadStream_FALSE(inStream, buf, (UInt32)1 << sectorSizeBits); +} + +static HRESULT ReadIDs(IInStream *inStream, Byte *buf, int sectorSizeBits, UInt32 sid, UInt32 *dest) +{ + RINOK(ReadSector(inStream, buf, sectorSizeBits, sid)); + UInt32 sectorSize = (UInt32)1 << sectorSizeBits; + for (UInt32 t = 0; t < sectorSize; t += 4) + *dest++ = Get32(buf + t); + return S_OK; +} + +static void GetFileTimeFromMem(const Byte *p, FILETIME *ft) +{ + ft->dwLowDateTime = Get32(p); + ft->dwHighDateTime = Get32(p + 4); +} + +void CItem::Parse(const Byte *p, bool mode64bit) +{ + memcpy(Name, p, kNameSizeMax); + // NameSize = Get16(p + 64); + Type = p[66]; + LeftDid = Get32(p + 68); + RightDid = Get32(p + 72); + SonDid = Get32(p + 76); + // Flags = Get32(p + 96); + GetFileTimeFromMem(p + 100, &CTime); + GetFileTimeFromMem(p + 108, &MTime); + Sid = Get32(p + 116); + Size = Get32(p + 120); + if (mode64bit) + Size |= ((UInt64)Get32(p + 124) << 32); +} + +void CDatabase::Clear() +{ + Fat.Free(); + MiniSids.Free(); + Mat.Free(); + Items.Clear(); + Refs.Clear(); +} + +static const UInt32 kNoDid = 0xFFFFFFFF; + +HRESULT CDatabase::AddNode(int parent, UInt32 did) +{ + if (did == kNoDid) + return S_OK; + if (did >= (UInt32)Items.Size()) + return S_FALSE; + const CItem &item = Items[did]; + if (item.IsEmpty()) + return S_FALSE; + CRef ref; + ref.Parent = parent; + ref.Did = did; + int index = Refs.Add(ref); + if (Refs.Size() > Items.Size()) + return S_FALSE; + RINOK(AddNode(parent, item.LeftDid)); + RINOK(AddNode(parent, item.RightDid)); + if (item.IsDir()) + { + RINOK(AddNode(index, item.SonDid)); + } + return S_OK; +} + +static const char kCharOpenBracket = '['; +static const char kCharCloseBracket = ']'; + +static UString CompoundNameToFileName(const UString &s) +{ + UString res; + for (int i = 0; i < s.Length(); i++) + { + wchar_t c = s[i]; + if (c < 0x20) + { + res += kCharOpenBracket; + wchar_t buf[32]; + ConvertUInt32ToString(c, buf); + res += buf; + res += kCharCloseBracket; + } + else + res += c; + } + return res; +} + +static char g_MsiChars[] = +"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._"; + +static const wchar_t *kMsi_ID = L""; // L"{msi}"; + +static const int kMsiNumBits = 6; +static const UInt32 kMsiNumChars = 1 << kMsiNumBits; +static const UInt32 kMsiCharMask = kMsiNumChars - 1; +static const UInt32 kMsiStartUnicodeChar = 0x3800; +static const UInt32 kMsiUnicodeRange = kMsiNumChars * (kMsiNumChars + 1); + +bool CompoundMsiNameToFileName(const UString &name, UString &resultName) +{ + resultName.Empty(); + for (int i = 0; i < name.Length(); i++) + { + wchar_t c = name[i]; + if (c < kMsiStartUnicodeChar || c > kMsiStartUnicodeChar + kMsiUnicodeRange) + return false; + if (i == 0) + resultName += kMsi_ID; + c -= kMsiStartUnicodeChar; + + UInt32 c0 = c & kMsiCharMask; + UInt32 c1 = c >> kMsiNumBits; + + if (c1 <= kMsiNumChars) + { + resultName += (wchar_t)g_MsiChars[c0]; + if (c1 == kMsiNumChars) + break; + resultName += (wchar_t)g_MsiChars[c1]; + } + else + resultName += L'!'; + } + return true; +} + +static UString ConvertName(const Byte *p, bool &isMsi) +{ + isMsi = false; + UString s; + for (int i = 0; i < kNameSizeMax; i += 2) + { + wchar_t c = (p[i] | (wchar_t)p[i + 1] << 8); + if (c == 0) + break; + s += c; + } + UString msiName; + if (CompoundMsiNameToFileName(s, msiName)) + { + isMsi = true; + return msiName; + } + return CompoundNameToFileName(s); +} + +static UString ConvertName(const Byte *p) +{ + bool isMsi; + return ConvertName(p, isMsi); +} + +UString CDatabase::GetItemPath(UInt32 index) const +{ + UString s; + while (index != kNoDid) + { + const CRef &ref = Refs[index]; + const CItem &item = Items[ref.Did]; + if (!s.IsEmpty()) + s = (UString)WCHAR_PATH_SEPARATOR + s; + s = ConvertName(item.Name) + s; + index = ref.Parent; + } + return s; +} + +HRESULT CDatabase::Open(IInStream *inStream) +{ + MainSubfile = -1; + static const UInt32 kHeaderSize = 512; + Byte p[kHeaderSize]; + RINOK(ReadStream_FALSE(inStream, p, kHeaderSize)); + if (memcmp(p, kSignature, kSignatureSize) != 0) + return S_FALSE; + if (Get16(p + 0x1A) > 4) // majorVer + return S_FALSE; + if (Get16(p + 0x1C) != 0xFFFE) + return S_FALSE; + int sectorSizeBits = Get16(p + 0x1E); + bool mode64bit = (sectorSizeBits >= 12); + int miniSectorSizeBits = Get16(p + 0x20); + SectorSizeBits = sectorSizeBits; + MiniSectorSizeBits = miniSectorSizeBits; + + if (sectorSizeBits > 28 || miniSectorSizeBits > 28 || + sectorSizeBits < 7 || miniSectorSizeBits < 2 || miniSectorSizeBits > sectorSizeBits) + return S_FALSE; + UInt32 numSectorsForFAT = Get32(p + 0x2C); + LongStreamMinSize = Get32(p + 0x38); + + UInt32 sectSize = (UInt32)1 << (int)sectorSizeBits; + + CByteBuffer sect; + sect.SetCapacity(sectSize); + + int ssb2 = (int)(sectorSizeBits - 2); + UInt32 numSidsInSec = (UInt32)1 << ssb2; + UInt32 numFatItems = numSectorsForFAT << ssb2; + if ((numFatItems >> ssb2) != numSectorsForFAT) + return S_FALSE; + FatSize = numFatItems; + + { + CUInt32Buf bat; + UInt32 numSectorsForBat = Get32(p + 0x48); + const UInt32 kNumHeaderBatItems = 109; + UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2); + if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat) + return S_FALSE; + if (!bat.Allocate(numBatItems)) + return S_FALSE; + UInt32 i; + for (i = 0; i < kNumHeaderBatItems; i++) + bat[i] = Get32(p + 0x4c + i * 4); + UInt32 sid = Get32(p + 0x44); + for (UInt32 s = 0; s < numSectorsForBat; s++) + { + RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i)); + i += numSidsInSec - 1; + sid = bat[i]; + } + numBatItems = i; + + if (!Fat.Allocate(numFatItems)) + return S_FALSE; + UInt32 j = 0; + + for (i = 0; i < numFatItems; j++, i += numSidsInSec) + { + if (j >= numBatItems) + return S_FALSE; + RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], Fat + i)); + } + } + + UInt32 numMatItems; + { + UInt32 numSectorsForMat = Get32(p + 0x40); + numMatItems = (UInt32)numSectorsForMat << ssb2; + if ((numMatItems >> ssb2) != numSectorsForMat) + return S_FALSE; + if (!Mat.Allocate(numMatItems)) + return S_FALSE; + UInt32 i; + UInt32 sid = Get32(p + 0x3C); + for (i = 0; i < numMatItems; i += numSidsInSec) + { + RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, Mat + i)); + if (sid >= numFatItems) + return S_FALSE; + sid = Fat[sid]; + } + if (sid != NFatID::kEndOfChain) + return S_FALSE; + } + + { + UInt32 sid = Get32(p + 0x30); + for (;;) + { + if (sid >= numFatItems) + return S_FALSE; + RINOK(ReadSector(inStream, sect, sectorSizeBits, sid)); + for (UInt32 i = 0; i < sectSize; i += 128) + { + CItem item; + item.Parse(sect + i, mode64bit); + Items.Add(item); + } + sid = Fat[sid]; + if (sid == NFatID::kEndOfChain) + break; + } + } + + CItem root = Items[0]; + + { + UInt32 numSectorsInMiniStream; + { + UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits; + if (numSatSects64 > NFatID::kMaxValue) + return S_FALSE; + numSectorsInMiniStream = (UInt32)numSatSects64; + } + NumSectorsInMiniStream = numSectorsInMiniStream; + if (!MiniSids.Allocate(numSectorsInMiniStream)) + return S_FALSE; + { + UInt64 matSize64 = (root.Size + ((UInt64)1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits; + if (matSize64 > NFatID::kMaxValue) + return S_FALSE; + MatSize = (UInt32)matSize64; + if (numMatItems < MatSize) + return S_FALSE; + } + + UInt32 sid = root.Sid; + for (UInt32 i = 0; ; i++) + { + if (sid == NFatID::kEndOfChain) + { + if (i != numSectorsInMiniStream) + return S_FALSE; + break; + } + if (i >= numSectorsInMiniStream) + return S_FALSE; + MiniSids[i] = sid; + if (sid >= numFatItems) + return S_FALSE; + sid = Fat[sid]; + } + } + + RINOK(AddNode(-1, root.SonDid)); + + unsigned numCabs = 0; + for (int i = 0; i < Refs.Size(); i++) + { + const CItem &item = Items[Refs[i].Did]; + if (item.IsDir() || numCabs > 1) + continue; + bool isMsiName; + UString msiName = ConvertName(item.Name, isMsiName); + if (isMsiName && msiName.Right(4).CompareNoCase(L".cab") == 0) + { + numCabs++; + MainSubfile = i; + } + } + if (numCabs > 1) + MainSubfile = -1; + + return S_OK; +} + +}} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.h b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.h new file mode 100644 index 000000000..429d3796e --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComIn.h @@ -0,0 +1,119 @@ +// Archive/ComIn.h + +#ifndef __ARCHIVE_COM_IN_H +#define __ARCHIVE_COM_IN_H + +#include "Common/MyString.h" +#include "Common/Buffer.h" + +namespace NArchive { +namespace NCom { + +struct CUInt32Buf +{ + UInt32 *_buf; +public: + CUInt32Buf(): _buf(0) {} + ~CUInt32Buf() { Free(); } + void Free(); + bool Allocate(UInt32 numItems); + operator UInt32 *() const { return _buf; }; +}; + +namespace NFatID +{ + const UInt32 kFree = 0xFFFFFFFF; + const UInt32 kEndOfChain = 0xFFFFFFFE; + const UInt32 kFatSector = 0xFFFFFFFD; + const UInt32 kMatSector = 0xFFFFFFFC; + const UInt32 kMaxValue = 0xFFFFFFFA; +} + +namespace NItemType +{ + const Byte kEmpty = 0; + const Byte kStorage = 1; + const Byte kStream = 2; + const Byte kLockBytes = 3; + const Byte kProperty = 4; + const Byte kRootStorage = 5; +} + +const UInt32 kNameSizeMax = 64; + +struct CItem +{ + Byte Name[kNameSizeMax]; + // UInt16 NameSize; + // UInt32 Flags; + FILETIME CTime; + FILETIME MTime; + UInt64 Size; + UInt32 LeftDid; + UInt32 RightDid; + UInt32 SonDid; + UInt32 Sid; + Byte Type; + + bool IsEmpty() const { return Type == NItemType::kEmpty; } + bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; } + + void Parse(const Byte *p, bool mode64bit); +}; + +struct CRef +{ + int Parent; + UInt32 Did; +}; + +class CDatabase +{ + UInt32 NumSectorsInMiniStream; + CUInt32Buf MiniSids; + + HRESULT AddNode(int parent, UInt32 did); +public: + + CUInt32Buf Fat; + UInt32 FatSize; + + CUInt32Buf Mat; + UInt32 MatSize; + + CObjectVector<CItem> Items; + CRecordVector<CRef> Refs; + + UInt32 LongStreamMinSize; + int SectorSizeBits; + int MiniSectorSizeBits; + + Int32 MainSubfile; + + void Clear(); + bool IsLargeStream(UInt64 size) const { return size >= LongStreamMinSize; } + UString GetItemPath(UInt32 index) const; + + UInt64 GetItemPackSize(UInt64 size) const + { + UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1; + return (size + mask) & ~mask; + } + + bool GetMiniCluster(UInt32 sid, UInt64 &res) const + { + int subBits = SectorSizeBits - MiniSectorSizeBits; + UInt32 fid = sid >> subBits; + if (fid >= NumSectorsInMiniStream) + return false; + res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1)); + return true; + } + + HRESULT Open(IInStream *inStream); +}; + + +}} + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Com/ComRegister.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComRegister.cpp new file mode 100644 index 000000000..6712b890f --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Com/ComRegister.cpp @@ -0,0 +1,13 @@ +// ComRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "ComHandler.h" +static IInArchive *CreateArc() { return new NArchive::NCom::CHandler; } + +static CArcInfo g_ArcInfo = + { L"Compound", L"msi msp doc xls ppt", 0, 0xE5, { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }, 8, false, CreateArc, 0 }; + +REGISTER_ARC(Com) diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.cpp new file mode 100644 index 000000000..a19f04579 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.cpp @@ -0,0 +1,19 @@ +// CoderMixer.cpp + +#include "StdAfx.h" + +#include "CoderMixer.h" + +namespace NCoderMixer { + +void CCoderInfo::SetCoderInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + InSizeAssigned = (inSize != 0); + if (InSizeAssigned) + InSizeValue = *inSize; + OutSizeAssigned = (outSize != 0); + if (OutSizeAssigned) + OutSizeValue = *outSize; +} + +} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.h new file mode 100644 index 000000000..6379dd808 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer.h @@ -0,0 +1,32 @@ +// CoderMixer.h + +#ifndef __CODER_MIXER_H +#define __CODER_MIXER_H + +#include "../../../Common/MyCom.h" +#include "../../ICoder.h" + +namespace NCoderMixer { + +struct CCoderInfo +{ + CMyComPtr<ICompressCoder> Coder; + CMyComPtr<ISequentialInStream> InStream; + CMyComPtr<ISequentialOutStream> OutStream; + CMyComPtr<ICompressProgressInfo> Progress; + + UInt64 InSizeValue; + UInt64 OutSizeValue; + bool InSizeAssigned; + bool OutSizeAssigned; + + void ReInit() + { + InSizeAssigned = OutSizeAssigned = false; + } + + void SetCoderInfo(const UInt64 *inSize, const UInt64 *outSize); +}; + +} +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.cpp new file mode 100644 index 000000000..0b06a489f --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.cpp @@ -0,0 +1,121 @@ +// CoderMixer2.cpp + +#include "StdAfx.h" + +#include "CoderMixer2.h" + +namespace NCoderMixer { + +CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo): + _srcBindInfo(srcBindInfo) +{ + srcBindInfo.GetNumStreams(NumSrcInStreams, _numSrcOutStreams); + + UInt32 j; + for (j = 0; j < NumSrcInStreams; j++) + { + _srcInToDestOutMap.Add(0); + DestOutToSrcInMap.Add(0); + } + for (j = 0; j < _numSrcOutStreams; j++) + { + _srcOutToDestInMap.Add(0); + _destInToSrcOutMap.Add(0); + } + + UInt32 destInOffset = 0; + UInt32 destOutOffset = 0; + UInt32 srcInOffset = NumSrcInStreams; + UInt32 srcOutOffset = _numSrcOutStreams; + + for (int i = srcBindInfo.Coders.Size() - 1; i >= 0; i--) + { + const CCoderStreamsInfo &srcCoderInfo = srcBindInfo.Coders[i]; + + srcInOffset -= srcCoderInfo.NumInStreams; + srcOutOffset -= srcCoderInfo.NumOutStreams; + + UInt32 j; + for (j = 0; j < srcCoderInfo.NumInStreams; j++, destOutOffset++) + { + UInt32 index = srcInOffset + j; + _srcInToDestOutMap[index] = destOutOffset; + DestOutToSrcInMap[destOutOffset] = index; + } + for (j = 0; j < srcCoderInfo.NumOutStreams; j++, destInOffset++) + { + UInt32 index = srcOutOffset + j; + _srcOutToDestInMap[index] = destInOffset; + _destInToSrcOutMap[destInOffset] = index; + } + } +} + +void CBindReverseConverter::CreateReverseBindInfo(CBindInfo &destBindInfo) +{ + destBindInfo.Coders.Clear(); + destBindInfo.BindPairs.Clear(); + destBindInfo.InStreams.Clear(); + destBindInfo.OutStreams.Clear(); + + int i; + for (i = _srcBindInfo.Coders.Size() - 1; i >= 0; i--) + { + const CCoderStreamsInfo &srcCoderInfo = _srcBindInfo.Coders[i]; + CCoderStreamsInfo destCoderInfo; + destCoderInfo.NumInStreams = srcCoderInfo.NumOutStreams; + destCoderInfo.NumOutStreams = srcCoderInfo.NumInStreams; + destBindInfo.Coders.Add(destCoderInfo); + } + for (i = _srcBindInfo.BindPairs.Size() - 1; i >= 0; i--) + { + const CBindPair &srcBindPair = _srcBindInfo.BindPairs[i]; + CBindPair destBindPair; + destBindPair.InIndex = _srcOutToDestInMap[srcBindPair.OutIndex]; + destBindPair.OutIndex = _srcInToDestOutMap[srcBindPair.InIndex]; + destBindInfo.BindPairs.Add(destBindPair); + } + for (i = 0; i < _srcBindInfo.InStreams.Size(); i++) + destBindInfo.OutStreams.Add(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]); + for (i = 0; i < _srcBindInfo.OutStreams.Size(); i++) + destBindInfo.InStreams.Add(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]); +} + +CCoderInfo2::CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams): + NumInStreams(numInStreams), + NumOutStreams(numOutStreams) +{ + InSizes.Reserve(NumInStreams); + InSizePointers.Reserve(NumInStreams); + OutSizes.Reserve(NumOutStreams); + OutSizePointers.Reserve(NumOutStreams); +} + +static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes, + CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems) +{ + sizes.Clear(); + sizePointers.Clear(); + for(UInt32 i = 0; i < numItems; i++) + { + if (srcSizes == 0 || srcSizes[i] == NULL) + { + sizes.Add(0); + sizePointers.Add(NULL); + } + else + { + sizes.Add(*srcSizes[i]); + sizePointers.Add(&sizes.Back()); + } + } +} + +void CCoderInfo2::SetCoderInfo(const UInt64 **inSizes, + const UInt64 **outSizes) +{ + SetSizes(inSizes, InSizes, InSizePointers, NumInStreams); + SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams); +} + +} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.h new file mode 100644 index 000000000..a03722d61 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2.h @@ -0,0 +1,174 @@ +// CoderMixer2.h + +#ifndef __CODER_MIXER2_H +#define __CODER_MIXER2_H + +#include "../../../Common/MyVector.h" +#include "../../../Common/Types.h" +#include "../../../Common/MyCom.h" +#include "../../ICoder.h" + +namespace NCoderMixer { + +struct CBindPair +{ + UInt32 InIndex; + UInt32 OutIndex; +}; + +struct CCoderStreamsInfo +{ + UInt32 NumInStreams; + UInt32 NumOutStreams; +}; + +struct CBindInfo +{ + CRecordVector<CCoderStreamsInfo> Coders; + CRecordVector<CBindPair> BindPairs; + CRecordVector<UInt32> InStreams; + CRecordVector<UInt32> OutStreams; + + void Clear() + { + Coders.Clear(); + BindPairs.Clear(); + InStreams.Clear(); + OutStreams.Clear(); + } + + /* + UInt32 GetCoderStartOutStream(UInt32 coderIndex) const + { + UInt32 numOutStreams = 0; + for (UInt32 i = 0; i < coderIndex; i++) + numOutStreams += Coders[i].NumOutStreams; + return numOutStreams; + } + */ + + + void GetNumStreams(UInt32 &numInStreams, UInt32 &numOutStreams) const + { + numInStreams = 0; + numOutStreams = 0; + for (int i = 0; i < Coders.Size(); i++) + { + const CCoderStreamsInfo &coderStreamsInfo = Coders[i]; + numInStreams += coderStreamsInfo.NumInStreams; + numOutStreams += coderStreamsInfo.NumOutStreams; + } + } + + int FindBinderForInStream(UInt32 inStream) const + { + for (int i = 0; i < BindPairs.Size(); i++) + if (BindPairs[i].InIndex == inStream) + return i; + return -1; + } + int FindBinderForOutStream(UInt32 outStream) const + { + for (int i = 0; i < BindPairs.Size(); i++) + if (BindPairs[i].OutIndex == outStream) + return i; + return -1; + } + + UInt32 GetCoderInStreamIndex(UInt32 coderIndex) const + { + UInt32 streamIndex = 0; + for (UInt32 i = 0; i < coderIndex; i++) + streamIndex += Coders[i].NumInStreams; + return streamIndex; + } + + UInt32 GetCoderOutStreamIndex(UInt32 coderIndex) const + { + UInt32 streamIndex = 0; + for (UInt32 i = 0; i < coderIndex; i++) + streamIndex += Coders[i].NumOutStreams; + return streamIndex; + } + + + void FindInStream(UInt32 streamIndex, UInt32 &coderIndex, + UInt32 &coderStreamIndex) const + { + for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++) + { + UInt32 curSize = Coders[coderIndex].NumInStreams; + if (streamIndex < curSize) + { + coderStreamIndex = streamIndex; + return; + } + streamIndex -= curSize; + } + throw 1; + } + void FindOutStream(UInt32 streamIndex, UInt32 &coderIndex, + UInt32 &coderStreamIndex) const + { + for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++) + { + UInt32 curSize = Coders[coderIndex].NumOutStreams; + if (streamIndex < curSize) + { + coderStreamIndex = streamIndex; + return; + } + streamIndex -= curSize; + } + throw 1; + } +}; + +class CBindReverseConverter +{ + UInt32 _numSrcOutStreams; + NCoderMixer::CBindInfo _srcBindInfo; + CRecordVector<UInt32> _srcInToDestOutMap; + CRecordVector<UInt32> _srcOutToDestInMap; + CRecordVector<UInt32> _destInToSrcOutMap; +public: + UInt32 NumSrcInStreams; + CRecordVector<UInt32> DestOutToSrcInMap; + + CBindReverseConverter(const NCoderMixer::CBindInfo &srcBindInfo); + void CreateReverseBindInfo(NCoderMixer::CBindInfo &destBindInfo); +}; + +struct CCoderInfo2 +{ + CMyComPtr<ICompressCoder> Coder; + CMyComPtr<ICompressCoder2> Coder2; + UInt32 NumInStreams; + UInt32 NumOutStreams; + + CRecordVector<UInt64> InSizes; + CRecordVector<UInt64> OutSizes; + CRecordVector<const UInt64 *> InSizePointers; + CRecordVector<const UInt64 *> OutSizePointers; + + CCoderInfo2(UInt32 numInStreams, UInt32 numOutStreams); + void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes); + + HRESULT QueryInterface(REFGUID iid, void** pp) const + { + IUnknown *p = Coder ? (IUnknown *)Coder : (IUnknown *)Coder2; + return p->QueryInterface(iid, pp); + } +}; + +class CCoderMixer2 +{ +public: + virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) = 0; + virtual void ReInit() = 0; + virtual void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) = 0; +}; + +} +#endif + diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.cpp new file mode 100644 index 000000000..d76450bd1 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.cpp @@ -0,0 +1,240 @@ +// CoderMixer2MT.cpp + +#include "StdAfx.h" + +#include "CoderMixer2MT.h" + +namespace NCoderMixer { + +CCoder2::CCoder2(UInt32 numInStreams, UInt32 numOutStreams): + CCoderInfo2(numInStreams, numOutStreams) +{ + InStreams.Reserve(NumInStreams); + InStreamPointers.Reserve(NumInStreams); + OutStreams.Reserve(NumOutStreams); + OutStreamPointers.Reserve(NumOutStreams); +} + +void CCoder2::Execute() { Code(NULL); } + +void CCoder2::Code(ICompressProgressInfo *progress) +{ + InStreamPointers.Clear(); + OutStreamPointers.Clear(); + UInt32 i; + for (i = 0; i < NumInStreams; i++) + { + if (InSizePointers[i] != NULL) + InSizePointers[i] = &InSizes[i]; + InStreamPointers.Add((ISequentialInStream *)InStreams[i]); + } + for (i = 0; i < NumOutStreams; i++) + { + if (OutSizePointers[i] != NULL) + OutSizePointers[i] = &OutSizes[i]; + OutStreamPointers.Add((ISequentialOutStream *)OutStreams[i]); + } + if (Coder) + Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0], + InSizePointers[0], OutSizePointers[0], progress); + else + Result = Coder2->Code(&InStreamPointers.Front(), &InSizePointers.Front(), NumInStreams, + &OutStreamPointers.Front(), &OutSizePointers.Front(), NumOutStreams, progress); + { + int i; + for (i = 0; i < InStreams.Size(); i++) + InStreams[i].Release(); + for (i = 0; i < OutStreams.Size(); i++) + OutStreams[i].Release(); + } +} + +static void SetSizes(const UInt64 **srcSizes, CRecordVector<UInt64> &sizes, + CRecordVector<const UInt64 *> &sizePointers, UInt32 numItems) +{ + sizes.Clear(); + sizePointers.Clear(); + for (UInt32 i = 0; i < numItems; i++) + { + if (srcSizes == 0 || srcSizes[i] == NULL) + { + sizes.Add(0); + sizePointers.Add(NULL); + } + else + { + sizes.Add(*srcSizes[i]); + sizePointers.Add(&sizes.Back()); + } + } +} + + +void CCoder2::SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes) +{ + SetSizes(inSizes, InSizes, InSizePointers, NumInStreams); + SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams); +} + +////////////////////////////////////// +// CCoderMixer2MT + +HRESULT CCoderMixer2MT::SetBindInfo(const CBindInfo &bindInfo) +{ + _bindInfo = bindInfo; + _streamBinders.Clear(); + for (int i = 0; i < _bindInfo.BindPairs.Size(); i++) + { + _streamBinders.Add(CStreamBinder()); + RINOK(_streamBinders.Back().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) +{ + AddCoderCommon(); + _coders.Back().Coder = coder; +} + +void CCoderMixer2MT::AddCoder2(ICompressCoder2 *coder) +{ + AddCoderCommon(); + _coders.Back().Coder2 = coder; +} + + +void CCoderMixer2MT::ReInit() +{ + for (int i = 0; i < _streamBinders.Size(); i++) + _streamBinders[i].ReInit(); +} + + +HRESULT CCoderMixer2MT::Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams) +{ + /* + if (_coders.Size() != _bindInfo.Coders.Size()) + throw 0; + */ + int i; + for (i = 0; i < _coders.Size(); i++) + { + CCoder2 &coderInfo = _coders[i]; + const CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[i]; + coderInfo.InStreams.Clear(); + UInt32 j; + for (j = 0; j < coderStreamsInfo.NumInStreams; j++) + coderInfo.InStreams.Add(NULL); + coderInfo.OutStreams.Clear(); + for (j = 0; j < coderStreamsInfo.NumOutStreams; j++) + coderInfo.OutStreams.Add(NULL); + } + + for (i = 0; i < _bindInfo.BindPairs.Size(); i++) + { + const CBindPair &bindPair = _bindInfo.BindPairs[i]; + UInt32 inCoderIndex, inCoderStreamIndex; + UInt32 outCoderIndex, outCoderStreamIndex; + _bindInfo.FindInStream(bindPair.InIndex, inCoderIndex, inCoderStreamIndex); + _bindInfo.FindOutStream(bindPair.OutIndex, outCoderIndex, outCoderStreamIndex); + + _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) + { + const UInt32 kBufSize = 1 << 19; + inSetSize->SetInBufSize(inCoderStreamIndex, kBufSize); + outSetSize->SetOutBufSize(outCoderStreamIndex, kBufSize); + } + } + + for (i = 0; i < _bindInfo.InStreams.Size(); i++) + { + UInt32 inCoderIndex, inCoderStreamIndex; + _bindInfo.FindInStream(_bindInfo.InStreams[i], inCoderIndex, inCoderStreamIndex); + _coders[inCoderIndex].InStreams[inCoderStreamIndex] = inStreams[i]; + } + + for (i = 0; i < _bindInfo.OutStreams.Size(); i++) + { + UInt32 outCoderIndex, outCoderStreamIndex; + _bindInfo.FindOutStream(_bindInfo.OutStreams[i], outCoderIndex, outCoderStreamIndex); + _coders[outCoderIndex].OutStreams[outCoderStreamIndex] = outStreams[i]; + } + return S_OK; +} + +HRESULT CCoderMixer2MT::ReturnIfError(HRESULT code) +{ + for (int i = 0; i < _coders.Size(); i++) + if (_coders[i].Result == code) + return code; + return S_OK; +} + +STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams, + const UInt64 ** /* inSizes */, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 ** /* outSizes */, + UInt32 numOutStreams, + ICompressProgressInfo *progress) +{ + if (numInStreams != (UInt32)_bindInfo.InStreams.Size() || + numOutStreams != (UInt32)_bindInfo.OutStreams.Size()) + return E_INVALIDARG; + + Init(inStreams, outStreams); + + int i; + for (i = 0; i < _coders.Size(); i++) + if (i != _progressCoderIndex) + { + RINOK(_coders[i].Create()); + } + + for (i = 0; i < _coders.Size(); i++) + if (i != _progressCoderIndex) + _coders[i].Start(); + + _coders[_progressCoderIndex].Code(progress); + + for (i = 0; i < _coders.Size(); i++) + if (i != _progressCoderIndex) + _coders[i].WaitFinish(); + + 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 != E_FAIL && result != S_FALSE) + return result; + } + + RINOK(ReturnIfError(S_FALSE)); + + for (i = 0; i < _coders.Size(); i++) + { + HRESULT result = _coders[i].Result; + if (result != S_OK) + return result; + } + return S_OK; +} + +} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.h new file mode 100644 index 000000000..d1c7f4d07 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2MT.h @@ -0,0 +1,80 @@ +// CoderMixer2MT.h + +#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 { + +struct CCoder2: public CCoderInfo2, public CVirtThread +{ + HRESULT Result; + CObjectVector< CMyComPtr<ISequentialInStream> > InStreams; + CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams; + CRecordVector<ISequentialInStream*> InStreamPointers; + CRecordVector<ISequentialOutStream*> OutStreamPointers; + + CCoder2(UInt32 numInStreams, UInt32 numOutStreams); + void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes); + virtual void Execute(); + 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, + public CMyUnknownImp +{ + CBindInfo _bindInfo; + CObjectVector<CStreamBinder> _streamBinders; + int _progressCoderIndex; + + void AddCoderCommon(); + HRESULT Init(ISequentialInStream **inStreams, ISequentialOutStream **outStreams); + HRESULT ReturnIfError(HRESULT code); +public: + CObjectVector<CCoder2> _coders; + MY_UNKNOWN_IMP + + STDMETHOD(Code)(ISequentialInStream **inStreams, + const UInt64 **inSizes, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 **outSizes, + UInt32 numOutStreams, + ICompressProgressInfo *progress); + + HRESULT SetBindInfo(const CBindInfo &bindInfo); + void AddCoder(ICompressCoder *coder); + void AddCoder2(ICompressCoder2 *coder); + void SetProgressCoderIndex(int coderIndex) { _progressCoderIndex = coderIndex; } + + 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; } +}; + +} +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.cpp new file mode 100644 index 000000000..a59ce5fc0 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.cpp @@ -0,0 +1,239 @@ +// CoderMixer2ST.cpp + +#include "StdAfx.h" + +#include "CoderMixer2ST.h" + +namespace NCoderMixer2 { + +CCoderMixer2ST::CCoderMixer2ST() {} + +CCoderMixer2ST::~CCoderMixer2ST(){ } + +HRESULT CCoderMixer2ST::SetBindInfo(const CBindInfo &bindInfo) +{ + _bindInfo = bindInfo; + return S_OK; +} + +void CCoderMixer2ST::AddCoderCommon(bool isMain) +{ + const CCoderStreamsInfo &csi = _bindInfo.Coders[_coders.Size()]; + _coders.Add(CSTCoderInfo(csi.NumInStreams, csi.NumOutStreams, isMain)); +} + +void CCoderMixer2ST::AddCoder(ICompressCoder *coder, bool isMain) +{ + AddCoderCommon(isMain); + _coders.Back().Coder = coder; +} + +void CCoderMixer2ST::AddCoder2(ICompressCoder2 *coder, bool isMain) +{ + AddCoderCommon(isMain); + _coders.Back().Coder2 = coder; +} + +void CCoderMixer2ST::ReInit() { } + +HRESULT CCoderMixer2ST::GetInStream( + ISequentialInStream **inStreams, const UInt64 **inSizes, + UInt32 streamIndex, ISequentialInStream **inStreamRes) +{ + CMyComPtr<ISequentialInStream> seqInStream; + int i; + for(i = 0; i < _bindInfo.InStreams.Size(); i++) + if (_bindInfo.InStreams[i] == streamIndex) + { + seqInStream = inStreams[i]; + *inStreamRes = seqInStream.Detach(); + return S_OK; + } + int binderIndex = _bindInfo.FindBinderForInStream(streamIndex); + if (binderIndex < 0) + return E_INVALIDARG; + + UInt32 coderIndex, coderStreamIndex; + _bindInfo.FindOutStream(_bindInfo.BindPairs[binderIndex].OutIndex, + coderIndex, coderStreamIndex); + + CCoderInfo &coder = _coders[coderIndex]; + if (!coder.Coder) + return E_NOTIMPL; + coder.Coder.QueryInterface(IID_ISequentialInStream, &seqInStream); + if (!seqInStream) + return E_NOTIMPL; + + UInt32 startIndex = _bindInfo.GetCoderInStreamIndex(coderIndex); + + CMyComPtr<ICompressSetInStream> setInStream; + if (!coder.Coder) + return E_NOTIMPL; + coder.Coder.QueryInterface(IID_ICompressSetInStream, &setInStream); + if (!setInStream) + return E_NOTIMPL; + + 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) +{ + CMyComPtr<ISequentialOutStream> seqOutStream; + int i; + for(i = 0; i < _bindInfo.OutStreams.Size(); i++) + if (_bindInfo.OutStreams[i] == streamIndex) + { + seqOutStream = outStreams[i]; + *outStreamRes = seqOutStream.Detach(); + return S_OK; + } + int binderIndex = _bindInfo.FindBinderForOutStream(streamIndex); + if (binderIndex < 0) + return E_INVALIDARG; + + UInt32 coderIndex, coderStreamIndex; + _bindInfo.FindInStream(_bindInfo.BindPairs[binderIndex].InIndex, + coderIndex, coderStreamIndex); + + CCoderInfo &coder = _coders[coderIndex]; + if (!coder.Coder) + return E_NOTIMPL; + coder.Coder.QueryInterface(IID_ISequentialOutStream, &seqOutStream); + if (!seqOutStream) + return E_NOTIMPL; + + UInt32 startIndex = _bindInfo.GetCoderOutStreamIndex(coderIndex); + + CMyComPtr<ICompressSetOutStream> setOutStream; + if (!coder.Coder) + return E_NOTIMPL; + coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream); + if (!setOutStream) + return E_NOTIMPL; + + if (coder.NumOutStreams > 1) + return E_NOTIMPL; + for (i = 0; i < (int)coder.NumOutStreams; i++) + { + CMyComPtr<ISequentialOutStream> seqOutStream2; + RINOK(GetOutStream(outStreams, outSizes, startIndex + i, &seqOutStream2)); + RINOK(setOutStream->SetOutStream(seqOutStream2)); + } + *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) +{ + if (numInStreams != (UInt32)_bindInfo.InStreams.Size() || + numOutStreams != (UInt32)_bindInfo.OutStreams.Size()) + return E_INVALIDARG; + + // 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) + { + if (_mainCoderIndex >= 0) + return E_NOTIMPL; + _mainCoderIndex = i; + } + if (_mainCoderIndex < 0) + _mainCoderIndex = 0; + + // _mainCoderIndex = 0; + // _mainCoderIndex = _coders.Size() - 1; + CCoderInfo &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++) + { + CMyComPtr<ISequentialInStream> seqInStream; + RINOK(GetInStream(inStreams, inSizes, startInIndex + i, &seqInStream)); + seqInStreams.Add(seqInStream); + } + for (i = 0; i < (int)mainCoder.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 < (int)mainCoder.NumInStreams; i++) + seqInStreamsSpec.Add(seqInStreams[i]); + for (i = 0; i < (int)mainCoder.NumOutStreams; i++) + seqOutStreamsSpec.Add(seqOutStreams[i]); + + for (i = 0; i < _coders.Size(); i++) + { + if (i == _mainCoderIndex) + continue; + CCoderInfo &coder = _coders[i]; + CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize; + coder.Coder.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize); + if (setOutStreamSize) + { + RINOK(setOutStreamSize->SetOutStreamSize(coder.OutSizePointers[0])); + } + } + if (mainCoder.Coder) + { + RINOK(mainCoder.Coder->Code( + seqInStreamsSpec[0], seqOutStreamsSpec[0], + mainCoder.InSizePointers[0], mainCoder.OutSizePointers[0], + progress)); + } + else + { + RINOK(mainCoder.Coder2->Code( + &seqInStreamsSpec.Front(), + &mainCoder.InSizePointers.Front(), mainCoder.NumInStreams, + &seqOutStreamsSpec.Front(), + &mainCoder.OutSizePointers.Front(), mainCoder.NumOutStreams, + progress)); + } + CMyComPtr<IOutStreamFlush> flush; + seqOutStreams.Front().QueryInterface(IID_IOutStreamFlush, &flush); + if (flush) + return flush->Flush(); + return S_OK; +} + +/* +UInt64 CCoderMixer2ST::GetWriteProcessedSize(UInt32 binderIndex) const +{ + return _streamBinders[binderIndex].ProcessedSize; +} +*/ + +} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.h new file mode 100644 index 000000000..a4ea7e80d --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixer2ST.h @@ -0,0 +1,88 @@ +// CoderMixer2ST.h + +#ifndef __CODER_MIXER2_ST_H +#define __CODER_MIXER2_ST_H + +#include "CoderMixer2.h" +#include "../../../Common/MyCom.h" +#include "../../ICoder.h" + +namespace NCoderMixer2 { + +// SetBindInfo() +// for each coder +// { +// AddCoder[2]() +// } +// +// for each file +// { +// ReInit() +// for each coder +// { +// SetCoderInfo +// } +// SetProgressIndex(UInt32 coderIndex); +// Code +// } + +struct CSTCoderInfo: public CCoderInfo +{ + bool IsMain; + CSTCoderInfo(UInt32 numInStreams, UInt32 numOutStreams, bool isMain): + CCoderInfo(numInStreams, numOutStreams),IsMain(isMain) {} +}; + +class CCoderMixer2ST: + public ICompressCoder2, + public CCoderMixer2, + 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); +public: + STDMETHOD(Code)(ISequentialInStream **inStreams, + const UInt64 **inSizes, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 **outSizes, + UInt32 numOutStreams, + ICompressProgressInfo *progress); + + 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; + } + + // UInt64 GetWriteProcessedSize(UInt32 binderIndex) const; + +private: + CBindInfo _bindInfo; + CObjectVector<CSTCoderInfo> _coders; + int _mainCoderIndex; +public: + HRESULT SetBindInfo(const CBindInfo &bindInfo); + +}; + +} +#endif + diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.cpp new file mode 100644 index 000000000..f43d1612d --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.cpp @@ -0,0 +1,99 @@ +// CoderMixerMT.cpp + +#include "StdAfx.h" + +#include "CoderMixerMT.h" + +namespace NCoderMixer { + +void CCoder::Execute() { Code(NULL); } + +void CCoder::Code(ICompressProgressInfo *progress) +{ + Result = Coder->Code(InStream, OutStream, + InSizeAssigned ? &InSizeValue : NULL, + OutSizeAssigned ? &OutSizeValue : NULL, + progress); + InStream.Release(); + OutStream.Release(); +} + +void CCoderMixerMT::AddCoder(ICompressCoder *coder) +{ + _coders.Add(CCoder()); + _coders.Back().Coder = coder; +} + +void CCoderMixerMT::ReInit() +{ + for(int i = 0; i < _coders.Size(); i++) + _coders[i].ReInit(); +} + +HRESULT CCoderMixerMT::ReturnIfError(HRESULT code) +{ + for (int i = 0; i < _coders.Size(); i++) + if (_coders[i].Result == code) + return code; + return S_OK; +} + +STDMETHODIMP CCoderMixerMT::Code(ISequentialInStream *inStream, + ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, + ICompressProgressInfo *progress) +{ + _coders.Front().InStream = inStream; + int i; + _coders.Back().OutStream = outStream; + + for (i = 0; i < _coders.Size(); i++) + if (i != _progressCoderIndex) + { + RINOK(_coders[i].Create()); + } + + _streamBinders.Clear(); + for (i = 0; i + 1 < _coders.Size(); i++) + { + _streamBinders.Add(CStreamBinder()); + CStreamBinder &sb = _streamBinders[i]; + RINOK(sb.CreateEvents()); + sb.CreateStreams(&_coders[i + 1].InStream, &_coders[i].OutStream); + } + + for(i = 0; i < _streamBinders.Size(); i++) + _streamBinders[i].ReInit(); + + for (i = 0; i < _coders.Size(); i++) + if (i != _progressCoderIndex) + _coders[i].Start(); + + _coders[_progressCoderIndex].Code(progress); + + for (i = 0; i < _coders.Size(); i++) + if (i != _progressCoderIndex) + _coders[i].WaitFinish(); + + 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 != E_FAIL && result != S_FALSE) + return result; + } + + RINOK(ReturnIfError(S_FALSE)); + + for (i = 0; i < _coders.Size(); i++) + { + HRESULT result = _coders[i].Result; + if (result != S_OK) + return result; + } + return S_OK; +} + +} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.h new file mode 100644 index 000000000..c70e1829f --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CoderMixerMT.h @@ -0,0 +1,69 @@ +// CoderMixerMT.h + +#ifndef __CODER_MIXER_MT_H +#define __CODER_MIXER_MT_H + +#include "../../../Common/MyVector.h" +#include "../../../Common/MyCom.h" +#include "../../ICoder.h" +#include "../../Common/StreamBinder.h" +#include "../../Common/VirtThread.h" +#include "CoderMixer.h" + +namespace NCoderMixer { + +struct CCoder: public CCoderInfo, public CVirtThread +{ + HRESULT Result; + + virtual void Execute(); + void Code(ICompressProgressInfo *progress); +}; + +/* + for each coder + AddCoder() + SetProgressIndex(UInt32 coderIndex); + + for each file + { + ReInit() + for each coder + SetCoderInfo + Code + } +*/ + + +class CCoderMixerMT: + public ICompressCoder, + public CMyUnknownImp +{ + CObjectVector<CStreamBinder> _streamBinders; + int _progressCoderIndex; + + HRESULT ReturnIfError(HRESULT code); +public: + CObjectVector<CCoder> _coders; + MY_UNKNOWN_IMP + + STDMETHOD(Code)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); + + void AddCoder(ICompressCoder *coder); + void SetProgressCoderIndex(int coderIndex) { _progressCoderIndex = coderIndex; } + + void ReInit(); + void SetCoderInfo(UInt32 coderIndex, const UInt64 *inSize, const UInt64 *outSize) + { _coders[coderIndex].SetCoderInfo(inSize, outSize); } + + /* + UInt64 GetWriteProcessedSize(UInt32 binderIndex) const + { return _streamBinders[binderIndex].ProcessedSize; } + */ +}; + +} +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.cpp new file mode 100644 index 000000000..a974b54c7 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.cpp @@ -0,0 +1,15 @@ +// CrossThreadProgress.cpp + +#include "StdAfx.h" + +#include "CrossThreadProgress.h" + +STDMETHODIMP CCrossThreadProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + InSize = inSize; + OutSize = outSize; + ProgressEvent.Set(); + WaitEvent.Lock(); + return Result; +} + diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.h new file mode 100644 index 000000000..7e0b10538 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/CrossThreadProgress.h @@ -0,0 +1,37 @@ +// CrossThreadProgress.h + +#ifndef __CROSSTHREADPROGRESS_H +#define __CROSSTHREADPROGRESS_H + +#include "../../ICoder.h" +#include "../../../Windows/Synchronization.h" +#include "../../../Common/MyCom.h" + +class CCrossThreadProgress: + public ICompressProgressInfo, + public CMyUnknownImp +{ +public: + const UInt64 *InSize; + const UInt64 *OutSize; + HRESULT Result; + NWindows::NSynchronization::CAutoResetEvent ProgressEvent; + NWindows::NSynchronization::CAutoResetEvent WaitEvent; + + HRes Create() + { + RINOK(ProgressEvent.CreateIfNotCreated()); + return WaitEvent.CreateIfNotCreated(); + } + void Init() + { + ProgressEvent.Reset(); + WaitEvent.Reset(); + } + + MY_UNKNOWN_IMP + + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); +}; + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.cpp new file mode 100644 index 000000000..54bcfec11 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.cpp @@ -0,0 +1,22 @@ +// DummyOutStream.cpp + +#include "StdAfx.h" + +#include "DummyOutStream.h" + +STDMETHODIMP CDummyOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 realProcessedSize; + HRESULT result; + if(!_stream) + { + realProcessedSize = size; + result = S_OK; + } + else + result = _stream->Write(data, size, &realProcessedSize); + _size += realProcessedSize; + if(processedSize != NULL) + *processedSize = realProcessedSize; + return result; +} diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.h b/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.h new file mode 100644 index 000000000..13d5b62ca --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/DummyOutStream.h @@ -0,0 +1,24 @@ +// DummyOutStream.h + +#ifndef __DUMMYOUTSTREAM_H +#define __DUMMYOUTSTREAM_H + +#include "../../IStream.h" +#include "Common/MyCom.h" + +class CDummyOutStream: + public ISequentialOutStream, + public CMyUnknownImp +{ + CMyComPtr<ISequentialOutStream> _stream; + UInt64 _size; +public: + void SetStream(ISequentialOutStream *outStream) { _stream = outStream; } + void ReleaseStream() { _stream.Release(); } + void Init() { _size = 0; } + MY_UNKNOWN_IMP + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + UInt64 GetSize() const { return _size; } +}; + +#endif diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Common/FindSignature.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Common/FindSignature.cpp new file mode 100644 index 000000000..15aa6ceae --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Common/FindSignature.cpp @@ -0,0 +1,62 @@ +// FindSignature.cpp + +#include "StdAfx.h" + +#include "Common/Buffer.h" + +#include "FindSignature.h" + +#include "../../Common/StreamUtils.h" + +HRESULT FindSignatureInStream(ISequentialInStream *strea |