Source code
Revision control
Copy as Markdown
Other Tools
// XzHandler.cpp↩
↩
#include "StdAfx.h"↩
↩
#include "../../../C/Alloc.h"↩
↩
#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"↩
#include "../Common/RegisterArc.h"↩
#include "../Common/StreamUtils.h"↩
↩
#include "../Compress/CopyCoder.h"↩
#include "../Compress/XzDecoder.h"↩
#include "../Compress/XzEncoder.h"↩
↩
#include "IArchive.h"↩
↩
#include "Common/HandlerOut.h"↩
↩
using namespace NWindows;↩
↩
namespace NArchive {↩
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,↩
public ISetProperties,↩
↩
#ifndef EXTRACT_ONLY↩
public IOutArchive,↩
#endif↩
↩
public CMyUnknownImp,↩
↩
#ifndef EXTRACT_ONLY↩
public CMultiMethodProps↩
#else↩
public CCommonMethodProps↩
#endif↩
{↩
CXzStatInfo _stat;↩
SRes MainDecodeSRes;↩
↩
bool _isArc;↩
bool _needSeekToStart;↩
bool _phySize_Defined;↩
bool _firstBlockWasRead;↩
↩
AString _methodsString;↩
↩
#ifndef EXTRACT_ONLY↩
↩
UInt32 _filterId;↩
↩
UInt64 _numSolidBytes;↩
↩
void InitXz()↩
{↩
_filterId = 0;↩
_numSolidBytes = XZ_PROPS__BLOCK_SIZE__AUTO;↩
}↩
↩
#endif↩
↩
void Init()↩
{↩
#ifndef EXTRACT_ONLY↩
InitXz();↩
CMultiMethodProps::Init();↩
#else↩
CCommonMethodProps::InitCommon();↩
#endif↩
}↩
↩
HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);↩
↩
HRESULT Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback);↩
↩
HRESULT Decode(NCompress::NXz::CDecoder &decoder,↩
ISequentialInStream *seqInStream,↩
ISequentialOutStream *outStream,↩
ICompressProgressInfo *progress)↩
{↩
#ifndef _7ZIP_ST↩
decoder._numThreads = _numThreads;↩
#endif↩
decoder._memUsage = _memUsage;↩
↩
MainDecodeSRes = SZ_OK;↩
↩
RINOK(decoder.Decode(seqInStream, outStream,↩
NULL, // *outSizeLimit↩
true, // finishStream↩
progress));↩
↩
_stat = decoder.Stat;↩
MainDecodeSRes = decoder.MainDecodeSRes;↩
↩
_phySize_Defined = true;↩
return S_OK;↩
}↩
↩
public:↩
MY_QUERYINTERFACE_BEGIN2(IInArchive)↩
MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq)↩
MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream)↩
MY_QUERYINTERFACE_ENTRY(ISetProperties)↩
#ifndef EXTRACT_ONLY↩
MY_QUERYINTERFACE_ENTRY(IOutArchive)↩
#endif↩
MY_QUERYINTERFACE_END↩
MY_ADDREF_RELEASE↩
↩
INTERFACE_IInArchive(;)↩
STDMETHOD(OpenSeq)(ISequentialInStream *stream);↩
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);↩
STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);↩
↩
#ifndef EXTRACT_ONLY↩
INTERFACE_IOutArchive(;)↩
#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():↩
_blocks(NULL),↩
_blocksArraySize(0)↩
{↩
#ifndef EXTRACT_ONLY↩
InitXz();↩
#endif↩
}↩
↩
CHandler::~CHandler()↩
{↩
MyFree(_blocks);↩
}↩
↩
↩
static const Byte kProps[] =↩
{↩
kpidSize,↩
kpidPackSize,↩
kpidMethod↩
};↩
↩
static const Byte kArcProps[] =↩
{↩
kpidMethod,↩
kpidNumStreams,↩
kpidNumBlocks,↩
kpidClusterSize,↩
kpidCharacts↩
};↩
↩
IMP_IInArchive_Props↩
IMP_IInArchive_ArcProps↩
↩
static inline char GetHex(unsigned value)↩
{↩
return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));↩
}↩
↩
static inline void AddHexToString(AString &s, Byte value)↩
{↩
s += GetHex(value >> 4);↩
s += GetHex(value & 0xF);↩
}↩
↩
static void Lzma2PropToString(AString &s, unsigned prop)↩
{↩
char c = 0;↩
UInt32 size;↩
if ((prop & 1) == 0)↩
size = prop / 2 + 12;↩
else↩
{↩
c = 'k';↩
size = (UInt32)(2 | (prop & 1)) << (prop / 2 + 1);↩
if (prop > 17)↩
{↩
size >>= 10;↩
c = 'm';↩
}↩
}↩
s.Add_UInt32(size);↩
if (c != 0)↩
s += c;↩
}↩
↩
struct CMethodNamePair↩
{↩
UInt32 Id;↩
const char *Name;↩
};↩
↩
static const CMethodNamePair g_NamePairs[] =↩
{↩
{ XZ_ID_Subblock, "SB" },↩
{ XZ_ID_Delta, "Delta" },↩
{ XZ_ID_X86, "BCJ" },↩
{ XZ_ID_PPC, "PPC" },↩
{ XZ_ID_IA64, "IA64" },↩
{ XZ_ID_ARM, "ARM" },↩
{ XZ_ID_ARMT, "ARMT" },↩
{ XZ_ID_SPARC, "SPARC" },↩
{ XZ_ID_LZMA2, "LZMA2" }↩
};↩
↩
static void AddMethodString(AString &s, const CXzFilter &f)↩
{↩
const char *p = NULL;↩
for (unsigned i = 0; i < ARRAY_SIZE(g_NamePairs); i++)↩
if (g_NamePairs[i].Id == f.id)↩
{↩
p = g_NamePairs[i].Name;↩
break;↩
}↩
char temp[32];↩
if (!p)↩
{↩
::ConvertUInt64ToString(f.id, temp);↩
p = temp;↩
}↩
↩
s += p;↩
↩
if (f.propsSize > 0)↩
{↩
s += ':';↩
if (f.id == XZ_ID_LZMA2 && f.propsSize == 1)↩
Lzma2PropToString(s, f.props[0]);↩
else if (f.id == XZ_ID_Delta && f.propsSize == 1)↩
s.Add_UInt32((UInt32)f.props[0] + 1);↩
else↩
{↩
s += '[';↩
for (UInt32 bi = 0; bi < f.propsSize; bi++)↩
AddHexToString(s, f.props[bi]);↩
s += ']';↩
}↩
}↩
}↩
↩
static const char * const kChecks[] =↩
{↩
"NoCheck"↩
, "CRC32"↩
, NULL↩
, NULL↩
, "CRC64"↩
, NULL↩
, NULL↩
, NULL↩
, NULL↩
, NULL↩
, "SHA256"↩
, NULL↩
, NULL↩
, NULL↩
, NULL↩
, NULL↩
};↩
↩
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));↩
for (i = 0; i <= XZ_CHECK_MASK; i++)↩
if (((mask >> i) & 1) != 0)↩
{↩
s.Add_Space_if_NotEmpty();↩
if (kChecks[i])↩
s += kChecks[i];↩
else↩
{↩
s += "Check-";↩
s.Add_UInt32((UInt32)i);↩
}↩
}↩
}↩
↩
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)↩
{↩
COM_TRY_BEGIN↩
NCOM::CPropVariant prop;↩
switch (propID)↩
{↩
case kpidPhySize: if (_phySize_Defined) prop = _stat.InSize; break;↩
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;↩
SRes sres = MainDecodeSRes; // _stat.DecodeRes2; //↩
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;↩
if (/*_stat.UnexpectedEnd */ sres == SZ_ERROR_INPUT_EOF) v |= kpv_ErrorFlags_UnexpectedEnd;↩
if (_stat.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;↩
if (/* _stat.HeadersError */ sres == SZ_ERROR_ARCHIVE) v |= kpv_ErrorFlags_HeadersError;↩
if (/* _stat.Unsupported */ sres == SZ_ERROR_UNSUPPORTED) v |= kpv_ErrorFlags_UnsupportedMethod;↩
if (/* _stat.DataError */ sres == SZ_ERROR_DATA) v |= kpv_ErrorFlags_DataError;↩
if (/* _stat.CrcError */ sres == SZ_ERROR_CRC) v |= kpv_ErrorFlags_CrcError;↩
if (v != 0)↩
prop = v;↩
break;↩
}↩
↩
case kpidMainSubfile:↩
{↩
// debug only, comment it:↩
// if (_blocks) prop = (UInt32)0;↩
break;↩
}↩
}↩
prop.Detach(value);↩
return S_OK;↩
COM_TRY_END↩
}↩
↩
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)↩
{↩
*numItems = 1;↩
return S_OK;↩
}↩
↩
STDMETHODIMP CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value)↩
{↩
COM_TRY_BEGIN↩
NCOM::CPropVariant prop;↩
switch (propID)↩
{↩
case kpidSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break;↩
case kpidPackSize: if (_phySize_Defined) prop = _stat.InSize; break;↩
case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;↩
}↩
prop.Detach(value);↩
return S_OK;↩
COM_TRY_END↩
}↩
↩
↩
struct COpenCallbackWrap↩
{↩
ICompressProgress vt;↩
IArchiveOpenCallback *OpenCallback;↩
HRESULT Res;↩
COpenCallbackWrap(IArchiveOpenCallback *progress);↩
};↩
↩
static SRes OpenCallbackProgress(const ICompressProgress *pp, UInt64 inSize, UInt64 /* outSize */)↩
{↩
COpenCallbackWrap *p = CONTAINER_FROM_VTBL(pp, COpenCallbackWrap, vt);↩
if (p->OpenCallback)↩
p->Res = p->OpenCallback->SetCompleted(NULL, &inSize);↩
return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS);↩
}↩
↩
COpenCallbackWrap::COpenCallbackWrap(IArchiveOpenCallback *callback)↩
{↩
vt.Progress = OpenCallbackProgress;↩
OpenCallback = callback;↩
Res = SZ_OK;↩
}↩
↩
↩
struct CXzsCPP↩
{↩
CXzs p;↩
CXzsCPP() { Xzs_Construct(&p); }↩
~CXzsCPP() { Xzs_Free(&p, &g_Alloc); }↩
};↩
↩
#define kInputBufSize ((size_t)1 << 10)↩
↩
struct CLookToRead2_CPP: public CLookToRead2↩
{↩
CLookToRead2_CPP()↩
{↩
buf = NULL;↩
LookToRead2_CreateVTable(this,↩
True // Lookahead ?↩
);↩
}↩
void Alloc(size_t allocSize)↩
{↩
buf = (Byte *)MyAlloc(allocSize);↩
if (buf)↩
this->bufSize = allocSize;↩
}↩
~CLookToRead2_CPP()↩
{↩
MyFree(buf);↩
}↩
};↩
↩
↩
static HRESULT SRes_to_Open_HRESULT(SRes res)↩
{↩
switch (res)↩
{↩
case SZ_OK: return S_OK;↩
case SZ_ERROR_MEM: return E_OUTOFMEMORY;↩
case SZ_ERROR_PROGRESS: return E_ABORT;↩
/*↩
case SZ_ERROR_UNSUPPORTED:↩
case SZ_ERROR_CRC:↩
case SZ_ERROR_DATA:↩
case SZ_ERROR_ARCHIVE:↩
case SZ_ERROR_NO_ARCHIVE:↩
return S_FALSE;↩
*/↩
}↩
return S_FALSE;↩
}↩
↩
↩
↩
HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback)↩
{↩
_needSeekToStart = true;↩
↩
{↩
CXzStreamFlags st;↩
CSeqInStreamWrap inStreamWrap;↩
↩
inStreamWrap.Init(inStream);↩
SRes res = Xz_ReadHeader(&st, &inStreamWrap.vt);↩
if (res != SZ_OK)↩
return SRes_to_Open_HRESULT(res);↩
↩
{↩
CXzBlock block;↩
Bool isIndex;↩
UInt32 headerSizeRes;↩
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++)↩
{↩
_methodsString.Add_Space_if_NotEmpty();↩
AddMethodString(_methodsString, block.filters[i]);↩
}↩
}↩
}↩
}↩
↩
RINOK(inStream->Seek(0, STREAM_SEEK_END, &_stat.InSize));↩
if (callback)↩
{↩
RINOK(callback->SetTotal(NULL, &_stat.InSize));↩
}↩
↩
CSeekInStreamWrap inStreamImp;↩
↩
inStreamImp.Init(inStream);↩
↩
CLookToRead2_CPP lookStream;↩
↩
lookStream.Alloc(kInputBufSize);↩
↩
if (!lookStream.buf)↩
return E_OUTOFMEMORY;↩
↩
lookStream.realStream = &inStreamImp.vt;↩
LookToRead2_Init(&lookStream);↩
↩
COpenCallbackWrap openWrap(callback);↩
↩
CXzsCPP xzs;↩
Int64 startPosition;↩
SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.vt, &startPosition, &openWrap.vt, &g_Alloc);↩
if (res == SZ_ERROR_PROGRESS)↩
return (openWrap.Res == S_OK) ? E_FAIL : openWrap.Res;↩
/*↩
if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0)↩
res = SZ_OK;↩
*/↩
if (res == SZ_OK && startPosition == 0)↩
{↩
_phySize_Defined = true;↩
↩
_stat.OutSize = Xzs_GetUnpackSize(&xzs.p);↩
_stat.UnpackSize_Defined = true;↩
↩
_stat.NumStreams = xzs.p.num;↩
_stat.NumStreams_Defined = true;↩
↩
_stat.NumBlocks = Xzs_GetNumBlocks(&xzs.p);↩
_stat.NumBlocks_Defined = true;↩
↩
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↩
{↩
res = SZ_OK;↩
}↩
↩
RINOK(SRes_to_Open_HRESULT(res));↩
_stream = inStream;↩
_seqStream = inStream;↩
_isArc = true;↩
return S_OK;↩
}↩
↩
↩
↩
STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)↩
{↩
COM_TRY_BEGIN↩
{↩
Close();↩
return Open2(inStream, callback);↩
}↩
COM_TRY_END↩
}↩
↩
STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)↩
{↩
Close();↩
_seqStream = stream;↩
_isArc = true;↩
_needSeekToStart = false;↩
return S_OK;↩
}↩
↩
STDMETHODIMP CHandler::Close()↩
{↩
XzStatInfo_Clear(&_stat);↩
↩
_isArc = false;↩
_needSeekToStart = false;↩
_phySize_Defined = false;↩
_firstBlockWasRead = false;↩
↩
_methodsString.Empty();↩
_stream.Release();↩
_seqStream.Release();↩
↩
MyFree(_blocks);↩
_blocks = NULL;↩
_blocksArraySize = 0;↩
_maxBlocksSize = 0;↩
↩
MainDecodeSRes = SZ_OK;↩
↩
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);↩
↩
XzUnpacker_SetOutBuf(&xzu.p, dest, unpackSize);↩
↩
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,↩
NULL,↩
&outLen,↩
xzu.InBuf + inPos, &inLen,↩
(inLen == 0), // srcFinished↩
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;↩
}↩
↩
↩
↩
static const UInt64 kMaxBlockSize_for_GetStream = (UInt64)1 << 40;↩
↩
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)↩
{↩
COM_TRY_BEGIN↩
↩
*stream = NULL;↩
↩
if (index != 0)↩
return E_INVALIDARG;↩
↩
if (!_stat.UnpackSize_Defined↩
|| _maxBlocksSize == 0 // 18.02↩
|| _maxBlocksSize > kMaxBlockSize_for_GetStream↩
|| _maxBlocksSize != (size_t)_maxBlocksSize)↩
return S_FALSE;↩
↩
UInt64 memSize;↩
if (!NSystem::GetRamSize(memSize))↩
memSize = (UInt64)(sizeof(size_t)) << 28;↩
{↩
if (_maxBlocksSize > memSize / 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↩
}↩
↩
↩
static Int32 Get_Extract_OperationResult(const NCompress::NXz::CDecoder &decoder)↩
{↩
Int32 opRes;↩
SRes sres = decoder.MainDecodeSRes; // decoder.Stat.DecodeRes2;↩
if (sres == SZ_ERROR_NO_ARCHIVE) // (!IsArc)↩
opRes = NExtract::NOperationResult::kIsNotArc;↩
else if (sres == SZ_ERROR_INPUT_EOF) // (UnexpectedEnd)↩
opRes = NExtract::NOperationResult::kUnexpectedEnd;↩
else if (decoder.Stat.DataAfterEnd)↩
opRes = NExtract::NOperationResult::kDataAfterEnd;↩
else if (sres == SZ_ERROR_CRC) // (CrcError)↩
opRes = NExtract::NOperationResult::kCRCError;↩
else if (sres == SZ_ERROR_UNSUPPORTED) // (Unsupported)↩
opRes = NExtract::NOperationResult::kUnsupportedMethod;↩
else if (sres == SZ_ERROR_ARCHIVE) // (HeadersError)↩
opRes = NExtract::NOperationResult::kDataError;↩
else if (sres == SZ_ERROR_DATA) // (DataError)↩
opRes = NExtract::NOperationResult::kDataError;↩
else if (sres != SZ_OK)↩
opRes = NExtract::NOperationResult::kDataError;↩
else↩
opRes = NExtract::NOperationResult::kOK;↩
return opRes;↩
}↩
↩
↩
↩
↩
STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,↩
Int32 testMode, IArchiveExtractCallback *extractCallback)↩
{↩
COM_TRY_BEGIN↩
if (numItems == 0)↩
return S_OK;↩
if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))↩
return E_INVALIDARG;↩
↩
if (_phySize_Defined)↩
extractCallback->SetTotal(_stat.InSize);↩
↩
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);↩
↩
CLocalProgress *lps = new CLocalProgress;↩
CMyComPtr<ICompressProgressInfo> lpsRef = lps;↩
lps->Init(extractCallback, true);↩
↩
if (_needSeekToStart)↩
{↩
if (!_stream)↩
return E_FAIL;↩
RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));↩
}↩
else↩
_needSeekToStart = true;↩
↩
↩
NCompress::NXz::CDecoder decoder;↩
↩
HRESULT hres = Decode(decoder, _seqStream, realOutStream, lpsRef);↩
↩
if (!decoder.MainDecodeSRes_wasUsed)↩
return hres == S_OK ? E_FAIL : hres;↩
↩
Int32 opRes = Get_Extract_OperationResult(decoder);↩
if (opRes == NExtract::NOperationResult::kOK↩
&& hres != S_OK)↩
opRes = NExtract::NOperationResult::kDataError;↩
↩
realOutStream.Release();↩
return extractCallback->SetOperationResult(opRes);↩
COM_TRY_END↩
}↩
↩
↩
↩
#ifndef EXTRACT_ONLY↩
↩
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)↩
{↩
*timeType = NFileTimeType::kUnix;↩
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);↩
}↩
↩
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_EMPTY)↩
if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE)↩
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;↩
RINOK(updateCallback->SetTotal(size));↩
}↩
↩
NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder;↩
CMyComPtr<ICompressCoder> encoder = encoderSpec;↩
↩
CXzProps &xzProps = encoderSpec->xzProps;↩
CLzma2EncProps &lzma2Props = xzProps.lzma2Props;↩
↩
lzma2Props.lzmaProps.level = GetLevel();↩
↩
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];↩
↩
FOR_VECTOR (j, m.Props)↩
{↩
const CProp &prop = m.Props[j];↩
RINOK(encoderSpec->SetCoderProp(prop.Id, prop.Value));↩
}↩
}↩
↩
CMyComPtr<ISequentialInStream> fileInStream;↩
RINOK(updateCallback->GetStream(0, &fileInStream));↩
↩
CLocalProgress *lps = new CLocalProgress;↩
CMyComPtr<ICompressProgressInfo> progress = lps;↩
lps->Init(updateCallback, true);↩
↩
return encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress);↩
}↩
↩
if (indexInArchive != 0)↩
return E_INVALIDARG;↩
↩
CMyComPtr<IArchiveUpdateCallbackFile> opCallback;↩
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);↩
if (opCallback)↩
{↩
RINOK(opCallback->ReportOperation(NEventIndexType::kInArcIndex, 0, NUpdateNotifyOp::kReplicate))↩
}↩
↩
if (_stream)↩
{↩
if (_phySize_Defined)↩
RINOK(updateCallback->SetTotal(_stat.InSize));↩
RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));↩
}↩
↩
CLocalProgress *lps = new CLocalProgress;↩
CMyComPtr<ICompressProgressInfo> progress = lps;↩
lps->Init(updateCallback, true);↩
↩
return NCompress::CopyStream(_stream, outStream, progress);↩
↩
COM_TRY_END↩
}↩
↩
#endif↩
↩
↩
HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)↩
{↩
UString name = nameSpec;↩
name.MakeLower_Ascii();↩
if (name.IsEmpty())↩
return E_INVALIDARG;↩
↩
#ifndef EXTRACT_ONLY↩
↩
if (name[0] == L's')↩
{↩
const wchar_t *s = name.Ptr(1);↩
if (*s == 0)↩
{↩
bool useStr = false;↩
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))↩
useStr = true;↩
break;↩
default: return E_INVALIDARG;↩
}↩
if (!useStr)↩
{↩
_numSolidBytes = (isSolid ? XZ_PROPS__BLOCK_SIZE__SOLID : XZ_PROPS__BLOCK_SIZE__AUTO);↩
return S_OK;↩
}↩
}↩
return ParseSizeString(s, value,↩
0, // percentsBase↩
_numSolidBytes) ? S_OK: E_INVALIDARG;↩
}↩
↩
return CMultiMethodProps::SetProperty(name, value);↩
↩
#else↩
↩
{↩
HRESULT hres;↩
if (SetCommonProperty(name, value, hres))↩
return hres;↩
}↩
↩
return E_INVALIDARG;↩
↩
#endif↩
}↩
↩
↩
↩
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]));↩
}↩
↩
#ifndef EXTRACT_ONLY↩
↩
if (!_filterMethod.MethodName.IsEmpty())↩
{↩
unsigned k;↩
for (k = 0; k < ARRAY_SIZE(g_NamePairs); k++)↩
{↩
const CMethodNamePair &pair = g_NamePairs[k];↩
if (StringsAreEqualNoCase_Ascii(_filterMethod.MethodName, pair.Name))↩
{↩
_filterId = pair.Id;↩
break;↩
}↩
}↩
if (k == ARRAY_SIZE(g_NamePairs))↩
return E_INVALIDARG;↩
}↩
↩
_methods.DeleteFrontal(GetNumEmptyMethods());↩
if (_methods.Size() > 1)↩
return E_INVALIDARG;↩
if (_methods.Size() == 1)↩
{↩
AString &methodName = _methods[0].MethodName;↩
if (methodName.IsEmpty())↩
methodName = k_LZMA2_Name;↩
else if (↩
!methodName.IsEqualTo_Ascii_NoCase(k_LZMA2_Name)↩
&& !methodName.IsEqualTo_Ascii_NoCase("xz"))↩
return E_INVALIDARG;↩
}↩
↩
#endif↩
↩
return S_OK;↩
↩
COM_TRY_END↩
}↩
↩
↩
REGISTER_ARC_IO(↩
"xz", "xz txz", "* .tar", 0xC,↩
XZ_SIG,↩
0,↩
NArcInfoFlags::kKeepName,↩
NULL)↩
↩
}}↩