diff options
Diffstat (limited to 'CPP/7zip/Archive/Nsis/NsisDecode.cpp')
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Nsis/NsisDecode.cpp | 221 |
1 files changed, 178 insertions, 43 deletions
diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.cpp b/CPP/7zip/Archive/Nsis/NsisDecode.cpp index 0845f965..bb73d273 100755..100644 --- a/CPP/7zip/Archive/Nsis/NsisDecode.cpp +++ b/CPP/7zip/Archive/Nsis/NsisDecode.cpp @@ -2,66 +2,65 @@ #include "StdAfx.h" -#include "NsisDecode.h" +#include "../../../../C/CpuArch.h" -#include "../../Common/StreamUtils.h" +#include "NsisDecode.h" +#include "../../Common/CreateCoder.h" +#include "../../Common/FilterCoder.h" +#include "../../Common/LimitedStreams.h" #include "../../Common/MethodId.h" +#include "../../Compress/BcjCoder.h" #include "../../Compress/BZip2Decoder.h" #include "../../Compress/DeflateDecoder.h" -#include "../../Compress/LzmaDecoder.h" + +#define Get32(p) GetUi32(p) namespace NArchive { namespace NNsis { -static const CMethodId k_BCJ_X86 = 0x03030103; - -HRESULT CDecoder::Init( - DECL_EXTERNAL_CODECS_LOC_VARS - IInStream *inStream, NMethodType::EEnum method, bool thereIsFilterFlag, bool &useFilter) +HRESULT CDecoder::Init(ISequentialInStream *inStream, bool &useFilter) { useFilter = false; - CObjectVector< CMyComPtr<ISequentialInStream> > inStreams; if (_decoderInStream) - if (method != _method) + if (Method != _curMethod) Release(); - _method = method; + _curMethod = Method; if (!_codecInStream) { - switch (method) + switch (Method) { // case NMethodType::kCopy: return E_NOTIMPL; case NMethodType::kDeflate: _codecInStream = new NCompress::NDeflate::NDecoder::CNsisCOMCoder(); break; case NMethodType::kBZip2: _codecInStream = new NCompress::NBZip2::CNsisDecoder(); break; - case NMethodType::kLZMA: _codecInStream = new NCompress::NLzma::CDecoder(); break; + case NMethodType::kLZMA: + _lzmaDecoder = new NCompress::NLzma::CDecoder(); + _codecInStream = _lzmaDecoder; + break; default: return E_NOTIMPL; } } - if (thereIsFilterFlag) + if (FilterFlag) { - UInt32 processedSize; - BYTE flag; - RINOK(inStream->Read(&flag, 1, &processedSize)); - if (processedSize != 1) - return E_FAIL; + Byte flag; + RINOK(ReadStream_FALSE(inStream, &flag, 1)); if (flag > 1) return E_NOTIMPL; useFilter = (flag != 0); } - if (useFilter) + if (!useFilter) + _decoderInStream = _codecInStream; + else { if (!_filterInStream) { - CMyComPtr<ICompressCoder> coder; - RINOK(CreateCoder( - EXTERNAL_CODECS_LOC_VARS - k_BCJ_X86, coder, false)); - if (!coder) - return E_NOTIMPL; + CFilterCoder *coderSpec = new CFilterCoder; + CMyComPtr<ICompressCoder> coder = coderSpec; + coderSpec->Filter = new CBCJ_x86_Decoder(); coder.QueryInterface(IID_ISequentialInStream, &_filterInStream); if (!_filterInStream) return E_NOTIMPL; @@ -73,23 +72,13 @@ HRESULT CDecoder::Init( RINOK(setInStream->SetInStream(_codecInStream)); _decoderInStream = _filterInStream; } - else - _decoderInStream = _codecInStream; - if (method == NMethodType::kLZMA) + if (Method == NMethodType::kLZMA) { - CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties; - _codecInStream.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); - if (setDecoderProperties) - { - static const UInt32 kPropertiesSize = 5; - BYTE properties[kPropertiesSize]; - UInt32 processedSize; - RINOK(inStream->Read(properties, kPropertiesSize, &processedSize)); - if (processedSize != kPropertiesSize) - return E_FAIL; - RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)properties, kPropertiesSize)); - } + const unsigned kPropsSize = LZMA_PROPS_SIZE; + Byte props[kPropsSize]; + RINOK(ReadStream_FALSE(inStream, props, kPropsSize)); + RINOK(_lzmaDecoder->SetDecoderProperties2((const Byte *)props, kPropsSize)); } { @@ -122,9 +111,155 @@ HRESULT CDecoder::Init( return S_OK; } -HRESULT CDecoder::Read(void *data, size_t *processedSize) +static const UInt32 kMask_IsCompressed = (UInt32)1 << 31; + +HRESULT CDecoder::SetToPos(UInt64 pos, ICompressProgressInfo *progress) { - return ReadStream(_decoderInStream, data, processedSize);; + if (StreamPos > pos) + return E_FAIL; + UInt64 inSizeStart = 0; + if (_lzmaDecoder) + inSizeStart = _lzmaDecoder->GetInputProcessedSize(); + UInt64 offset = 0; + while (StreamPos < pos) + { + size_t size = (size_t)MyMin(pos - StreamPos, (UInt64)Buffer.Size()); + RINOK(Read(Buffer, &size)); + if (size == 0) + return S_FALSE; + StreamPos += size; + offset += size; + + UInt64 inSize = 0; + if (_lzmaDecoder) + inSize = _lzmaDecoder->GetInputProcessedSize() - inSizeStart; + RINOK(progress->SetRatioInfo(&inSize, &offset)); + } + return S_OK; +} + +HRESULT CDecoder::Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize, + ISequentialOutStream *realOutStream, ICompressProgressInfo *progress, + UInt32 &packSizeRes, UInt32 &unpackSizeRes) +{ + CLimitedSequentialInStream *limitedStreamSpec = NULL; + CMyComPtr<ISequentialInStream> limitedStream; + packSizeRes = 0; + unpackSizeRes = 0; + + if (Solid) + { + Byte temp[4]; + size_t processedSize = 4; + RINOK(Read(temp, &processedSize)); + if (processedSize != 4) + return S_FALSE; + StreamPos += processedSize; + UInt32 size = Get32(temp); + if (unpackSizeDefined && size != unpackSize) + return S_FALSE; + unpackSize = size; + unpackSizeDefined = true; + } + else + { + Byte temp[4]; + RINOK(ReadStream_FALSE(InputStream, temp, 4)); + StreamPos += 4; + UInt32 size = Get32(temp); + + if ((size & kMask_IsCompressed) == 0) + { + if (unpackSizeDefined && size != unpackSize) + return S_FALSE; + packSizeRes = size; + if (outBuf) + outBuf->Alloc(size); + + UInt64 offset = 0; + + while (size > 0) + { + UInt32 curSize = (UInt32)MyMin((size_t)size, Buffer.Size()); + UInt32 processedSize; + RINOK(InputStream->Read(Buffer, curSize, &processedSize)); + if (processedSize == 0) + return S_FALSE; + if (outBuf) + memcpy((Byte *)*outBuf + (size_t)offset, Buffer, processedSize); + offset += processedSize; + size -= processedSize; + StreamPos += processedSize; + unpackSizeRes += processedSize; + if (realOutStream) + RINOK(WriteStream(realOutStream, Buffer, processedSize)); + RINOK(progress->SetRatioInfo(&offset, &offset)); + } + + return S_OK; + } + + size &= ~kMask_IsCompressed; + packSizeRes = size; + limitedStreamSpec = new CLimitedSequentialInStream; + limitedStream = limitedStreamSpec; + limitedStreamSpec->SetStream(InputStream); + limitedStreamSpec->Init(size); + { + bool useFilter; + RINOK(Init(limitedStream, useFilter)); + } + } + + if (outBuf) + { + if (!unpackSizeDefined) + return S_FALSE; + outBuf->Alloc(unpackSize); + } + + UInt64 inSizeStart = 0; + if (_lzmaDecoder) + inSizeStart = _lzmaDecoder->GetInputProcessedSize(); + + // we don't allow files larger than 4 GB; + if (!unpackSizeDefined) + unpackSize = 0xFFFFFFFF; + UInt32 offset = 0; + + for (;;) + { + size_t rem = unpackSize - offset; + if (rem == 0) + break; + size_t size = Buffer.Size(); + if (size > rem) + size = rem; + RINOK(Read(Buffer, &size)); + if (size == 0) + { + if (unpackSizeDefined) + return S_FALSE; + break; + } + if (outBuf) + memcpy((Byte *)*outBuf + (size_t)offset, Buffer, size); + StreamPos += size; + offset += (UInt32)size; + + UInt64 inSize = 0; // it can be improved: we need inSize for Deflate and BZip2 too. + if (_lzmaDecoder) + inSize = _lzmaDecoder->GetInputProcessedSize() - inSizeStart; + if (Solid) + packSizeRes = (UInt32)inSize; + unpackSizeRes += (UInt32)size; + + UInt64 outSize = offset; + RINOK(progress->SetRatioInfo(&inSize, &outSize)); + if (realOutStream) + RINOK(WriteStream(realOutStream, Buffer, size)); + } + return S_OK; } }} |