/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: ZSTDDecompressor.hpp Date: 2022-2-15 Author: Reece ***/ #pragma once #include "zstd.h" namespace Aurora::Compression { struct ZSTDInflate : BaseStream { DecompressInfo meta; ZSTDInflate(const DecompressInfo &meta) : meta(meta), BaseStream(meta.uInternalStreamSize) {} ~ZSTDInflate() { if (auto dctx = AuExchange(this->dctx_, {})) { ZSTD_freeDCtx(dctx); } } bool Init(const AuSPtr &pReader) override { this->pReader_ = pReader; this->dctx_ = ZSTD_createDCtx(); if (!this->IsValid()) { SysPushErrorMem(); return false; } if (!this->dctx_) { SysPushErrorGen("Couldn't create decompressor"); return false; } for (const auto &[a, b] : meta.options) { auto uRet = ZSTD_DCtx_setParameter(this->dctx_, (ZSTD_dParameter)a, b); if (ZSTD_isError(uRet)) { SysPushErrorArg("Decompressor argument assignment {} = {}", a, b); this->SetLastError(uRet, ZSTD_getErrorName(uRet)); return false; } } this->pIterator_ = this->din_; this->uAvailableIn_ = 0; this->SetArray(this->din_); this->SetOutArray(this->dout_); return true; } AuStreamReadWrittenPair_t Ingest_s(AuUInt32 input) override { AuUInt32 uLength = AuUInt32(ZSTD_DStreamInSize()); AuUInt32 uOutFrameLength = AuUInt32(ZSTD_DStreamOutSize()); AuUInt32 done {}, read {}; if (!this->pReader_) { return {}; } while (read < input) { read += IngestForInPointer(this->pReader_, this->pIterator_, this->uAvailableIn_, input - read, this); if (!this->uAvailableIn_) { return {read, done}; } this->input_ = ZSTD_inBuffer {this->pIterator_, this->uAvailableIn_, 0}; while (this->input_.pos < this->input_.size) { auto [pMainDOut, uMainDOutLength] = this->GetDOutPair(); ZSTD_outBuffer output = { pMainDOut, uMainDOutLength, 0 }; auto ret = ZSTD_decompressStream(this->dctx_, &output, &this->input_); if (ZSTD_isError(ret)) { this->SetLastError(ret, ZSTD_getErrorName(ret)); this->pReader_.reset(); return AuMakePair(read, 0); } done += AuUInt32(output.pos); if (!Write2(reinterpret_cast(pMainDOut), AuUInt32(output.pos))) { this->pReader_.reset(); this->SetLastError(0x69, "OOM"); return AuMakePair(read, 0); } } this->uAvailableIn_ = 0; } return {read, done}; } private: AuSPtr pReader_; ZSTD_DCtx *dctx_ {}; char din_[ZSTD_BLOCKSIZE_MAX + 3 /*ZSTD_BLOCKHEADERSIZE*/]; char dout_[ZSTD_BLOCKSIZE_MAX]; char *pIterator_ {}; AuUInt32 uAvailableIn_ {}; ZSTD_inBuffer input_; }; }