/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: BrotliDecompressor.hpp Date: 2023-3-12 Author: Reece ***/ #pragma once #include "brotli/decode.h" namespace Aurora::Compression { struct BrotliInflate : BaseStream { DecompressInfo meta; BrotliInflate(const DecompressInfo &meta) : meta(meta), BaseStream(meta.uInternalStreamSize) { } ~BrotliInflate() { if (this->pState) { BrotliDecoderDestroyInstance(this->pState); } } bool Init(const AuSPtr &reader) override { int ret; this->pReader_ = reader; if (!this->IsValid()) { SysPushErrorMem(); return false; } this->pState = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr); if (!this->pState) { SysPushErrorMem("No brotli decoder"); return false; } for (const auto &[a, b] : meta.options) { if (!BrotliDecoderSetParameter(this->pState, (BrotliDecoderParameter)a, b)) { SysPushErrorArg("Decompressor argument assignment {} = {}", a, b); return false; } } this->SetArray(this->din_); this->SetOutArray(this->dout_); return true; } AuStreamReadWrittenPair_t Ingest_s(AuUInt32 input) override { AuUInt32 done {}, read {}; if (!this->pReader_) { return {}; } while (read < input) { read += IngestForInPointer(this->pReader_, this->pInBuffer, this->uAvailIn, input - read, this); if (!this->uAvailIn) { return { read, done }; } size_t outNext {}; uint8_t *pOut {}; do { auto [pMainDOut, uMainDOutLength] = this->GetDOutPair(); outNext = uMainDOutLength; pOut = (uint8_t *)pMainDOut; auto ret = BrotliDecoderDecompressStream(this->pState, &this->uAvailIn, (const uint8_t **)&this->pInBuffer, &outNext, &pOut, nullptr); if (ret == BROTLI_DECODER_RESULT_ERROR) { this->SetLastError(ret, BrotliDecoderErrorString((BrotliDecoderErrorCode)ret)); this->pReader_.reset(); return AuMakePair(read, 0); } auto have = uMainDOutLength - outNext; done += have; if (!Write2(pMainDOut, have)) { this->pReader_.reset(); this->SetLastError(0x69, "OOM"); return AuMakePair(read, 0); } } while (outNext == 0); } return { read, done }; } private: AuSPtr pReader_; unsigned char din_[kChunkSize]; unsigned char dout_[kChunkSize]; uint8_t *pInBuffer; size_t uAvailIn {}; BrotliDecoderState *pState {}; }; }