7#include "../utility/utility.hpp"
8#include "../container/container.hpp"
9#include "../parser/parser.hpp"
10#include "../macros.hpp"
14hi_export_module(hikogui.codec.inflate);
16hi_export
namespace hi {
inline namespace v1 {
19inline void inflate_copy_block(std::span<std::byte const> bytes,
std::size_t& bit_offset,
std::size_t max_size, bstring& r)
21 auto offset = (bit_offset + 7) / 8;
23 auto LEN = **make_placement_ptr<little_uint16_buf_t>(bytes, offset);
24 [[maybe_unused]]
auto NLEN = **make_placement_ptr<little_uint16_buf_t>(bytes, offset);
26 hi_check((offset + LEN) <= bytes.size(),
"input buffer overrun");
27 hi_check((r.size() + LEN) <= max_size,
"output buffer overrun");
28 r.append(&bytes[offset], LEN);
30 bit_offset = offset * 8;
54 return get_bits(bytes, bit_offset, 1) + 11;
56 return get_bits(bytes, bit_offset, 1) + 13;
58 return get_bits(bytes, bit_offset, 1) + 15;
60 return get_bits(bytes, bit_offset, 1) + 17;
62 return get_bits(bytes, bit_offset, 2) + 19;
64 return get_bits(bytes, bit_offset, 2) + 23;
66 return get_bits(bytes, bit_offset, 2) + 27;
68 return get_bits(bytes, bit_offset, 2) + 31;
70 return get_bits(bytes, bit_offset, 3) + 35;
72 return get_bits(bytes, bit_offset, 3) + 43;
74 return get_bits(bytes, bit_offset, 3) + 51;
76 return get_bits(bytes, bit_offset, 3) + 59;
78 return get_bits(bytes, bit_offset, 4) + 67;
80 return get_bits(bytes, bit_offset, 4) + 83;
82 return get_bits(bytes, bit_offset, 4) + 99;
84 return get_bits(bytes, bit_offset, 4) + 115;
86 return get_bits(bytes, bit_offset, 5) + 131;
88 return get_bits(bytes, bit_offset, 5) + 163;
90 return get_bits(bytes, bit_offset, 5) + 195;
92 return get_bits(bytes, bit_offset, 5) + 227;
96 throw parse_error(std::format(
"Literal/Length symbol out of range {}", symbol));
113 return get_bits(bytes, bit_offset, 1) + 5;
115 return get_bits(bytes, bit_offset, 1) + 7;
117 return get_bits(bytes, bit_offset, 2) + 9;
119 return get_bits(bytes, bit_offset, 2) + 13;
121 return get_bits(bytes, bit_offset, 3) + 17;
123 return get_bits(bytes, bit_offset, 3) + 25;
125 return get_bits(bytes, bit_offset, 4) + 33;
127 return get_bits(bytes, bit_offset, 4) + 49;
129 return get_bits(bytes, bit_offset, 5) + 65;
131 return get_bits(bytes, bit_offset, 5) + 97;
133 return get_bits(bytes, bit_offset, 6) + 129;
135 return get_bits(bytes, bit_offset, 6) + 193;
137 return get_bits(bytes, bit_offset, 7) + 257;
139 return get_bits(bytes, bit_offset, 7) + 385;
141 return get_bits(bytes, bit_offset, 8) + 513;
143 return get_bits(bytes, bit_offset, 8) + 769;
145 return get_bits(bytes, bit_offset, 9) + 1025;
147 return get_bits(bytes, bit_offset, 9) + 1537;
149 return get_bits(bytes, bit_offset, 10) + 2049;
151 return get_bits(bytes, bit_offset, 10) + 3073;
153 return get_bits(bytes, bit_offset, 11) + 4097;
155 return get_bits(bytes, bit_offset, 11) + 6145;
157 return get_bits(bytes, bit_offset, 12) + 8193;
159 return get_bits(bytes, bit_offset, 12) + 12289;
161 return get_bits(bytes, bit_offset, 13) + 16385;
163 return get_bits(bytes, bit_offset, 13) + 24577;
165 throw parse_error(std::format(
"Distance symbol out of range {}", symbol));
169inline void inflate_block(
170 std::span<std::byte const> bytes,
173 huffman_tree<int16_t>
const& literal_tree,
174 huffman_tree<int16_t>
const& distance_tree,
182 hi_check(((bit_offset + 27) >> 3) <= bytes.size(),
"Input buffer overrun");
184 auto const literal_symbol = literal_tree.get_symbol(bytes, bit_offset);
186 if (literal_symbol <= 255) {
187 hi_check(r.size() < max_size,
"Output buffer overrun");
188 r.push_back(
static_cast<std::byte
>(literal_symbol));
190 }
else if (literal_symbol == 256) {
195 auto const length = inflate_decode_length(bytes, bit_offset, literal_symbol);
196 hi_check(r.size() + length <= max_size,
"Output buffer overrun");
201 hi_check(((bit_offset + 22) >> 3) <= bytes.size(),
"Input buffer overrun");
202 auto const distance_symbol = distance_tree.get_symbol(bytes, bit_offset);
207 hi_check(((bit_offset + 20) >> 3) <= bytes.size(),
"Input buffer overrun");
208 auto const distance = inflate_decode_distance(bytes, bit_offset, distance_symbol);
210 hi_check(distance <= r.size(),
"Distance beyond start of decompressed data");
212 for (
auto i = 0; i != length; ++i) {
213 r.push_back(r[src_i++]);
219inline huffman_tree<int16_t> deflate_fixed_literal_tree = []() {
222 for (
int i = 0; i <= 143; ++i) {
225 for (
int i = 144; i <= 255; ++i) {
228 for (
int i = 256; i <= 279; ++i) {
231 for (
int i = 280; i <= 287; ++i) {
238inline huffman_tree<int16_t> deflate_fixed_distance_tree = []() {
241 for (
int i = 0; i <= 31; ++i) {
248inline void inflate_fixed_block(std::span<std::byte const> bytes,
std::size_t& bit_offset,
std::size_t max_size, bstring& r)
250 inflate_block(bytes, bit_offset, max_size, deflate_fixed_literal_tree, deflate_fixed_distance_tree, r);
253[[nodiscard]]
inline huffman_tree<int16_t>
257 constexpr auto symbols =
std::array<int16_t, 19>{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
259 hi_check(((bit_offset + (3 *
static_cast<std::size_t>(nr_symbols)) + 7) >> 3) <= bytes.size(),
"Input buffer overrun");
262 for (
auto i = 0_uz; i != nr_symbols; ++i) {
263 auto const symbol = symbols[i];
264 lengths[symbol] = narrow_cast<uint8_t>(
get_bits(bytes, bit_offset, 3));
270 std::span<std::byte const> bytes,
273 huffman_tree<int16_t>
const& code_length_tree)
278 auto prev_length = 0_uz;
279 while (r.size() < nr_symbols) {
284 hi_check(((bit_offset + 21) >> 3) <= bytes.size(),
"Input buffer overrun");
285 auto const symbol = code_length_tree.get_symbol(bytes, bit_offset);
290 auto copy_length =
get_bits(bytes, bit_offset, 2) + 3;
291 while (copy_length--) {
292 r.push_back(
static_cast<uint8_t
>(prev_length));
298 auto copy_length =
get_bits(bytes, bit_offset, 3) + 3;
299 while (copy_length--) {
306 auto copy_length =
get_bits(bytes, bit_offset, 7) + 11;
307 while (copy_length--) {
313 r.push_back(
static_cast<uint8_t
>(prev_length = symbol));
320inline void inflate_dynamic_block(std::span<std::byte const> bytes,
std::size_t& bit_offset,
std::size_t max_size, bstring& r)
325 hi_check(((bit_offset + 21) >> 3) <= bytes.size(),
"Input buffer overrun");
326 auto const HLIT =
get_bits(bytes, bit_offset, 5);
327 auto const HDIST =
get_bits(bytes, bit_offset, 5);
328 auto const HCLEN =
get_bits(bytes, bit_offset, 4);
330 auto const code_length_tree = inflate_code_lengths(bytes, bit_offset, HCLEN + 4);
332 auto const lengths = inflate_lengths(bytes, bit_offset, HLIT + HDIST + 258, code_length_tree);
333 hi_check(lengths[256] != 0,
"The end-of-block symbol must be in the table");
335 auto const lengths_ptr = lengths.
data();
336 hi_assert_not_null(lengths_ptr);
340 inflate_block(bytes, bit_offset, max_size, literal_tree, distance_tree, r);
357hi_export [[nodiscard]]
inline bstring
369 hi_check(((bit_offset + 10) >> 3) <= bytes.size(),
"Input buffer overrun");
371 BFINAL =
get_bit(bytes, bit_offset);
372 auto const BTYPE =
get_bits(bytes, bit_offset, 2);
376 detail::inflate_copy_block(bytes, bit_offset, max_size, r);
379 detail::inflate_fixed_block(bytes, bit_offset, max_size, r);
382 detail::inflate_dynamic_block(bytes, bit_offset, max_size, r);
390 offset = (bit_offset + 7) / 8;
The HikoGUI namespace.
Definition array_generic.hpp:20
std::size_t get_bits(std::span< std::byte const > buffer, std::size_t &index, std::size_t length) noexcept
Read a bits from of span of bytes Bits are ordered LSB first.
Definition bits.hpp:55
bool get_bit(std::span< std::byte const > buffer, std::size_t &index) noexcept
Read a single bit from span of bytes Bits are ordered LSB first.
Definition bits.hpp:27
hi_export bstring inflate(std::span< std::byte const > bytes, std::size_t &offset, std::size_t max_size=0x0100 '0000)
Inflate compressed data using the deflate algorithm bytes should include at least 32 bit of trailer,...
Definition inflate.hpp:358
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
static huffman_tree from_lengths(uint8_t const *lengths, std::size_t nr_symbols)
Build a canonical-huffman table from a set of lengths.
Definition huffman.hpp:122
Exception thrown during parsing on an error.
Definition exception_intf.hpp:48