mirror of
https://github.com/Xevion/easy7zip.git
synced 2026-02-01 08:24:14 -06:00
Switch to Zstandard's New advanced API.
- long distance matching is enabled - the compression should improve, the speed also - decompression code is single threaded only
This commit is contained in:
@@ -1,115 +1,53 @@
|
||||
// (C) 2016 Tino Reichardt
|
||||
// (C) 2016 - 2018 Tino Reichardt
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "ZstdDecoder.h"
|
||||
|
||||
int ZstdRead(void *arg, ZSTDCB_Buffer * in)
|
||||
{
|
||||
struct ZstdStream *x = (struct ZstdStream*)arg;
|
||||
size_t size = in->size;
|
||||
|
||||
HRESULT res = ReadStream(x->inStream, in->buf, &size);
|
||||
|
||||
/* catch errors */
|
||||
switch (res) {
|
||||
case E_ABORT:
|
||||
return -2;
|
||||
case E_OUTOFMEMORY:
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* some other error -> read_fail */
|
||||
if (res != S_OK)
|
||||
return -1;
|
||||
|
||||
in->size = size;
|
||||
*x->processedIn += size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ZstdWrite(void *arg, ZSTDCB_Buffer * out)
|
||||
{
|
||||
struct ZstdStream *x = (struct ZstdStream*)arg;
|
||||
UInt32 todo = (UInt32)out->size;
|
||||
UInt32 done = 0;
|
||||
|
||||
while (todo != 0)
|
||||
{
|
||||
UInt32 block;
|
||||
HRESULT res = x->outStream->Write((char*)out->buf + done, todo, &block);
|
||||
|
||||
/* catch errors */
|
||||
switch (res) {
|
||||
case E_ABORT:
|
||||
return -2;
|
||||
case E_OUTOFMEMORY:
|
||||
return -3;
|
||||
}
|
||||
|
||||
done += block;
|
||||
if (res == k_My_HRESULT_WritingWasCut)
|
||||
break;
|
||||
/* some other error -> write_fail */
|
||||
if (res != S_OK)
|
||||
return -1;
|
||||
|
||||
if (block == 0)
|
||||
return -1;
|
||||
todo -= block;
|
||||
}
|
||||
|
||||
*x->processedOut += done;
|
||||
/* we need no lock here, cause only one thread can write... */
|
||||
if (x->progress)
|
||||
x->progress->SetRatioInfo(x->processedIn, x->processedOut);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace NCompress {
|
||||
namespace NZSTD {
|
||||
|
||||
CDecoder::CDecoder():
|
||||
_ctx(NULL),
|
||||
_srcBuf(NULL),
|
||||
_dstBuf(NULL),
|
||||
_srcBufSize(ZSTD_DStreamInSize()),
|
||||
_dstBufSize(ZSTD_DStreamOutSize()),
|
||||
_processedIn(0),
|
||||
_processedOut(0),
|
||||
_inputSize(0),
|
||||
_numThreads(NWindows::NSystem::GetNumberOfProcessors())
|
||||
|
||||
{
|
||||
_props.clear();
|
||||
_hMutex = CreateMutex(NULL, FALSE, NULL);
|
||||
}
|
||||
|
||||
CDecoder::~CDecoder()
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT CDecoder::ErrorOut(size_t code)
|
||||
{
|
||||
const char *strError = ZSTDCB_getErrorString(code);
|
||||
wchar_t wstrError[200+5]; /* no malloc here, /TR */
|
||||
|
||||
mbstowcs(wstrError, strError, 200);
|
||||
MessageBoxW(0, wstrError, L"7-Zip Zstandard", MB_ICONERROR | MB_OK);
|
||||
MyFree(wstrError);
|
||||
|
||||
return S_FALSE;
|
||||
if (_ctx) {
|
||||
ZSTD_freeDCtx(_ctx);
|
||||
MyFree(_srcBuf);
|
||||
MyFree(_dstBuf);
|
||||
CloseHandle(_hMutex);
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte * prop, UInt32 size)
|
||||
{
|
||||
DProps *pProps = (DProps *)prop;
|
||||
|
||||
if (size != sizeof(DProps))
|
||||
switch (size) {
|
||||
case 3:
|
||||
case 5:
|
||||
memcpy(&_props, pProps, sizeof (DProps));
|
||||
return S_OK;
|
||||
default:
|
||||
return E_NOTIMPL;
|
||||
|
||||
memcpy(&_props, pProps, sizeof (DProps));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetNumberOfThreads(UInt32 numThreads)
|
||||
{
|
||||
const UInt32 kNumThreadsMax = ZSTDCB_THREAD_MAX;
|
||||
const UInt32 kNumThreadsMax = ZSTD_THREAD_MAX;
|
||||
if (numThreads < 1) numThreads = 1;
|
||||
if (numThreads > kNumThreadsMax) numThreads = kNumThreadsMax;
|
||||
_numThreads = numThreads;
|
||||
@@ -132,42 +70,55 @@ STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 * outSize)
|
||||
HRESULT CDecoder::CodeSpec(ISequentialInStream * inStream,
|
||||
ISequentialOutStream * outStream, ICompressProgressInfo * progress)
|
||||
{
|
||||
ZSTDCB_RdWr_t rdwr;
|
||||
size_t result;
|
||||
HRESULT res = S_OK;
|
||||
/* 1) create context */
|
||||
if (!_ctx) {
|
||||
_ctx = ZSTD_createDCtx();
|
||||
if (!_ctx)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
struct ZstdStream Rd;
|
||||
Rd.inStream = inStream;
|
||||
Rd.processedIn = &_processedIn;
|
||||
_srcBuf = MyAlloc(_srcBufSize);
|
||||
if (!_srcBuf)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
struct ZstdStream Wr;
|
||||
Wr.progress = progress;
|
||||
Wr.outStream = outStream;
|
||||
Wr.processedIn = &_processedIn;
|
||||
Wr.processedOut = &_processedOut;
|
||||
|
||||
/* 1) setup read/write functions */
|
||||
rdwr.fn_read = ::ZstdRead;
|
||||
rdwr.fn_write = ::ZstdWrite;
|
||||
rdwr.arg_read = (void *)&Rd;
|
||||
rdwr.arg_write = (void *)&Wr;
|
||||
|
||||
/* 2) create decompression context */
|
||||
ZSTDCB_DCtx *ctx = ZSTDCB_createDCtx(_numThreads, _inputSize);
|
||||
if (!ctx)
|
||||
return S_FALSE;
|
||||
|
||||
/* 3) decompress */
|
||||
result = ZSTDCB_decompressDCtx(ctx, &rdwr);
|
||||
if (ZSTDCB_isError(result)) {
|
||||
if (result == (size_t)-ZSTDCB_error_canceled)
|
||||
return E_ABORT;
|
||||
return ErrorOut(result);
|
||||
_dstBuf = MyAlloc(_dstBufSize);
|
||||
if (!_dstBuf)
|
||||
return E_OUTOFMEMORY;
|
||||
} else {
|
||||
ZSTD_resetDStream(_ctx);
|
||||
}
|
||||
|
||||
/* 4) free resources */
|
||||
ZSTDCB_freeDCtx(ctx);
|
||||
return res;
|
||||
for (;;) {
|
||||
size_t size = _srcBufSize;
|
||||
RINOK(ReadStream(inStream, _srcBuf, &size));
|
||||
for (;;) {
|
||||
ZSTD_inBuffer inBuff = { _srcBuf, size, 0 };
|
||||
ZSTD_outBuffer outBuff= { _dstBuf, _dstBufSize, 0 };
|
||||
size_t const readSizeHint = ZSTD_decompressStream(_ctx, &outBuff, &inBuff);
|
||||
|
||||
if (ZSTD_isError(readSizeHint))
|
||||
return E_FAIL;
|
||||
|
||||
/* write decompressed data */
|
||||
RINOK(WriteStream(outStream, _dstBuf, outBuff.pos));
|
||||
WaitForSingleObject(_hMutex, INFINITE);
|
||||
_processedOut += outBuff.pos;
|
||||
RINOK(progress->SetRatioInfo(&_processedIn, &_processedOut));
|
||||
ReleaseMutex(_hMutex);
|
||||
|
||||
if (inBuff.pos > 0) {
|
||||
memmove(_srcBuf, (char*)_srcBuf + inBuff.pos, inBuff.size - inBuff.pos);
|
||||
size = _srcBufSize - inBuff.pos;
|
||||
RINOK(ReadStream(inStream, (char*)_srcBuf + inBuff.pos, &size));
|
||||
}
|
||||
|
||||
if (inBuff.size != inBuff.pos)
|
||||
return E_FAIL;
|
||||
|
||||
/* eof */
|
||||
if (readSizeHint == 0)
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::Code(ISequentialInStream * inStream, ISequentialOutStream * outStream,
|
||||
|
||||
Reference in New Issue
Block a user