mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-08 14:07:00 -06:00
17.01
This commit is contained in:
@@ -7,8 +7,11 @@
|
||||
#include "../../Common/ComTry.h"
|
||||
#include "../../Common/Defs.h"
|
||||
#include "../../Common/IntToString.h"
|
||||
#include "../../Common/MyBuffer.h"
|
||||
#include "../../Common/StringToInt.h"
|
||||
|
||||
#include "../../Windows/PropVariant.h"
|
||||
#include "../../Windows/System.h"
|
||||
|
||||
#include "../Common/CWrappers.h"
|
||||
#include "../Common/ProgressUtils.h"
|
||||
@@ -33,9 +36,19 @@ namespace NXz {
|
||||
#define k_LZMA2_Name "LZMA2"
|
||||
|
||||
|
||||
struct CBlockInfo
|
||||
{
|
||||
unsigned StreamFlags;
|
||||
UInt64 PackPos;
|
||||
UInt64 PackSize; // pure value from Index record, it doesn't include pad zeros
|
||||
UInt64 UnpackPos;
|
||||
};
|
||||
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IArchiveOpenSeq,
|
||||
public IInArchiveGetStream,
|
||||
#ifndef EXTRACT_ONLY
|
||||
public IOutArchive,
|
||||
public ISetProperties,
|
||||
@@ -48,9 +61,7 @@ class CHandler:
|
||||
bool _isArc;
|
||||
bool _needSeekToStart;
|
||||
bool _phySize_Defined;
|
||||
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CMyComPtr<ISequentialInStream> _seqStream;
|
||||
bool _firstBlockWasRead;
|
||||
|
||||
AString _methodsString;
|
||||
|
||||
@@ -58,8 +69,20 @@ class CHandler:
|
||||
|
||||
UInt32 _filterId;
|
||||
|
||||
UInt64 _numSolidBytes;
|
||||
|
||||
HRESULT SetSolidFromString(const UString &s);
|
||||
HRESULT SetSolidFromPROPVARIANT(const PROPVARIANT &value);
|
||||
HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
|
||||
|
||||
void InitSolid()
|
||||
{
|
||||
_numSolidBytes = XZ_PROPS__BLOCK_SIZE__AUTO;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
InitSolid();
|
||||
_filterId = 0;
|
||||
CMultiMethodProps::Init();
|
||||
}
|
||||
@@ -83,6 +106,7 @@ class CHandler:
|
||||
public:
|
||||
MY_QUERYINTERFACE_BEGIN2(IInArchive)
|
||||
MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq)
|
||||
MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream)
|
||||
#ifndef EXTRACT_ONLY
|
||||
MY_QUERYINTERFACE_ENTRY(IOutArchive)
|
||||
MY_QUERYINTERFACE_ENTRY(ISetProperties)
|
||||
@@ -92,22 +116,45 @@ public:
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
INTERFACE_IOutArchive(;)
|
||||
STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
|
||||
#endif
|
||||
|
||||
size_t _blocksArraySize;
|
||||
CBlockInfo *_blocks;
|
||||
UInt64 _maxBlocksSize;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CMyComPtr<ISequentialInStream> _seqStream;
|
||||
|
||||
CXzBlock _firstBlock;
|
||||
|
||||
CHandler();
|
||||
~CHandler();
|
||||
|
||||
HRESULT SeekToPackPos(UInt64 pos)
|
||||
{
|
||||
return _stream->Seek(pos, STREAM_SEEK_SET, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
CHandler::CHandler()
|
||||
|
||||
CHandler::CHandler():
|
||||
_blocks(NULL),
|
||||
_blocksArraySize(0)
|
||||
{
|
||||
#ifndef EXTRACT_ONLY
|
||||
Init();
|
||||
#endif
|
||||
}
|
||||
|
||||
CHandler::~CHandler()
|
||||
{
|
||||
MyFree(_blocks);
|
||||
}
|
||||
|
||||
|
||||
static const Byte kProps[] =
|
||||
{
|
||||
@@ -120,7 +167,9 @@ static const Byte kArcProps[] =
|
||||
{
|
||||
kpidMethod,
|
||||
kpidNumStreams,
|
||||
kpidNumBlocks
|
||||
kpidNumBlocks,
|
||||
kpidClusterSize,
|
||||
kpidCharacts
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
@@ -177,7 +226,7 @@ static const CMethodNamePair g_NamePairs[] =
|
||||
{ XZ_ID_LZMA2, "LZMA2" }
|
||||
};
|
||||
|
||||
static AString GetMethodString(const CXzFilter &f)
|
||||
static void AddMethodString(AString &s, const CXzFilter &f)
|
||||
{
|
||||
const char *p = NULL;
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(g_NamePairs); i++)
|
||||
@@ -193,7 +242,7 @@ static AString GetMethodString(const CXzFilter &f)
|
||||
p = temp;
|
||||
}
|
||||
|
||||
AString s (p);
|
||||
s += p;
|
||||
|
||||
if (f.propsSize > 0)
|
||||
{
|
||||
@@ -210,13 +259,6 @@ static AString GetMethodString(const CXzFilter &f)
|
||||
s += ']';
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static void AddString(AString &dest, const AString &src)
|
||||
{
|
||||
dest.Add_Space_if_NotEmpty();
|
||||
dest += src;
|
||||
}
|
||||
|
||||
static const char * const kChecks[] =
|
||||
@@ -239,27 +281,24 @@ static const char * const kChecks[] =
|
||||
, NULL
|
||||
};
|
||||
|
||||
static AString GetCheckString(const CXzs &xzs)
|
||||
static void AddCheckString(AString &s, const CXzs &xzs)
|
||||
{
|
||||
size_t i;
|
||||
UInt32 mask = 0;
|
||||
for (i = 0; i < xzs.num; i++)
|
||||
mask |= ((UInt32)1 << XzFlags_GetCheckType(xzs.streams[i].flags));
|
||||
AString s;
|
||||
for (i = 0; i <= XZ_CHECK_MASK; i++)
|
||||
if (((mask >> i) & 1) != 0)
|
||||
{
|
||||
AString s2;
|
||||
s.Add_Space_if_NotEmpty();
|
||||
if (kChecks[i])
|
||||
s2 = kChecks[i];
|
||||
s += kChecks[i];
|
||||
else
|
||||
{
|
||||
s2 = "Check-";
|
||||
s2.Add_UInt32((UInt32)i);
|
||||
s += "Check-";
|
||||
s.Add_UInt32((UInt32)i);
|
||||
}
|
||||
AddString(s, s2);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
@@ -272,11 +311,26 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
case kpidNumStreams: if (_stat.NumStreams_Defined) prop = _stat.NumStreams; break;
|
||||
case kpidNumBlocks: if (_stat.NumBlocks_Defined) prop = _stat.NumBlocks; break;
|
||||
case kpidUnpackSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break;
|
||||
case kpidClusterSize: if (_stat.NumBlocks_Defined && _stat.NumBlocks > 1) prop = _maxBlocksSize; break;
|
||||
case kpidCharacts:
|
||||
if (_firstBlockWasRead)
|
||||
{
|
||||
AString s;
|
||||
if (XzBlock_HasPackSize(&_firstBlock))
|
||||
s.Add_OptSpaced("BlockPackSize");
|
||||
if (XzBlock_HasUnpackSize(&_firstBlock))
|
||||
s.Add_OptSpaced("BlockUnpackSize");
|
||||
if (!s.IsEmpty())
|
||||
prop = s;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
|
||||
case kpidErrorFlags:
|
||||
{
|
||||
UInt32 v = 0;
|
||||
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
|
||||
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
|
||||
if (_stat.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
|
||||
if (_stat.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
|
||||
if (_stat.HeadersError) v |= kpv_ErrorFlags_HeadersError;
|
||||
@@ -284,6 +338,13 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
if (_stat.DataError) v |= kpv_ErrorFlags_DataError;
|
||||
if (_stat.CrcError) v |= kpv_ErrorFlags_CrcError;
|
||||
prop = v;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidMainSubfile:
|
||||
{
|
||||
// if (_blocks) prop = (UInt32)0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
@@ -409,9 +470,15 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal
|
||||
SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.vt, &isIndex, &headerSizeRes);
|
||||
if (res2 == SZ_OK && !isIndex)
|
||||
{
|
||||
_firstBlockWasRead = true;
|
||||
_firstBlock = block;
|
||||
|
||||
unsigned numFilters = XzBlock_GetNumFilters(&block);
|
||||
for (unsigned i = 0; i < numFilters; i++)
|
||||
AddString(_methodsString, GetMethodString(block.filters[i]));
|
||||
{
|
||||
_methodsString.Add_Space_if_NotEmpty();
|
||||
AddMethodString(_methodsString, block.filters[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -422,7 +489,7 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal
|
||||
RINOK(callback->SetTotal(NULL, &_stat.PhySize));
|
||||
}
|
||||
|
||||
CSeekInStreamWrap inStreamImp;;
|
||||
CSeekInStreamWrap inStreamImp;
|
||||
|
||||
inStreamImp.Init(inStream);
|
||||
|
||||
@@ -460,7 +527,64 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal
|
||||
_stat.NumBlocks = Xzs_GetNumBlocks(&xzs.p);
|
||||
_stat.NumBlocks_Defined = true;
|
||||
|
||||
AddString(_methodsString, GetCheckString(xzs.p));
|
||||
AddCheckString(_methodsString, xzs.p);
|
||||
|
||||
const size_t numBlocks = (size_t)_stat.NumBlocks + 1;
|
||||
const size_t bytesAlloc = numBlocks * sizeof(CBlockInfo);
|
||||
|
||||
if (bytesAlloc / sizeof(CBlockInfo) == _stat.NumBlocks + 1)
|
||||
{
|
||||
_blocks = (CBlockInfo *)MyAlloc(bytesAlloc);
|
||||
if (_blocks)
|
||||
{
|
||||
unsigned blockIndex = 0;
|
||||
UInt64 unpackPos = 0;
|
||||
|
||||
for (size_t si = xzs.p.num; si != 0;)
|
||||
{
|
||||
si--;
|
||||
const CXzStream &str = xzs.p.streams[si];
|
||||
UInt64 packPos = str.startOffset + XZ_STREAM_HEADER_SIZE;
|
||||
|
||||
for (size_t bi = 0; bi < str.numBlocks; bi++)
|
||||
{
|
||||
const CXzBlockSizes &bs = str.blocks[bi];
|
||||
const UInt64 packSizeAligned = bs.totalSize + ((0 - (unsigned)bs.totalSize) & 3);
|
||||
|
||||
if (bs.unpackSize != 0)
|
||||
{
|
||||
if (blockIndex >= _stat.NumBlocks)
|
||||
return E_FAIL;
|
||||
|
||||
CBlockInfo &block = _blocks[blockIndex++];
|
||||
block.StreamFlags = str.flags;
|
||||
block.PackSize = bs.totalSize; // packSizeAligned;
|
||||
block.PackPos = packPos;
|
||||
block.UnpackPos = unpackPos;
|
||||
}
|
||||
packPos += packSizeAligned;
|
||||
unpackPos += bs.unpackSize;
|
||||
if (_maxBlocksSize < bs.unpackSize)
|
||||
_maxBlocksSize = bs.unpackSize;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (blockIndex != _stat.NumBlocks)
|
||||
{
|
||||
// there are Empty blocks;
|
||||
}
|
||||
*/
|
||||
if (_stat.OutSize != unpackPos)
|
||||
return E_FAIL;
|
||||
CBlockInfo &block = _blocks[blockIndex++];
|
||||
block.StreamFlags = 0;
|
||||
block.PackSize = 0;
|
||||
block.PackPos = 0;
|
||||
block.UnpackPos = unpackPos;
|
||||
_blocksArraySize = blockIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -474,6 +598,8 @@ HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCal
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
@@ -499,39 +625,297 @@ STDMETHODIMP CHandler::Close()
|
||||
|
||||
_isArc = false;
|
||||
_needSeekToStart = false;
|
||||
|
||||
_phySize_Defined = false;
|
||||
_firstBlockWasRead = false;
|
||||
|
||||
_methodsString.Empty();
|
||||
_stream.Release();
|
||||
_seqStream.Release();
|
||||
|
||||
MyFree(_blocks);
|
||||
_blocks = NULL;
|
||||
_blocksArraySize = 0;
|
||||
_maxBlocksSize = 0;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
struct CXzUnpackerCPP2
|
||||
{
|
||||
Byte *InBuf;
|
||||
// Byte *OutBuf;
|
||||
CXzUnpacker p;
|
||||
|
||||
CXzUnpackerCPP2();
|
||||
~CXzUnpackerCPP2();
|
||||
};
|
||||
|
||||
CXzUnpackerCPP2::CXzUnpackerCPP2(): InBuf(NULL)
|
||||
// , OutBuf(NULL)
|
||||
{
|
||||
XzUnpacker_Construct(&p, &g_Alloc);
|
||||
}
|
||||
|
||||
CXzUnpackerCPP2::~CXzUnpackerCPP2()
|
||||
{
|
||||
XzUnpacker_Free(&p);
|
||||
MidFree(InBuf);
|
||||
// MidFree(OutBuf);
|
||||
}
|
||||
|
||||
|
||||
class CInStream:
|
||||
public IInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
UInt64 _virtPos;
|
||||
UInt64 Size;
|
||||
UInt64 _cacheStartPos;
|
||||
size_t _cacheSize;
|
||||
CByteBuffer _cache;
|
||||
// UInt64 _startPos;
|
||||
CXzUnpackerCPP2 xz;
|
||||
|
||||
void InitAndSeek()
|
||||
{
|
||||
_virtPos = 0;
|
||||
_cacheStartPos = 0;
|
||||
_cacheSize = 0;
|
||||
// _startPos = startPos;
|
||||
}
|
||||
|
||||
CHandler *_handlerSpec;
|
||||
CMyComPtr<IUnknown> _handler;
|
||||
|
||||
MY_UNKNOWN_IMP1(IInStream)
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
|
||||
|
||||
~CInStream();
|
||||
};
|
||||
|
||||
|
||||
CInStream::~CInStream()
|
||||
{
|
||||
// _cache.Free();
|
||||
}
|
||||
|
||||
|
||||
size_t FindBlock(const CBlockInfo *blocks, size_t numBlocks, UInt64 pos)
|
||||
{
|
||||
size_t left = 0, right = numBlocks;
|
||||
for (;;)
|
||||
{
|
||||
size_t mid = (left + right) / 2;
|
||||
if (mid == left)
|
||||
return left;
|
||||
if (pos < blocks[mid].UnpackPos)
|
||||
right = mid;
|
||||
else
|
||||
left = mid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static HRESULT DecodeBlock(CXzUnpackerCPP2 &xzu,
|
||||
ISequentialInStream *seqInStream,
|
||||
unsigned streamFlags,
|
||||
UInt64 packSize, // pure size from Index record, it doesn't include pad zeros
|
||||
size_t unpackSize, Byte *dest
|
||||
// , ICompressProgressInfo *progress
|
||||
)
|
||||
{
|
||||
const size_t kInBufSize = (size_t)1 << 16;
|
||||
|
||||
XzUnpacker_Init(&xzu.p);
|
||||
|
||||
if (!xzu.InBuf)
|
||||
{
|
||||
xzu.InBuf = (Byte *)MidAlloc(kInBufSize);
|
||||
if (!xzu.InBuf)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
xzu.p.streamFlags = (UInt16)streamFlags;
|
||||
XzUnpacker_PrepareToRandomBlockDecoding(&xzu.p);
|
||||
|
||||
const UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3);
|
||||
UInt64 packRem = packSizeAligned;
|
||||
|
||||
UInt32 inSize = 0;
|
||||
SizeT inPos = 0;
|
||||
SizeT outPos = 0;
|
||||
|
||||
HRESULT readRes = S_OK;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (inPos == inSize && readRes == S_OK)
|
||||
{
|
||||
inPos = 0;
|
||||
inSize = 0;
|
||||
UInt32 rem = kInBufSize;
|
||||
if (rem > packRem)
|
||||
rem = (UInt32)packRem;
|
||||
if (rem != 0)
|
||||
readRes = seqInStream->Read(xzu.InBuf, rem, &inSize);
|
||||
}
|
||||
|
||||
SizeT inLen = inSize - inPos;
|
||||
SizeT outLen = unpackSize - outPos;
|
||||
|
||||
ECoderStatus status;
|
||||
|
||||
SRes res = XzUnpacker_Code(&xzu.p,
|
||||
dest + outPos, &outLen,
|
||||
xzu.InBuf + inPos, &inLen,
|
||||
CODER_FINISH_END, &status);
|
||||
|
||||
// return E_OUTOFMEMORY;
|
||||
// res = SZ_ERROR_CRC;
|
||||
|
||||
if (res != SZ_OK)
|
||||
{
|
||||
if (res == SZ_ERROR_CRC)
|
||||
return S_FALSE;
|
||||
return SResToHRESULT(res);
|
||||
}
|
||||
|
||||
inPos += inLen;
|
||||
outPos += outLen;
|
||||
|
||||
packRem -= inLen;
|
||||
|
||||
Bool blockFinished = XzUnpacker_IsBlockFinished(&xzu.p);
|
||||
|
||||
if ((inLen == 0 && outLen == 0) || blockFinished)
|
||||
{
|
||||
if (packRem != 0 || !blockFinished || unpackSize != outPos)
|
||||
return S_FALSE;
|
||||
if (XzUnpacker_GetPackSizeForIndex(&xzu.p) != packSize)
|
||||
return S_FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
if (size == 0)
|
||||
return S_OK;
|
||||
|
||||
{
|
||||
if (_virtPos >= Size)
|
||||
return S_OK; // (Size == _virtPos) ? S_OK: E_FAIL;
|
||||
{
|
||||
UInt64 rem = Size - _virtPos;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
}
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
return S_OK;
|
||||
|
||||
if (_virtPos < _cacheStartPos || _virtPos >= _cacheStartPos + _cacheSize)
|
||||
{
|
||||
size_t bi = FindBlock(_handlerSpec->_blocks, _handlerSpec->_blocksArraySize, _virtPos);
|
||||
const CBlockInfo &block = _handlerSpec->_blocks[bi];
|
||||
const UInt64 unpackSize = _handlerSpec->_blocks[bi + 1].UnpackPos - block.UnpackPos;
|
||||
if (_cache.Size() < unpackSize)
|
||||
return E_FAIL;
|
||||
|
||||
_cacheSize = 0;
|
||||
|
||||
RINOK(_handlerSpec->SeekToPackPos(block.PackPos));
|
||||
RINOK(DecodeBlock(xz, _handlerSpec->_seqStream, block.StreamFlags, block.PackSize,
|
||||
(size_t)unpackSize, _cache));
|
||||
_cacheStartPos = block.UnpackPos;
|
||||
_cacheSize = (size_t)unpackSize;
|
||||
}
|
||||
|
||||
{
|
||||
size_t offset = (size_t)(_virtPos - _cacheStartPos);
|
||||
size_t rem = _cacheSize - offset;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
memcpy(data, _cache + offset, size);
|
||||
_virtPos += size;
|
||||
if (processedSize)
|
||||
*processedSize = size;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
|
||||
{
|
||||
switch (seekOrigin)
|
||||
{
|
||||
case STREAM_SEEK_SET: break;
|
||||
case STREAM_SEEK_CUR: offset += _virtPos; break;
|
||||
case STREAM_SEEK_END: offset += Size; break;
|
||||
default: return STG_E_INVALIDFUNCTION;
|
||||
}
|
||||
if (offset < 0)
|
||||
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
|
||||
_virtPos = offset;
|
||||
if (newPosition)
|
||||
*newPosition = offset;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class CSeekToSeqStream:
|
||||
public IInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
CMyComPtr<ISequentialInStream> Stream;
|
||||
MY_UNKNOWN_IMP1(IInStream)
|
||||
static const UInt64 kMaxBlockSize_for_GetStream = (UInt64)1 << 40;
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
|
||||
};
|
||||
|
||||
STDMETHODIMP CSeekToSeqStream::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
return Stream->Read(data, size, processedSize);
|
||||
COM_TRY_BEGIN
|
||||
|
||||
*stream = NULL;
|
||||
|
||||
if (index != 0)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!_stat.UnpackSize_Defined
|
||||
|| _maxBlocksSize > kMaxBlockSize_for_GetStream
|
||||
|| _maxBlocksSize != (size_t)_maxBlocksSize)
|
||||
return S_FALSE;
|
||||
|
||||
UInt64 physSize = (UInt64)(sizeof(size_t)) << 29;
|
||||
bool ramSize_Defined = NSystem::GetRamSize(physSize);
|
||||
if (ramSize_Defined)
|
||||
{
|
||||
if (_maxBlocksSize > physSize / 4)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
CInStream *spec = new CInStream;
|
||||
CMyComPtr<ISequentialInStream> specStream = spec;
|
||||
spec->_cache.Alloc((size_t)_maxBlocksSize);
|
||||
spec->_handlerSpec = this;
|
||||
spec->_handler = (IInArchive *)this;
|
||||
spec->Size = _stat.OutSize;
|
||||
spec->InitAndSeek();
|
||||
|
||||
*stream = specStream.Detach();
|
||||
return S_OK;
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CSeekToSeqStream::Seek(Int64, UInt32, UInt64 *) { return E_NOTIMPL; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -584,6 +968,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
|
||||
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
|
||||
@@ -592,16 +978,15 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
|
||||
if (numItems == 0)
|
||||
{
|
||||
CSeqOutStreamWrap seqOutStream;
|
||||
|
||||
seqOutStream.Init(outStream);
|
||||
SRes res = Xz_EncodeEmpty(&seqOutStream.vt);
|
||||
return SResToHRESULT(res);
|
||||
@@ -641,82 +1026,76 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
|
||||
NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder;
|
||||
CMyComPtr<ICompressCoder> encoder = encoderSpec;
|
||||
CLzma2EncProps &lzma2Props = encoderSpec->_lzma2Props;
|
||||
|
||||
CXzProps &xzProps = encoderSpec->xzProps;
|
||||
CLzma2EncProps &lzma2Props = xzProps.lzma2Props;
|
||||
|
||||
lzma2Props.lzmaProps.level = GetLevel();
|
||||
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
RINOK(updateCallback->GetStream(0, &fileInStream));
|
||||
|
||||
xzProps.reduceSize = size;
|
||||
/*
|
||||
{
|
||||
NCOM::CPropVariant prop = (UInt64)size;
|
||||
RINOK(encoderSpec->SetCoderProp(NCoderPropID::kReduceSize, prop));
|
||||
}
|
||||
*/
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
xzProps.numTotalThreads = _numThreads;
|
||||
#endif
|
||||
|
||||
xzProps.blockSize = _numSolidBytes;
|
||||
if (_numSolidBytes == XZ_PROPS__BLOCK_SIZE__SOLID)
|
||||
{
|
||||
xzProps.lzma2Props.blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID;
|
||||
}
|
||||
|
||||
RINOK(encoderSpec->SetCheckSize(_crcSize));
|
||||
|
||||
{
|
||||
CXzFilterProps &filter = xzProps.filterProps;
|
||||
|
||||
if (_filterId == XZ_ID_Delta)
|
||||
{
|
||||
bool deltaDefined = false;
|
||||
FOR_VECTOR (j, _filterMethod.Props)
|
||||
{
|
||||
const CProp &prop = _filterMethod.Props[j];
|
||||
if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4)
|
||||
{
|
||||
UInt32 delta = (UInt32)prop.Value.ulVal;
|
||||
if (delta < 1 || delta > 256)
|
||||
return E_INVALIDARG;
|
||||
filter.delta = delta;
|
||||
deltaDefined = true;
|
||||
}
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (!deltaDefined)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
filter.id = _filterId;
|
||||
}
|
||||
|
||||
FOR_VECTOR (i, _methods)
|
||||
{
|
||||
COneMethodInfo &m = _methods[i];
|
||||
|
||||
/*
|
||||
SetGlobalLevelTo(m);
|
||||
#ifndef _7ZIP_ST
|
||||
CMultiMethodProps::SetMethodThreads(m, _numThreads);
|
||||
#endif
|
||||
*/
|
||||
|
||||
FOR_VECTOR (j, m.Props)
|
||||
{
|
||||
FOR_VECTOR (j, m.Props)
|
||||
{
|
||||
const CProp &prop = m.Props[j];
|
||||
RINOK(encoderSpec->SetCoderProp(prop.Id, prop.Value));
|
||||
}
|
||||
const CProp &prop = m.Props[j];
|
||||
RINOK(encoderSpec->SetCoderProp(prop.Id, prop.Value));
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
lzma2Props.numTotalThreads = _numThreads;
|
||||
#endif
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
RINOK(updateCallback->GetStream(0, &fileInStream));
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(updateCallback, true);
|
||||
|
||||
CXzProps &xzProps = encoderSpec->xzProps;
|
||||
CXzFilterProps &filter = encoderSpec->filter;
|
||||
|
||||
XzProps_Init(&xzProps);
|
||||
XzFilterProps_Init(&filter);
|
||||
|
||||
xzProps.lzma2Props = &lzma2Props;
|
||||
xzProps.filterProps = (_filterId != 0 ? &filter : NULL);
|
||||
switch (_crcSize)
|
||||
{
|
||||
case 0: xzProps.checkId = XZ_CHECK_NO; break;
|
||||
case 4: xzProps.checkId = XZ_CHECK_CRC32; break;
|
||||
case 8: xzProps.checkId = XZ_CHECK_CRC64; break;
|
||||
case 32: xzProps.checkId = XZ_CHECK_SHA256; break;
|
||||
default: return E_INVALIDARG;
|
||||
}
|
||||
filter.id = _filterId;
|
||||
if (_filterId == XZ_ID_Delta)
|
||||
{
|
||||
bool deltaDefined = false;
|
||||
FOR_VECTOR (j, _filterMethod.Props)
|
||||
{
|
||||
const CProp &prop = _filterMethod.Props[j];
|
||||
if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4)
|
||||
{
|
||||
UInt32 delta = (UInt32)prop.Value.ulVal;
|
||||
if (delta < 1 || delta > 256)
|
||||
return E_INVALIDARG;
|
||||
filter.delta = delta;
|
||||
deltaDefined = true;
|
||||
}
|
||||
}
|
||||
if (!deltaDefined)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
return encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress);
|
||||
}
|
||||
|
||||
@@ -747,11 +1126,83 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
}
|
||||
|
||||
|
||||
HRESULT CHandler::SetSolidFromString(const UString &s)
|
||||
{
|
||||
UString s2 = s;
|
||||
s2.MakeLower_Ascii();
|
||||
|
||||
{
|
||||
const wchar_t *start = ((const wchar_t *)s2);
|
||||
const wchar_t *end;
|
||||
UInt64 v = ConvertStringToUInt64(start, &end);
|
||||
if (start == end)
|
||||
return E_INVALIDARG;
|
||||
if ((unsigned)(end - start) + 1 != s2.Len())
|
||||
return E_INVALIDARG;
|
||||
wchar_t c = *end;
|
||||
{
|
||||
unsigned numBits;
|
||||
switch (c)
|
||||
{
|
||||
case 'b': numBits = 0; break;
|
||||
case 'k': numBits = 10; break;
|
||||
case 'm': numBits = 20; break;
|
||||
case 'g': numBits = 30; break;
|
||||
case 't': numBits = 40; break;
|
||||
default: return E_INVALIDARG;
|
||||
}
|
||||
_numSolidBytes = (v << numBits);
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value)
|
||||
{
|
||||
bool isSolid;
|
||||
switch (value.vt)
|
||||
{
|
||||
case VT_EMPTY: isSolid = true; break;
|
||||
case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
|
||||
case VT_BSTR:
|
||||
if (StringToBool(value.bstrVal, isSolid))
|
||||
break;
|
||||
return SetSolidFromString(value.bstrVal);
|
||||
default: return E_INVALIDARG;
|
||||
}
|
||||
_numSolidBytes = (isSolid ? XZ_PROPS__BLOCK_SIZE__SOLID : XZ_PROPS__BLOCK_SIZE__AUTO);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
|
||||
{
|
||||
UString name = nameSpec;
|
||||
name.MakeLower_Ascii();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (name[0] == L's')
|
||||
{
|
||||
name.Delete(0);
|
||||
if (name.IsEmpty())
|
||||
return SetSolidFromPROPVARIANT(value);
|
||||
if (value.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
return SetSolidFromString(name);
|
||||
}
|
||||
|
||||
return CMultiMethodProps::SetProperty(name, value);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
Init();
|
||||
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
RINOK(SetProperty(names[i], values[i]));
|
||||
@@ -781,7 +1232,9 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
|
||||
AString &methodName = _methods[0].MethodName;
|
||||
if (methodName.IsEmpty())
|
||||
methodName = k_LZMA2_Name;
|
||||
else if (!methodName.IsEqualTo_Ascii_NoCase(k_LZMA2_Name))
|
||||
else if (
|
||||
!methodName.IsEqualTo_Ascii_NoCase(k_LZMA2_Name)
|
||||
&& !methodName.IsEqualTo_Ascii_NoCase("xz"))
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user