/*** 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 : public BaseStream { DecompressInfo meta; ZSTDInflate(const DecompressInfo &meta) : meta(meta), BaseStream(meta.internalStreamSize) {} ~ZSTDInflate() { if (auto dctx = AuExchange(dctx_, {})) { ZSTD_freeDCtx(dctx); } } bool Init(const AuSPtr &reader) { size_t ret; this->reader_ = reader; this->dctx_ = ZSTD_createDCtx(); if (!this->dctx_) { SysPushErrorGen("Couldn't create decompressor"); return false; } if (!this->_outbuffer) { SysPushErrorMem(); return false; } this->curPtr_ = this->din_; this->availIn_ = 0; SetArray(this->din_); return true; } AuStreamReadWrittenPair_t Ingest_s(AuUInt32 input) override { AuUInt32 length = ZSTD_DStreamInSize(); AuUInt32 outFrameLength = ZSTD_DStreamOutSize(); AuUInt32 done {}, read {}; while (read < input) { read += IngestForInPointer(this->reader_, this->curPtr_, this->availIn_, input - read); if (!this->availIn_) { return {read, done}; } this->input_ = ZSTD_inBuffer {this->curPtr_, this->availIn_, 0}; while (this->input_.pos < this->input_.size) { ZSTD_outBuffer output = {this->dout_, outFrameLength, 0}; auto ret = ZSTD_decompressStream(this->dctx_, &output, &this->input_); if (ZSTD_isError(ret)) { SysPushErrorIO("Compression error: {}", ZSTD_getErrorName(ret)); this->availIn_ -= output.pos; return AuMakePair(read, 0); } done += output.pos; if (!Write(reinterpret_cast(output.dst), output.pos)) { return AuMakePair(read, 0); } } this->availIn_ -= this->input_.pos; } return {read, done}; } private: AuSPtr reader_; ZSTD_DCtx *dctx_; char din_[ZSTD_BLOCKSIZE_MAX + 3 /*ZSTD_BLOCKHEADERSIZE*/]; char dout_[ZSTD_BLOCKSIZE_MAX]; char *curPtr_; AuUInt32 availIn_; ZSTD_inBuffer input_; }; }