A fork of https://github.com/crosspoint-reader/crosspoint-reader
1#include "InflateReader.h"
2
3#include <cstring>
4#include <type_traits>
5
6namespace {
7constexpr size_t INFLATE_DICT_SIZE = 32768;
8}
9
10// Guarantee the cast pattern in the header comment is valid.
11static_assert(std::is_standard_layout<InflateReader>::value,
12 "InflateReader must be standard-layout for the uzlib callback cast to work");
13
14InflateReader::~InflateReader() { deinit(); }
15
16bool InflateReader::init(const bool streaming) {
17 deinit(); // free any previously allocated ring buffer and reset state
18
19 if (streaming) {
20 ringBuffer = static_cast<uint8_t*>(malloc(INFLATE_DICT_SIZE));
21 if (!ringBuffer) return false;
22 memset(ringBuffer, 0, INFLATE_DICT_SIZE);
23 }
24
25 uzlib_uncompress_init(&decomp, ringBuffer, ringBuffer ? INFLATE_DICT_SIZE : 0);
26 return true;
27}
28
29void InflateReader::deinit() {
30 if (ringBuffer) {
31 free(ringBuffer);
32 ringBuffer = nullptr;
33 }
34 memset(&decomp, 0, sizeof(decomp));
35}
36
37void InflateReader::setSource(const uint8_t* src, size_t len) {
38 decomp.source = src;
39 decomp.source_limit = src + len;
40}
41
42void InflateReader::setReadCallback(int (*cb)(struct uzlib_uncomp*)) { decomp.source_read_cb = cb; }
43
44void InflateReader::skipZlibHeader() {
45 uzlib_get_byte(&decomp);
46 uzlib_get_byte(&decomp);
47}
48
49bool InflateReader::read(uint8_t* dest, size_t len) {
50 if (!ringBuffer) {
51 // One-shot mode: back-references use absolute offset from dest_start.
52 // Valid only when read() is called once with the full output buffer.
53 decomp.dest_start = dest;
54 }
55 decomp.dest = dest;
56 decomp.dest_limit = dest + len;
57
58 const int res = uzlib_uncompress(&decomp);
59 if (res < 0) return false;
60 return decomp.dest == decomp.dest_limit;
61}
62
63InflateStatus InflateReader::readAtMost(uint8_t* dest, size_t maxLen, size_t* produced) {
64 if (!ringBuffer) {
65 // One-shot mode: back-references use absolute offset from dest_start.
66 // Valid only when readAtMost() is called once with the full output buffer.
67 decomp.dest_start = dest;
68 }
69 decomp.dest = dest;
70 decomp.dest_limit = dest + maxLen;
71
72 const int res = uzlib_uncompress(&decomp);
73 *produced = static_cast<size_t>(decomp.dest - dest);
74
75 if (res == TINF_DONE) return InflateStatus::Done;
76 if (res < 0) return InflateStatus::Error;
77 return InflateStatus::Ok;
78}