mirror of
https://github.com/holub/mame
synced 2025-06-28 15:14:21 +03:00
1444 lines
33 KiB
C++
1444 lines
33 KiB
C++
// 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;
|
|
};
|
|
|
|
|
|
Z7_class_CHandler_final:
|
|
public IInArchive,
|
|
public IArchiveOpenSeq,
|
|
public IInArchiveGetStream,
|
|
public ISetProperties,
|
|
#ifndef Z7_EXTRACT_ONLY
|
|
public IOutArchive,
|
|
#endif
|
|
public CMyUnknownImp,
|
|
#ifndef Z7_EXTRACT_ONLY
|
|
public CMultiMethodProps
|
|
#else
|
|
public CCommonMethodProps
|
|
#endif
|
|
{
|
|
Z7_COM_QI_BEGIN2(IInArchive)
|
|
Z7_COM_QI_ENTRY(IArchiveOpenSeq)
|
|
Z7_COM_QI_ENTRY(IInArchiveGetStream)
|
|
Z7_COM_QI_ENTRY(ISetProperties)
|
|
#ifndef Z7_EXTRACT_ONLY
|
|
Z7_COM_QI_ENTRY(IOutArchive)
|
|
#endif
|
|
Z7_COM_QI_END
|
|
Z7_COM_ADDREF_RELEASE
|
|
|
|
Z7_IFACE_COM7_IMP(IInArchive)
|
|
Z7_IFACE_COM7_IMP(IArchiveOpenSeq)
|
|
Z7_IFACE_COM7_IMP(IInArchiveGetStream)
|
|
Z7_IFACE_COM7_IMP(ISetProperties)
|
|
#ifndef Z7_EXTRACT_ONLY
|
|
Z7_IFACE_COM7_IMP(IOutArchive)
|
|
#endif
|
|
|
|
CXzStatInfo _stat; // it's stat from backward parsing
|
|
CXzStatInfo _stat2; // it's data from forward parsing, if the decoder was called
|
|
SRes _stat2_decode_SRes;
|
|
bool _stat_defined;
|
|
bool _stat2_defined;
|
|
|
|
const CXzStatInfo *GetStat() const
|
|
{
|
|
if (_stat_defined) return &_stat;
|
|
if (_stat2_defined) return &_stat2;
|
|
return NULL;
|
|
}
|
|
|
|
bool _isArc;
|
|
bool _needSeekToStart;
|
|
bool _firstBlockWasRead;
|
|
|
|
AString _methodsString;
|
|
|
|
|
|
#ifndef Z7_EXTRACT_ONLY
|
|
|
|
UInt32 _filterId;
|
|
UInt64 _numSolidBytes;
|
|
|
|
void InitXz()
|
|
{
|
|
_filterId = 0;
|
|
_numSolidBytes = XZ_PROPS_BLOCK_SIZE_AUTO;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
void Init()
|
|
{
|
|
#ifndef Z7_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 Z7_ST
|
|
decoder._numThreads = _numThreads;
|
|
#endif
|
|
decoder._memUsage = _memUsage_Decompress;
|
|
|
|
HRESULT hres = decoder.Decode(seqInStream, outStream,
|
|
NULL, // *outSizeLimit
|
|
true, // finishStream
|
|
progress);
|
|
|
|
if (decoder.MainDecodeSRes_wasUsed
|
|
&& decoder.MainDecodeSRes != SZ_ERROR_MEM
|
|
&& decoder.MainDecodeSRes != SZ_ERROR_UNSUPPORTED)
|
|
{
|
|
// if (!_stat2_defined)
|
|
{
|
|
_stat2_decode_SRes = decoder.MainDecodeSRes;
|
|
_stat2 = decoder.Stat;
|
|
_stat2_defined = true;
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
public:
|
|
CBlockInfo *_blocks;
|
|
size_t _blocksArraySize;
|
|
UInt64 _maxBlocksSize;
|
|
CMyComPtr<IInStream> _stream;
|
|
CMyComPtr<ISequentialInStream> _seqStream;
|
|
|
|
CXzBlock _firstBlock;
|
|
|
|
CHandler();
|
|
~CHandler();
|
|
|
|
HRESULT SeekToPackPos(UInt64 pos)
|
|
{
|
|
return InStream_SeekSet(_stream, pos);
|
|
}
|
|
};
|
|
|
|
|
|
CHandler::CHandler():
|
|
_blocks(NULL),
|
|
_blocksArraySize(0)
|
|
{
|
|
#ifndef Z7_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_ARM64, "ARM64" },
|
|
{ XZ_ID_LZMA2, "LZMA2" }
|
|
};
|
|
|
|
static void AddMethodString(AString &s, const CXzFilter &f)
|
|
{
|
|
const char *p = NULL;
|
|
for (unsigned i = 0; i < Z7_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 if (f.id == XZ_ID_ARM64 && f.propsSize == 1)
|
|
s.Add_UInt32((UInt32)f.props[0] + 16 + 2);
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
|
|
{
|
|
COM_TRY_BEGIN
|
|
NCOM::CPropVariant prop;
|
|
|
|
const CXzStatInfo *stat = GetStat();
|
|
|
|
switch (propID)
|
|
{
|
|
case kpidPhySize: if (stat) prop = stat->InSize; break;
|
|
case kpidNumStreams: if (stat && stat->NumStreams_Defined) prop = stat->NumStreams; break;
|
|
case kpidNumBlocks: if (stat && stat->NumBlocks_Defined) prop = stat->NumBlocks; break;
|
|
case kpidUnpackSize: if (stat && stat->UnpackSize_Defined) prop = stat->OutSize; break;
|
|
case kpidClusterSize: if (_stat_defined && _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 = _stat2_decode_SRes;
|
|
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
|
|
if (sres == SZ_ERROR_INPUT_EOF) v |= kpv_ErrorFlags_UnexpectedEnd;
|
|
if (_stat2_defined && _stat2.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
|
|
if (sres == SZ_ERROR_ARCHIVE) v |= kpv_ErrorFlags_HeadersError;
|
|
if (sres == SZ_ERROR_UNSUPPORTED) v |= kpv_ErrorFlags_UnsupportedMethod;
|
|
if (sres == SZ_ERROR_DATA) v |= kpv_ErrorFlags_DataError;
|
|
if (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
|
|
}
|
|
|
|
Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
|
|
{
|
|
*numItems = 1;
|
|
return S_OK;
|
|
}
|
|
|
|
Z7_COM7F_IMF(CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value))
|
|
{
|
|
COM_TRY_BEGIN
|
|
const CXzStatInfo *stat = GetStat();
|
|
NCOM::CPropVariant prop;
|
|
switch (propID)
|
|
{
|
|
case kpidSize: if (stat && stat->UnpackSize_Defined) prop = stat->OutSize; break;
|
|
case kpidPackSize: if (stat) 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;
|
|
|
|
// new clang shows "non-POD" warning for offsetof(), if we use constructor instead of Init()
|
|
void Init(IArchiveOpenCallback *progress);
|
|
};
|
|
|
|
static SRes OpenCallbackProgress(ICompressProgressPtr pp, UInt64 inSize, UInt64 /* outSize */)
|
|
{
|
|
Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(COpenCallbackWrap)
|
|
if (p->OpenCallback)
|
|
p->Res = p->OpenCallback->SetCompleted(NULL, &inSize);
|
|
return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS);
|
|
}
|
|
|
|
void COpenCallbackWrap::Init(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 (inStreamWrap.Res != S_OK)
|
|
return inStreamWrap.Res;
|
|
if (res != SZ_OK)
|
|
return SRes_to_Open_HRESULT(res);
|
|
|
|
{
|
|
CXzBlock block;
|
|
BoolInt isIndex;
|
|
UInt32 headerSizeRes;
|
|
|
|
SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.vt, &isIndex, &headerSizeRes);
|
|
|
|
if (inStreamWrap.Res != S_OK)
|
|
return inStreamWrap.Res;
|
|
|
|
if (res2 != SZ_OK)
|
|
{
|
|
if (res2 == SZ_ERROR_INPUT_EOF)
|
|
{
|
|
_stat2_decode_SRes = res2;
|
|
_stream = inStream;
|
|
_seqStream = inStream;
|
|
_isArc = true;
|
|
return S_OK;
|
|
}
|
|
|
|
if (res2 == SZ_ERROR_ARCHIVE)
|
|
return S_FALSE;
|
|
}
|
|
else if (!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_GetSize_SeekToEnd(inStream, _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;
|
|
openWrap.Init(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)
|
|
{
|
|
_stat_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;
|
|
}
|
|
|
|
|
|
|
|
Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback))
|
|
{
|
|
COM_TRY_BEGIN
|
|
{
|
|
Close();
|
|
return Open2(inStream, callback);
|
|
}
|
|
COM_TRY_END
|
|
}
|
|
|
|
Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
|
|
{
|
|
Close();
|
|
_seqStream = stream;
|
|
_isArc = true;
|
|
_needSeekToStart = false;
|
|
return S_OK;
|
|
}
|
|
|
|
Z7_COM7F_IMF(CHandler::Close())
|
|
{
|
|
XzStatInfo_Clear(&_stat);
|
|
XzStatInfo_Clear(&_stat2);
|
|
_stat_defined = false;
|
|
_stat2_defined = false;
|
|
_stat2_decode_SRes = SZ_OK;
|
|
|
|
_isArc = false;
|
|
_needSeekToStart = 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);
|
|
}
|
|
|
|
|
|
Z7_CLASS_IMP_COM_1(
|
|
CInStream
|
|
, IInStream
|
|
)
|
|
Z7_IFACE_COM7_IMP(ISequentialInStream)
|
|
|
|
UInt64 _virtPos;
|
|
public:
|
|
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;
|
|
|
|
// ~CInStream();
|
|
};
|
|
|
|
/*
|
|
CInStream::~CInStream()
|
|
{
|
|
// _cache.Free();
|
|
}
|
|
*/
|
|
|
|
static 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;
|
|
|
|
const 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;
|
|
|
|
const BoolInt 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Z7_COM7F_IMF(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)
|
|
{
|
|
const 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;
|
|
}
|
|
|
|
{
|
|
const size_t offset = (size_t)(_virtPos - _cacheStartPos);
|
|
const 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
|
|
}
|
|
|
|
|
|
Z7_COM7F_IMF(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 = (UInt64)offset;
|
|
if (newPosition)
|
|
*newPosition = (UInt64)offset;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
static const UInt64 kMaxBlockSize_for_GetStream = (UInt64)1 << 40;
|
|
|
|
Z7_COM7F_IMF(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;
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
Z7_COM7F_IMF(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;
|
|
|
|
const CXzStatInfo *stat = GetStat();
|
|
|
|
if (stat)
|
|
extractCallback->SetTotal(stat->InSize);
|
|
|
|
UInt64 currentTotalPacked = 0;
|
|
RINOK(extractCallback->SetCompleted(¤tTotalPacked))
|
|
CMyComPtr<ISequentialOutStream> realOutStream;
|
|
const 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(InStream_SeekToBegin(_stream))
|
|
}
|
|
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 Z7_EXTRACT_ONLY
|
|
|
|
Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType))
|
|
{
|
|
*timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType;
|
|
// *timeType = NFileTimeType::kUnix;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
Z7_COM7F_IMF(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;
|
|
|
|
{
|
|
Z7_DECL_CMyComPtr_QI_FROM(
|
|
IStreamSetRestriction,
|
|
setRestriction, outStream)
|
|
if (setRestriction)
|
|
RINOK(setRestriction->SetRestriction(0, 0))
|
|
}
|
|
|
|
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 dataSize;
|
|
{
|
|
NCOM::CPropVariant prop;
|
|
RINOK(updateCallback->GetProperty(0, kpidSize, &prop))
|
|
if (prop.vt != VT_UI8)
|
|
return E_INVALIDARG;
|
|
dataSize = prop.uhVal.QuadPart;
|
|
}
|
|
|
|
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 = dataSize;
|
|
/*
|
|
{
|
|
NCOM::CPropVariant prop = (UInt64)dataSize;
|
|
RINOK(encoderSpec->SetCoderProp(NCoderPropID::kReduceSize, prop))
|
|
}
|
|
*/
|
|
|
|
#ifndef Z7_ST
|
|
|
|
UInt32 numThreads = _numThreads;
|
|
|
|
const UInt32 kNumThreads_Max = 1024;
|
|
if (numThreads > kNumThreads_Max)
|
|
numThreads = kNumThreads_Max;
|
|
|
|
if (!_numThreads_WasForced
|
|
&& _numThreads >= 1
|
|
&& _memUsage_WasSet)
|
|
{
|
|
COneMethodInfo oneMethodInfo;
|
|
if (!_methods.IsEmpty())
|
|
oneMethodInfo = _methods[0];
|
|
|
|
SetGlobalLevelTo(oneMethodInfo);
|
|
|
|
const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0);
|
|
if (!numThreads_WasSpecifiedInMethod)
|
|
{
|
|
// here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already
|
|
CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, numThreads);
|
|
}
|
|
|
|
UInt64 cs = _numSolidBytes;
|
|
if (cs != XZ_PROPS_BLOCK_SIZE_AUTO)
|
|
oneMethodInfo.AddProp_BlockSize2(cs);
|
|
cs = oneMethodInfo.Get_Xz_BlockSize();
|
|
|
|
if (cs != XZ_PROPS_BLOCK_SIZE_AUTO &&
|
|
cs != XZ_PROPS_BLOCK_SIZE_SOLID)
|
|
{
|
|
const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads();
|
|
const UInt32 numBlockThreads_Original = numThreads / lzmaThreads;
|
|
|
|
if (numBlockThreads_Original > 1)
|
|
{
|
|
UInt32 numBlockThreads = numBlockThreads_Original;
|
|
{
|
|
const UInt64 lzmaMemUsage = oneMethodInfo.Get_Lzma_MemUsage(false);
|
|
for (; numBlockThreads > 1; numBlockThreads--)
|
|
{
|
|
UInt64 size = numBlockThreads * (lzmaMemUsage + cs);
|
|
UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1;
|
|
if (cs < ((UInt32)1 << 26)) numPackChunks++;
|
|
if (cs < ((UInt32)1 << 24)) numPackChunks++;
|
|
if (cs < ((UInt32)1 << 22)) numPackChunks++;
|
|
size += numPackChunks * cs;
|
|
// printf("\nnumBlockThreads = %d, size = %d\n", (unsigned)(numBlockThreads), (unsigned)(size >> 20));
|
|
if (size <= _memUsage_Compress)
|
|
break;
|
|
}
|
|
}
|
|
if (numBlockThreads == 0)
|
|
numBlockThreads = 1;
|
|
if (numBlockThreads != numBlockThreads_Original)
|
|
numThreads = numBlockThreads * lzmaThreads;
|
|
}
|
|
}
|
|
}
|
|
xzProps.numTotalThreads = (int)numThreads;
|
|
|
|
#endif // Z7_ST
|
|
|
|
|
|
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))
|
|
if (!fileInStream)
|
|
return S_FALSE;
|
|
{
|
|
CMyComPtr<IStreamGetSize> streamGetSize;
|
|
fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
|
|
if (streamGetSize)
|
|
{
|
|
UInt64 size;
|
|
if (streamGetSize->GetSize(&size) == S_OK)
|
|
dataSize = size;
|
|
}
|
|
}
|
|
RINOK(updateCallback->SetTotal(dataSize))
|
|
CLocalProgress *lps = new CLocalProgress;
|
|
CMyComPtr<ICompressProgressInfo> progress = lps;
|
|
lps->Init(updateCallback, true);
|
|
RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, progress))
|
|
}
|
|
|
|
return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
|
|
}
|
|
|
|
if (indexInArchive != 0)
|
|
return E_INVALIDARG;
|
|
|
|
Z7_DECL_CMyComPtr_QI_FROM(
|
|
IArchiveUpdateCallbackFile,
|
|
opCallback, updateCallback)
|
|
if (opCallback)
|
|
{
|
|
RINOK(opCallback->ReportOperation(NEventIndexType::kInArcIndex, 0, NUpdateNotifyOp::kReplicate))
|
|
}
|
|
|
|
if (_stream)
|
|
{
|
|
const CXzStatInfo *stat = GetStat();
|
|
if (stat)
|
|
{
|
|
RINOK(updateCallback->SetTotal(stat->InSize))
|
|
}
|
|
RINOK(InStream_SeekToBegin(_stream))
|
|
}
|
|
|
|
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 Z7_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
|
|
}
|
|
|
|
|
|
|
|
Z7_COM7F_IMF(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 Z7_EXTRACT_ONLY
|
|
|
|
if (!_filterMethod.MethodName.IsEmpty())
|
|
{
|
|
unsigned k;
|
|
for (k = 0; k < Z7_ARRAY_SIZE(g_NamePairs); k++)
|
|
{
|
|
const CMethodNamePair &pair = g_NamePairs[k];
|
|
if (StringsAreEqualNoCase_Ascii(_filterMethod.MethodName, pair.Name))
|
|
{
|
|
_filterId = pair.Id;
|
|
break;
|
|
}
|
|
}
|
|
if (k == Z7_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
|
|
, 0
|
|
, NULL)
|
|
|
|
}}
|