/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: LZ4Decompressor.hpp Date: 2022-2-15 Author: Reece ***/ #pragma once #include "lz4.h" #include "lz4frame.h" namespace Aurora::Compression { struct LZ4Inflate : BaseStream { DecompressInfo meta; LZ4Inflate(const DecompressInfo &meta) : meta(meta), BaseStream(meta.uInternalStreamSize) {} ~LZ4Inflate() { if (this->lz4Stream_) { LZ4F_freeDecompressionContext(this->lz4Stream_); } } bool Init(const AuSPtr &pReader) override { this->pReader_ = pReader; if (!this->IsValid()) { SysPushErrorMem(); return false; } auto err = LZ4F_createDecompressionContext(&this->lz4Stream_, LZ4F_getVersion()); if (LZ4F_isError(err)) { return {}; } auto bufferSize = meta.uInternalStreamSize; this->pBufferIn_ = AuSPtr(new char[bufferSize], AuDefaultDeleter()); if (!this->pBufferIn_) { return {}; } this->pBufferOut_ = AuSPtr(new char[bufferSize], AuDefaultDeleter()); if (!this->pBufferOut_) { return {}; } this->pReadPtr_ = this->pBufferIn_.get(); SetPointer(this->pReadPtr_, bufferSize); return true; } AuStreamReadWrittenPair_t Ingest_s(AuUInt32 input) override { bool ret = true; AuUInt32 inputStat = 0, outputStat = 0; size_t bytesRemInFrame {}; LZ4F_decompressOptions_t opts {}; auto bufferSize = meta.uInternalStreamSize; while (inputStat < input) { inputStat += IngestForInPointer(this->pReader_, this->pReadPtr_, this->uBufferInAvail_, input - inputStat); if (!this->uBufferInAvail_) { return {inputStat, outputStat}; } auto frameSize = bytesRemInFrame ? bytesRemInFrame : LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH; frameSize = LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH; if (this->uBufferInAvail_ < frameSize) { return {inputStat, outputStat}; } size_t frameSPtr = this->uBufferInAvail_; size_t frameS2Ptr = bufferSize; bytesRemInFrame = LZ4F_decompress(this->lz4Stream_, this->pBufferOut_.get(), &frameS2Ptr, this->pReadPtr_, &frameSPtr, &opts); if (LZ4F_isError(bytesRemInFrame)) { return {}; } this->pReadPtr_ += frameSPtr; outputStat += bytesRemInFrame; this->uBufferInAvail_ -= frameSPtr; if (frameS2Ptr) { if (!Write(this->pBufferOut_.get(), frameS2Ptr)) { SysPushErrorIO("Compression Out of Overhead"); return {}; } } inputStat += frameS2Ptr; } return AuMakePair(inputStat, outputStat); } private: AuSPtr pReader_; LZ4F_dctx* lz4Stream_ {}; AuSPtr pBufferIn_; AuSPtr pBufferOut_; char *pReadPtr_; AuUInt32 uBufferInAvail_ {}; }; }