Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/Nsis/NsisDecode.cpp')
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Nsis/NsisDecode.cpp221
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;
}
}}