#include "InflateReader.h" #include #include namespace { constexpr size_t INFLATE_DICT_SIZE = 32768; } // Guarantee the cast pattern in the header comment is valid. static_assert(std::is_standard_layout::value, "InflateReader must be standard-layout for the uzlib callback cast to work"); InflateReader::~InflateReader() { deinit(); } bool InflateReader::init(const bool streaming) { deinit(); // free any previously allocated ring buffer and reset state if (streaming) { ringBuffer = static_cast(malloc(INFLATE_DICT_SIZE)); if (!ringBuffer) return false; memset(ringBuffer, 0, INFLATE_DICT_SIZE); } uzlib_uncompress_init(&decomp, ringBuffer, ringBuffer ? INFLATE_DICT_SIZE : 0); return true; } void InflateReader::deinit() { if (ringBuffer) { free(ringBuffer); ringBuffer = nullptr; } memset(&decomp, 0, sizeof(decomp)); } void InflateReader::setSource(const uint8_t* src, size_t len) { decomp.source = src; decomp.source_limit = src + len; } void InflateReader::setReadCallback(int (*cb)(struct uzlib_uncomp*)) { decomp.source_read_cb = cb; } void InflateReader::skipZlibHeader() { uzlib_get_byte(&decomp); uzlib_get_byte(&decomp); } bool InflateReader::read(uint8_t* dest, size_t len) { if (!ringBuffer) { // One-shot mode: back-references use absolute offset from dest_start. // Valid only when read() is called once with the full output buffer. decomp.dest_start = dest; } decomp.dest = dest; decomp.dest_limit = dest + len; const int res = uzlib_uncompress(&decomp); if (res < 0) return false; return decomp.dest == decomp.dest_limit; } InflateStatus InflateReader::readAtMost(uint8_t* dest, size_t maxLen, size_t* produced) { if (!ringBuffer) { // One-shot mode: back-references use absolute offset from dest_start. // Valid only when readAtMost() is called once with the full output buffer. decomp.dest_start = dest; } decomp.dest = dest; decomp.dest_limit = dest + maxLen; const int res = uzlib_uncompress(&decomp); *produced = static_cast(decomp.dest - dest); if (res == TINF_DONE) return InflateStatus::Done; if (res < 0) return InflateStatus::Error; return InflateStatus::Ok; }