AuroraRuntime/Source/Compression/Compressors/BrotliDecompressor.hpp

120 lines
3.4 KiB
C++

/***
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<IO::IStreamReader> &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<uint8_t, size_t>(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<IO::IStreamReader> pReader_;
unsigned char din_[kChunkSize];
unsigned char dout_[kChunkSize];
uint8_t *pInBuffer;
size_t uAvailIn {};
BrotliDecoderState *pState {};
};
}