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:
Tino Reichardt
2018-10-26 00:09:25 +02:00
parent cc10eb2d9b
commit 739ec50c75
15 changed files with 207 additions and 235 deletions
+67 -116
View File
@@ -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,