/*** 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 { class LZ4Inflate : public BaseStream { AuSPtr bufferIn_; AuSPtr bufferOut_; char *readPtr_; AuUInt32 bufferInAvail {}; public: DecompressInfo meta; LZ4Inflate(const DecompressInfo &meta) : meta(meta), BaseStream(meta.internalStreamSize) {} ~LZ4Inflate() { if (this->lz4Stream_) { LZ4F_freeDecompressionContext(this->lz4Stream_); } } bool Init(const AuSPtr &reader) { this->reader_ = reader; auto err = LZ4F_createDecompressionContext(&this->lz4Stream_, LZ4F_getVersion()); if (LZ4F_isError(err)) { return {}; } auto bufferSize = meta.internalStreamSize; this->bufferIn_ = AuSPtr(new char[bufferSize], AuDefaultDeleter()); if (!this->bufferIn_) { return {}; } this->bufferOut_ = AuSPtr(new char[bufferSize], AuDefaultDeleter()); if (!this->bufferOut_) { return {}; } this->readPtr_ = this->bufferIn_.get(); SetPointer(this->readPtr_, 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.internalStreamSize; while (inputStat < input) { inputStat += IngestForInPointer(this->reader_, this->readPtr_, this->bufferInAvail, input - inputStat); if (!this->bufferInAvail) { return {inputStat, outputStat}; } auto frameSize = bytesRemInFrame ? bytesRemInFrame : LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH; frameSize = LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH; if (this->bufferInAvail < frameSize) { return {inputStat, outputStat}; } size_t frameSPtr = this->bufferInAvail; size_t frameS2Ptr = bufferSize; bytesRemInFrame = LZ4F_decompress(this->lz4Stream_, this->bufferOut_.get(), &frameS2Ptr, this->readPtr_, &frameSPtr, &opts); if (LZ4F_isError(bytesRemInFrame)) { return {}; } this->readPtr_ += frameSPtr; this->bufferInAvail -= frameSPtr; if (frameS2Ptr) { if (!Write(this->bufferOut_.get(), frameS2Ptr)) { return {}; } } outputStat += frameS2Ptr; } return {inputStat, outputStat}; } private: AuSPtr reader_; LZ4F_dctx* lz4Stream_ {}; }; }