Files
nsis-plugin-ns7zip/versions/26.00/CPP/7zip/Archive/ZstdHandler.cpp
T
Simone d074cc7c07 chore: initial commit (extracted from Launchers monorepo)
Plugin: ns7zip v2.0.0
Architectures: x86-ansi, x86-unicode, amd64-unicode
License: LGPL-2.1-or-later
2026-04-29 14:07:51 +02:00

1148 lines
28 KiB
C++

// ZstdHandler.cpp
#include "StdAfx.h"
// #define Z7_USE_ZSTD_ORIG_DECODER
// #define Z7_USE_ZSTD_COMPRESSION
#include "../../Common/ComTry.h"
#include "../Common/MethodProps.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamUtils.h"
#include "../Compress/CopyCoder.h"
#include "../Compress/ZstdDecoder.h"
#ifdef Z7_USE_ZSTD_ORIG_DECODER
#include "../Compress/Zstd2Decoder.h"
#endif
#ifdef Z7_USE_ZSTD_COMPRESSION
#include "../Compress/ZstdEncoder.h"
#include "../Compress/ZstdEncoderProps.h"
#include "Common/HandlerOut.h"
#endif
#include "Common/DummyOutStream.h"
#include "../../../C/CpuArch.h"
using namespace NWindows;
namespace NArchive {
namespace NZstd {
#define DESCRIPTOR_Get_DictionaryId_Flag(d) ((d) & 3)
#define DESCRIPTOR_FLAG_CHECKSUM (1 << 2)
#define DESCRIPTOR_FLAG_RESERVED (1 << 3)
#define DESCRIPTOR_FLAG_UNUSED (1 << 4)
#define DESCRIPTOR_FLAG_SINGLE (1 << 5)
#define DESCRIPTOR_Get_ContentSize_Flag3(d) ((d) >> 5)
#define DESCRIPTOR_Is_ContentSize_Defined(d) (((d) & 0xe0) != 0)
struct CFrameHeader
{
Byte Descriptor;
Byte WindowDescriptor;
UInt32 DictionaryId;
UInt64 ContentSize;
/* by zstd specification:
the decoder must check that (Is_Reserved() == false)
the decoder must ignore Unused_bit */
bool Is_Reserved() const { return (Descriptor & DESCRIPTOR_FLAG_RESERVED) != 0; }
bool Is_Checksum() const { return (Descriptor & DESCRIPTOR_FLAG_CHECKSUM) != 0; }
bool Is_SingleSegment() const { return (Descriptor & DESCRIPTOR_FLAG_SINGLE) != 0; }
bool Is_ContentSize_Defined() const { return DESCRIPTOR_Is_ContentSize_Defined(Descriptor); }
unsigned Get_DictionaryId_Flag() const { return DESCRIPTOR_Get_DictionaryId_Flag(Descriptor); }
unsigned Get_ContentSize_Flag3() const { return DESCRIPTOR_Get_ContentSize_Flag3(Descriptor); }
const Byte *Parse(const Byte *p, int size)
{
if ((unsigned)size < 2)
return NULL;
Descriptor = *p++;
size--;
{
Byte w = 0;
if (!Is_SingleSegment())
{
w = *p++;
size--;
}
WindowDescriptor = w;
}
{
unsigned n = Get_DictionaryId_Flag();
UInt32 d = 0;
if (n)
{
n = (unsigned)1 << (n - 1);
if ((size -= (int)n) < 0)
return NULL;
d = GetUi32(p) & ((UInt32)(Int32)-1 >> (32 - 8u * n));
p += n;
}
DictionaryId = d;
}
{
unsigned n = Get_ContentSize_Flag3();
UInt64 v = 0;
if (n)
{
n >>= 1;
if (n == 1)
v = 256;
n = (unsigned)1 << n;
if ((size -= (int)n) < 0)
return NULL;
v += GetUi64(p) & ((UInt64)(Int64)-1 >> (64 - 8u * n));
p += n;
}
ContentSize = v;
}
return p;
}
};
class CHandler Z7_final:
public IInArchive,
public IArchiveOpenSeq,
public ISetProperties,
#ifdef Z7_USE_ZSTD_COMPRESSION
public IOutArchive,
#endif
public CMyUnknownImp
{
Z7_COM_QI_BEGIN2(IInArchive)
Z7_COM_QI_ENTRY(IArchiveOpenSeq)
Z7_COM_QI_ENTRY(ISetProperties)
#ifdef Z7_USE_ZSTD_COMPRESSION
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(ISetProperties)
#ifdef Z7_USE_ZSTD_COMPRESSION
Z7_IFACE_COM7_IMP(IOutArchive)
#endif
bool _isArc;
bool _needSeekToStart;
// bool _dataAfterEnd;
// bool _needMoreInput;
bool _unsupportedBlock;
bool _wasParsed;
bool _phySize_Decoded_Defined;
bool _unpackSize_Defined; // decoded
bool _decoded_Info_Defined;
bool _parseMode;
bool _disableHash;
// bool _smallMode;
UInt64 _phySize;
UInt64 _phySize_Decoded;
UInt64 _unpackSize;
CZstdDecInfo _parsed_Info;
CZstdDecInfo _decoded_Info;
CMyComPtr<IInStream> _stream;
CMyComPtr<ISequentialInStream> _seqStream;
#ifdef Z7_USE_ZSTD_COMPRESSION
CSingleMethodProps _props;
#endif
public:
CHandler():
_parseMode(false),
_disableHash(false)
// _smallMode(false)
{}
};
static const Byte kProps[] =
{
kpidSize,
kpidPackSize
};
static const Byte kArcProps[] =
{
kpidNumStreams,
kpidNumBlocks,
kpidMethod,
// kpidChecksum
kpidCRC
};
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
// static const unsigned kBlockType_Raw = 0;
static const unsigned kBlockType_RLE = 1;
// static const unsigned kBlockType_Compressed = 2;
static const unsigned kBlockType_Reserved = 3;
/*
static const char * const kNames[] =
{
"RAW"
, "RLE"
, "Compressed"
, "Reserved"
};
*/
static void Add_UInt64(AString &s, const char *name, UInt64 v)
{
s.Add_OptSpaced(name);
s.Add_Colon();
s.Add_UInt64(v);
}
static void PrintSize(AString &s, UInt64 w)
{
char c = 0;
if ((w & ((1 << 30) - 1)) == 0) { c = 'G'; w >>= 30; }
else if ((w & ((1 << 20) - 1)) == 0) { c = 'M'; w >>= 20; }
else if ((w & ((1 << 10) - 1)) == 0) { c = 'K'; w >>= 10; }
s.Add_UInt64(w);
if (c)
{
s.Add_Char(c);
s += "iB";
}
}
Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
{
NCOM::CPropVariant prop;
CZstdDecInfo *p = NULL;
if (_wasParsed || !_decoded_Info_Defined)
p = &_parsed_Info;
else if (_decoded_Info_Defined)
p = &_decoded_Info;
switch (propID)
{
case kpidPhySize:
if (_wasParsed)
prop = _phySize;
else if (_phySize_Decoded_Defined)
prop = _phySize_Decoded;
break;
case kpidUnpackSize:
if (_unpackSize_Defined)
prop = _unpackSize;
break;
case kpidNumStreams:
if (p)
if (_wasParsed || _decoded_Info_Defined)
prop = p->num_DataFrames;
break;
case kpidNumBlocks:
if (p)
if (_wasParsed || _decoded_Info_Defined)
prop = p->num_Blocks;
break;
// case kpidChecksum:
case kpidCRC:
if (p)
if (p->checksum_Defined && p->num_DataFrames == 1)
prop = p->checksum; // it's checksum from last frame
break;
case kpidMethod:
{
AString s;
s.Add_OptSpaced(p == &_decoded_Info ?
"decoded:" : _wasParsed ?
"parsed:" :
"header-open-only:");
if (p->dictionaryId != 0)
{
if (p->are_DictionaryId_Different)
s.Add_OptSpaced("different-dictionary-IDs");
s.Add_OptSpaced("dictionary-ID:");
s.Add_UInt32(p->dictionaryId);
}
/*
if (ContentSize_Defined)
{
s.Add_OptSpaced("ContentSize=");
s.Add_UInt64(ContentSize_Total);
}
*/
// if (p->are_Checksums)
if (p->descriptor_OR & DESCRIPTOR_FLAG_CHECKSUM)
s.Add_OptSpaced("XXH64");
if (p->descriptor_NOT_OR & DESCRIPTOR_FLAG_CHECKSUM)
s.Add_OptSpaced("NO-XXH64");
if (p->descriptor_OR & DESCRIPTOR_FLAG_UNUSED)
s.Add_OptSpaced("unused_bit");
if (p->descriptor_OR & DESCRIPTOR_FLAG_SINGLE)
s.Add_OptSpaced("single-segments");
if (p->descriptor_NOT_OR & DESCRIPTOR_FLAG_SINGLE)
{
// Add_UInt64(s, "wnd-descriptors", p->num_WindowDescriptors);
s.Add_OptSpaced("wnd-desc-log-MAX:");
// WindowDescriptor_MAX = 16 << 3; // for debug
const unsigned e = p->windowDescriptor_MAX >> 3;
s.Add_UInt32(e + 10);
const unsigned m = p->windowDescriptor_MAX & 7;
if (m != 0)
{
s.Add_Dot();
s.Add_UInt32(m);
}
}
if (DESCRIPTOR_Is_ContentSize_Defined(p->descriptor_OR) ||
(p->descriptor_NOT_OR & DESCRIPTOR_FLAG_SINGLE))
/*
if (p->are_ContentSize_Known ||
p->are_WindowDescriptors)
*/
{
s.Add_OptSpaced("wnd-MAX:");
PrintSize(s, p->windowSize_MAX);
if (p->windowSize_MAX != p->windowSize_Allocate_MAX)
{
s.Add_OptSpaced("wnd-use-MAX:");
PrintSize(s, p->windowSize_Allocate_MAX);
}
}
if (p->num_DataFrames != 1)
Add_UInt64(s, "data-frames", p->num_DataFrames);
if (p->num_SkipFrames != 0)
{
Add_UInt64(s, "skip-frames", p->num_SkipFrames);
Add_UInt64(s, "skip-frames-size-total", p->skipFrames_Size);
}
if (p->are_ContentSize_Unknown)
s.Add_OptSpaced("unknown-content-size");
if (DESCRIPTOR_Is_ContentSize_Defined(p->descriptor_OR))
{
Add_UInt64(s, "content-size-frame-max", p->contentSize_MAX);
Add_UInt64(s, "content-size-total", p->contentSize_Total);
}
/*
for (unsigned i = 0; i < 4; i++)
{
const UInt64 n = p->num_Blocks_forType[i];
if (n)
{
s.Add_OptSpaced(kNames[i]);
s += "-blocks:";
s.Add_UInt64(n);
s.Add_OptSpaced(kNames[i]);
s += "-block-bytes:";
s.Add_UInt64(p->num_BlockBytes_forType[i]);
}
}
*/
prop = s;
break;
}
case kpidErrorFlags:
{
UInt32 v = 0;
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
// if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
// if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
if (_unsupportedBlock) v |= kpv_ErrorFlags_UnsupportedMethod;
/*
if (_parsed_Info.numBlocks_forType[kBlockType_Reserved])
v |= kpv_ErrorFlags_UnsupportedMethod;
*/
prop = v;
break;
}
default: break;
}
prop.Detach(value);
return S_OK;
}
Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
{
*numItems = 1;
return S_OK;
}
Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
{
NCOM::CPropVariant prop;
switch (propID)
{
case kpidPackSize:
if (_wasParsed)
prop = _phySize;
else if (_phySize_Decoded_Defined)
prop = _phySize_Decoded;
break;
case kpidSize:
if (_wasParsed && !_parsed_Info.are_ContentSize_Unknown)
prop = _parsed_Info.contentSize_Total;
else if (_unpackSize_Defined)
prop = _unpackSize;
break;
default: break;
}
prop.Detach(value);
return S_OK;
}
static const unsigned kSignatureSize = 4;
static const Byte k_Signature[kSignatureSize] = { 0x28, 0xb5, 0x2f, 0xfd } ;
static const UInt32 kDataFrameSignature32 = 0xfd2fb528;
static const UInt32 kSkipFrameSignature = 0x184d2a50;
static const UInt32 kSkipFrameSignature_Mask = 0xfffffff0;
/*
API_FUNC_static_IsArc IsArc_Zstd(const Byte *p, size_t size)
{
if (size < kSignatureSize)
return k_IsArc_Res_NEED_MORE;
if (memcmp(p, k_Signature, kSignatureSize) != 0)
{
const UInt32 v = GetUi32(p);
if ((v & kSkipFrameSignature_Mask) != kSkipFrameSignature)
return k_IsArc_Res_NO;
return k_IsArc_Res_YES;
}
p += 4;
// return k_IsArc_Res_YES;
}
}
*/
// kBufSize must be >= (ZSTD_FRAMEHEADERSIZE_MAX = 18)
// we use big buffer for fast parsing of worst case small blocks.
static const unsigned kBufSize =
1 << 9;
// 1 << 14; // fastest in real file
struct CStreamBuffer
{
unsigned pos;
unsigned lim;
IInStream *Stream;
UInt64 StreamOffset;
Byte buf[kBufSize];
CStreamBuffer():
pos(0),
lim(0),
StreamOffset(0)
{}
unsigned Avail() const { return lim - pos; }
const Byte *GetPtr() const { return &buf[pos]; }
UInt64 GetCurOffset() const { return StreamOffset - Avail(); }
void SkipInBuf(UInt32 size) { pos += size; }
HRESULT Skip(UInt32 size);
HRESULT Read(unsigned num);
};
HRESULT CStreamBuffer::Skip(UInt32 size)
{
unsigned rem = lim - pos;
if (rem != 0)
{
if (rem > size)
rem = size;
pos += rem;
size -= rem;
if (pos != lim)
return S_OK;
}
if (size == 0)
return S_OK;
return Stream->Seek(size, STREAM_SEEK_CUR, &StreamOffset);
}
HRESULT CStreamBuffer::Read(unsigned num)
{
if (lim - pos >= num)
return S_OK;
if (pos != 0)
{
lim -= pos;
memmove(buf, buf + pos, lim);
pos = 0;
}
size_t processed = kBufSize - ((unsigned)StreamOffset & (kBufSize - 1));
const unsigned avail = kBufSize - lim;
num -= lim;
if (avail < processed || processed < num)
processed = avail;
const HRESULT res = ReadStream(Stream, buf + lim, &processed);
StreamOffset += processed;
lim += (unsigned)processed;
return res;
}
static const unsigned k_ZSTD_FRAMEHEADERSIZE_MAX = 4 + 14;
Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
{
COM_TRY_BEGIN
Close();
CZstdDecInfo *p = &_parsed_Info;
// p->are_ContentSize_Unknown = False;
CStreamBuffer sb;
sb.Stream = stream;
for (;;)
{
RINOK(sb.Read(k_ZSTD_FRAMEHEADERSIZE_MAX))
if (sb.Avail() < kSignatureSize)
break;
if (callback && (ZstdDecInfo_GET_NUM_FRAMES(p) & 0xFFF) == 2)
{
const UInt64 numBytes = sb.GetCurOffset();
RINOK(callback->SetCompleted(NULL, &numBytes))
}
const UInt32 v = GetUi32(sb.GetPtr());
if (v != kDataFrameSignature32)
{
if ((v & kSkipFrameSignature_Mask) != kSkipFrameSignature)
break;
_phySize = sb.GetCurOffset() + 8;
p->num_SkipFrames++;
sb.SkipInBuf(4);
if (sb.Avail() < 4)
break;
const UInt32 size = GetUi32(sb.GetPtr());
p->skipFrames_Size += size;
sb.SkipInBuf(4);
_phySize = sb.GetCurOffset() + size;
RINOK(sb.Skip(size))
continue;
}
p->num_DataFrames++;
// _numStreams_Defined = true;
sb.SkipInBuf(4);
CFrameHeader fh;
{
const Byte *data = fh.Parse(sb.GetPtr(), (int)sb.Avail());
if (!data)
{
// _needMoreInput = true;
// we set size for one byte more to show that stream was truncated
_phySize = sb.StreamOffset + 1;
break;
}
if (fh.Is_Reserved())
{
// we don't want false detection
if (ZstdDecInfo_GET_NUM_FRAMES(p) == 1)
return S_FALSE;
// _phySize = sb.GetCurOffset();
break;
}
sb.SkipInBuf((unsigned)(data - sb.GetPtr()));
}
p->descriptor_OR = (Byte)(p->descriptor_OR | fh.Descriptor);
p->descriptor_NOT_OR = (Byte)(p->descriptor_NOT_OR | ~fh.Descriptor);
// _numBlocks_Defined = true;
// if (fh.Get_DictionaryId_Flag())
// p->dictionaryId_Cur = fh.DictionaryId;
if (fh.DictionaryId != 0)
{
if (p->dictionaryId == 0)
p->dictionaryId = fh.DictionaryId;
else if (p->dictionaryId != fh.DictionaryId)
p->are_DictionaryId_Different = True;
}
UInt32 blockSizeAllowedMax = (UInt32)1 << 17;
{
UInt64 winSize = fh.ContentSize;
UInt64 winSize_forAllocate = fh.ContentSize;
if (!fh.Is_SingleSegment())
{
if (p->windowDescriptor_MAX < fh.WindowDescriptor)
p->windowDescriptor_MAX = fh.WindowDescriptor;
const unsigned e = (fh.WindowDescriptor >> 3);
const unsigned m = (fh.WindowDescriptor & 7);
winSize = (UInt64)(8 + m) << (e + 10 - 3);
if (!fh.Is_ContentSize_Defined()
|| fh.DictionaryId != 0
|| winSize_forAllocate > winSize)
winSize_forAllocate = winSize;
// p->are_WindowDescriptors = true;
}
else
{
// p->are_SingleSegments = True;
}
if (blockSizeAllowedMax > winSize)
blockSizeAllowedMax = (UInt32)winSize;
if (p->windowSize_MAX < winSize)
p->windowSize_MAX = winSize;
if (p->windowSize_Allocate_MAX < winSize_forAllocate)
p->windowSize_Allocate_MAX = winSize_forAllocate;
}
if (fh.Is_ContentSize_Defined())
{
// p->are_ContentSize_Known = True;
p->contentSize_Total += fh.ContentSize;
if (p->contentSize_MAX < fh.ContentSize)
p->contentSize_MAX = fh.ContentSize;
}
else
{
p->are_ContentSize_Unknown = True;
}
p->checksum_Defined = false;
// p->numBlocks_forType[3] += 99; // for debug
if (!_parseMode)
{
if (ZstdDecInfo_GET_NUM_FRAMES(p) == 1)
break;
}
_wasParsed = true;
bool blocksWereParsed = false;
for (;;)
{
if (callback && (p->num_Blocks & 0xFFF) == 2)
{
// Sleep(10);
const UInt64 numBytes = sb.GetCurOffset();
RINOK(callback->SetCompleted(NULL, &numBytes))
}
_phySize = sb.GetCurOffset() + 3;
RINOK(sb.Read(3))
if (sb.Avail() < 3)
{
// _needMoreInput = true;
// return S_FALSE;
break; // change it
}
const unsigned pos = sb.pos;
sb.pos = pos + 3;
UInt32 b = 0;
b += (UInt32)sb.buf[pos];
b += (UInt32)sb.buf[pos + 1] << (8 * 1);
b += (UInt32)sb.buf[pos + 2] << (8 * 2);
p->num_Blocks++;
const unsigned blockType = (b >> 1) & 3;
UInt32 size = b >> 3;
// p->num_Blocks_forType[blockType]++;
// p->num_BlockBytes_forType[blockType] += size;
if (size > blockSizeAllowedMax
|| blockType == kBlockType_Reserved)
{
_unsupportedBlock = true;
if (ZstdDecInfo_GET_NUM_FRAMES(p) == 1 && p->num_Blocks == 1)
return S_FALSE;
break;
}
if (blockType == kBlockType_RLE)
size = 1;
_phySize = sb.GetCurOffset() + size;
RINOK(sb.Skip(size))
if (b & 1)
{
// it's last block
blocksWereParsed = true;
break;
}
}
if (!blocksWereParsed)
break;
if (fh.Is_Checksum())
{
_phySize = sb.GetCurOffset() + 4;
RINOK(sb.Read(4))
if (sb.Avail() < 4)
break;
p->checksum_Defined = true;
// if (p->num_DataFrames == 1)
p->checksum = GetUi32(sb.GetPtr());
sb.SkipInBuf(4);
}
}
if (ZstdDecInfo_GET_NUM_FRAMES(p) == 0)
return S_FALSE;
_needSeekToStart = true;
// } // _parseMode
_isArc = true;
_stream = stream;
_seqStream = stream;
return S_OK;
COM_TRY_END
}
Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
{
Close();
_isArc = true;
_seqStream = stream;
return S_OK;
}
Z7_COM7F_IMF(CHandler::Close())
{
_isArc = false;
_needSeekToStart = false;
// _dataAfterEnd = false;
// _needMoreInput = false;
_unsupportedBlock = false;
_wasParsed = false;
_phySize_Decoded_Defined = false;
_unpackSize_Defined = false;
_decoded_Info_Defined = false;
ZstdDecInfo_CLEAR(&_parsed_Info)
ZstdDecInfo_CLEAR(&_decoded_Info)
_phySize = 0;
_phySize_Decoded = 0;
_unpackSize = 0;
_seqStream.Release();
_stream.Release();
return S_OK;
}
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;
if (_wasParsed)
{
RINOK(extractCallback->SetTotal(_phySize))
}
Int32 opRes;
{
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);
if (_needSeekToStart)
{
if (!_stream)
return E_FAIL;
RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL))
}
else
_needSeekToStart = true;
CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
lps->Init(extractCallback, true);
#ifdef Z7_USE_ZSTD_ORIG_DECODER
CMyComPtr2_Create<ICompressCoder, NCompress::NZstd2::CDecoder> decoder;
#else
CMyComPtr2_Create<ICompressCoder, NCompress::NZstd::CDecoder> decoder;
#endif
CMyComPtr2_Create<ISequentialOutStream, CDummyOutStream> outStreamSpec;
outStreamSpec->SetStream(realOutStream);
outStreamSpec->Init();
// realOutStream.Release();
decoder->FinishMode = true;
#ifndef Z7_USE_ZSTD_ORIG_DECODER
decoder->DisableHash = _disableHash;
#endif
// _dataAfterEnd = false;
// _needMoreInput = false;
const HRESULT hres = decoder.Interface()->Code(_seqStream, outStreamSpec, NULL, NULL, lps);
/*
{
UInt64 t1 = decoder->GetInputProcessedSize();
// for debug
const UInt32 kTempSize = 64;
Byte buf[kTempSize];
UInt32 processedSize = 0;
RINOK(decoder->ReadUnusedFromInBuf(buf, kTempSize, &processedSize))
processedSize -= processedSize;
UInt64 t2 = decoder->GetInputProcessedSize();
t2 = t2;
t1 = t1;
}
*/
const UInt64 outSize = outStreamSpec->GetSize();
// }
// if (hres == E_ABORT) return hres;
opRes = NExtract::NOperationResult::kDataError;
if (hres == E_OUTOFMEMORY)
{
return hres;
// opRes = NExtract::NOperationResult::kMemError;
}
else if (hres == S_OK || hres == S_FALSE)
{
#ifndef Z7_USE_ZSTD_ORIG_DECODER
_decoded_Info_Defined = true;
_decoded_Info = decoder->_state.info;
// NumDataFrames_Decoded = decoder->_state.info.num_DataFrames;
// NumSkipFrames_Decoded = decoder->_state.info.num_SkipFrames;
const UInt64 inSize = decoder->_inProcessed;
#else
const UInt64 inSize = decoder->GetInputProcessedSize();
#endif
_phySize_Decoded = inSize;
_phySize_Decoded_Defined = true;
_unpackSize_Defined = true;
_unpackSize = outSize;
// RINOK(
lps.Interface()->SetRatioInfo(&inSize, &outSize);
#ifdef Z7_USE_ZSTD_ORIG_DECODER
if (hres == S_OK)
opRes = NExtract::NOperationResult::kOK;
#else
if (decoder->ResInfo.decode_SRes == SZ_ERROR_CRC)
{
opRes = NExtract::NOperationResult::kCRCError;
}
else if (decoder->ResInfo.decode_SRes == SZ_ERROR_NO_ARCHIVE)
{
_isArc = false;
opRes = NExtract::NOperationResult::kIsNotArc;
}
else if (decoder->ResInfo.decode_SRes == SZ_ERROR_INPUT_EOF)
opRes = NExtract::NOperationResult::kUnexpectedEnd;
else
{
if (hres == S_OK && decoder->ResInfo.decode_SRes == SZ_OK)
opRes = NExtract::NOperationResult::kOK;
if (decoder->ResInfo.extraSize)
{
// if (inSize == 0) _isArc = false;
opRes = NExtract::NOperationResult::kDataAfterEnd;
}
/*
if (decoder->ResInfo.unexpededEnd)
opRes = NExtract::NOperationResult::kUnexpectedEnd;
*/
}
#endif
}
else if (hres == E_NOTIMPL)
{
opRes = NExtract::NOperationResult::kUnsupportedMethod;
}
else
return hres;
}
return extractCallback->SetOperationResult(opRes);
COM_TRY_END
}
Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
{
// return _props.SetProperties(names, values, numProps);
// _smallMode = false;
_disableHash = false;
_parseMode = false;
// _parseMode = true; // for debug
#ifdef Z7_USE_ZSTD_COMPRESSION
_props.Init();
#endif
for (UInt32 i = 0; i < numProps; i++)
{
UString name = names[i];
const PROPVARIANT &value = values[i];
if (name.IsEqualTo("parse"))
{
bool parseMode = true;
RINOK(PROPVARIANT_to_bool(value, parseMode))
_parseMode = parseMode;
continue;
}
if (name.IsPrefixedBy_Ascii_NoCase("crc"))
{
name.Delete(0, 3);
UInt32 crcSize = 4;
RINOK(ParsePropToUInt32(name, value, crcSize))
if (crcSize == 0)
_disableHash = true;
else if (crcSize == 4)
_disableHash = false;
else
return E_INVALIDARG;
continue;
}
#ifdef Z7_USE_ZSTD_COMPRESSION
/*
if (name.IsEqualTo("small"))
{
bool smallMode = true;
RINOK(PROPVARIANT_to_bool(value, smallMode))
_smallMode = smallMode;
continue;
}
*/
RINOK(_props.SetProperty(names[i], value))
#endif
}
return S_OK;
}
#ifdef Z7_USE_ZSTD_COMPRESSION
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 != 1)
return E_INVALIDARG;
{
CMyComPtr<IStreamSetRestriction> setRestriction;
outStream->QueryInterface(IID_IStreamSetRestriction, (void **)&setRestriction);
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 size;
{
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(0, kpidSize, &prop))
if (prop.vt != VT_UI8)
return E_INVALIDARG;
size = prop.uhVal.QuadPart;
}
if (!_props.MethodName.IsEmpty()
&& !_props.MethodName.IsEqualTo_Ascii_NoCase("zstd"))
return E_INVALIDARG;
{
CMyComPtr<ISequentialInStream> fileInStream;
RINOK(updateCallback->GetStream(0, &fileInStream))
if (!fileInStream)
return S_FALSE;
{
CMyComPtr<IStreamGetSize> streamGetSize;
fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
if (streamGetSize)
{
UInt64 size2;
if (streamGetSize->GetSize(&size2) == S_OK)
size = size2;
}
}
RINOK(updateCallback->SetTotal(size))
CMethodProps props2 = _props;
#ifndef Z7_ST
/*
CSingleMethodProps (_props)
derives from
CMethodProps (props2)
So we transfer additional variable (num Threads) to CMethodProps list of properties
*/
UInt32 numThreads = _props._numThreads;
if (numThreads > Z7_ZSTDMT_NBWORKERS_MAX)
numThreads = Z7_ZSTDMT_NBWORKERS_MAX;
if (_props.FindProp(NCoderPropID::kNumThreads) < 0)
{
if (!_props._numThreads_WasForced
&& numThreads >= 1
&& _props._memUsage_WasSet)
{
NCompress::NZstd::CEncoderProps zstdProps;
RINOK(zstdProps.SetFromMethodProps(_props))
ZstdEncProps_NormalizeFull(&zstdProps.EncProps);
numThreads = ZstdEncProps_GetNumThreads_for_MemUsageLimit(
&zstdProps.EncProps, _props._memUsage_Compress, numThreads);
}
props2.AddProp_NumThreads(numThreads);
}
#endif // Z7_ST
CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
lps->Init(updateCallback, true);
{
CMyComPtr2_Create<ICompressCoder, NCompress::NZstd::CEncoder> encoder;
// size = 1 << 24; // for debug
RINOK(props2.SetCoderProps(encoder.ClsPtr(), size != (UInt64)(Int64)-1 ? &size : NULL))
// encoderSpec->_props.SmallFileOpt = _smallMode;
// we must set kExpectedDataSize just before Code().
encoder->SrcSizeHint64 = size;
/*
CMyComPtr<ICompressSetCoderPropertiesOpt> optProps;
_compressEncoder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void**)&optProps);
if (optProps)
{
PROPID propID = NCoderPropID::kExpectedDataSize;
NWindows::NCOM::CPropVariant prop = (UInt64)size;
// RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1))
RINOK(encoderSpec->SetCoderPropertiesOpt(&propID, &prop, 1))
}
*/
RINOK(encoder.Interface()->Code(fileInStream, outStream, NULL, NULL, lps))
}
}
return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
}
if (indexInArchive != 0)
return E_INVALIDARG;
CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
lps->Init(updateCallback, true);
CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
if (opCallback)
{
RINOK(opCallback->ReportOperation(
NEventIndexType::kInArcIndex, 0,
NUpdateNotifyOp::kReplicate))
}
if (_stream)
RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL))
return NCompress::CopyStream(_stream, outStream, lps);
COM_TRY_END
}
#endif
#ifndef Z7_USE_ZSTD_COMPRESSION
#undef IMP_CreateArcOut
#define IMP_CreateArcOut
#undef CreateArcOut
#define CreateArcOut NULL
#endif
#ifdef Z7_USE_ZSTD_COMPRESSION
REGISTER_ARC_IO(
"zstd2", "zst tzst", "* .tar", 0xe + 1,
k_Signature, 0
, NArcInfoFlags::kKeepName
, 0
, NULL)
#else
REGISTER_ARC_IO(
"zstd", "zst tzst", "* .tar", 0xe,
k_Signature, 0
, NArcInfoFlags::kKeepName
, 0
, NULL)
#endif
}}