heatshrink 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 553a73f5cb2ee340e54986732cf2cef0d023fa38
4
+ data.tar.gz: 9d91a1831172c3dd7228f34cb960b1242122a791
5
+ SHA512:
6
+ metadata.gz: 75f14d29b24602c4be64f29ec5f1a6b9c4f753932a9d4ea6e33d5c0544c979076014c29e7d0767398950728403b7a6b6388854047cb941ed6baeb60e63ecbdd6
7
+ data.tar.gz: 7e5200d8225ec2f81f71e6907bdf82867d4b5a64457b8ab5821875c613bd0a7765986b7327a6726925cbfb0df81befd0e17c5a05c11aa0f2e1ac61f5572ec4f5
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+ $CFLAGS += ' -Wno-declaration-after-statement -std=c99'
3
+ create_makefile 'heatshrink/heatshrink'
@@ -0,0 +1,20 @@
1
+ #ifndef HEATSHRINK_H
2
+ #define HEATSHRINK_H
3
+
4
+ #define HEATSHRINK_AUTHOR "Scott Vokes <scott.vokes@atomicobject.com>"
5
+ #define HEATSHRINK_URL "https://github.com/atomicobject/heatshrink"
6
+
7
+ /* Version 0.4.0 */
8
+ #define HEATSHRINK_VERSION_MAJOR 0
9
+ #define HEATSHRINK_VERSION_MINOR 4
10
+ #define HEATSHRINK_VERSION_PATCH 0
11
+
12
+ #define HEATSHRINK_MIN_WINDOW_BITS 4
13
+ #define HEATSHRINK_MAX_WINDOW_BITS 15
14
+
15
+ #define HEATSHRINK_MIN_LOOKAHEAD_BITS 3
16
+
17
+ #define HEATSHRINK_LITERAL_MARKER 0x01
18
+ #define HEATSHRINK_BACKREF_MARKER 0x00
19
+
20
+ #endif
@@ -0,0 +1,26 @@
1
+ #ifndef HEATSHRINK_CONFIG_H
2
+ #define HEATSHRINK_CONFIG_H
3
+
4
+ /* Should functionality assuming dynamic allocation be used? */
5
+ #ifndef HEATSHRINK_DYNAMIC_ALLOC
6
+ #define HEATSHRINK_DYNAMIC_ALLOC 1
7
+ #endif
8
+
9
+ #if HEATSHRINK_DYNAMIC_ALLOC
10
+ /* Optional replacement of malloc/free */
11
+ #define HEATSHRINK_MALLOC(SZ) malloc(SZ)
12
+ #define HEATSHRINK_FREE(P, SZ) free(P)
13
+ #else
14
+ /* Required parameters for static configuration */
15
+ #define HEATSHRINK_STATIC_INPUT_BUFFER_SIZE 32
16
+ #define HEATSHRINK_STATIC_WINDOW_BITS 8
17
+ #define HEATSHRINK_STATIC_LOOKAHEAD_BITS 4
18
+ #endif
19
+
20
+ /* Turn on logging for debugging. */
21
+ #define HEATSHRINK_DEBUGGING_LOGS 0
22
+
23
+ /* Use indexing for faster compression. (This requires additional space.) */
24
+ #define HEATSHRINK_USE_INDEX 1
25
+
26
+ #endif
@@ -0,0 +1,367 @@
1
+ #include <stdlib.h>
2
+ #include <string.h>
3
+ #include "heatshrink_decoder.h"
4
+
5
+ /* States for the polling state machine. */
6
+ typedef enum {
7
+ HSDS_TAG_BIT, /* tag bit */
8
+ HSDS_YIELD_LITERAL, /* ready to yield literal byte */
9
+ HSDS_BACKREF_INDEX_MSB, /* most significant byte of index */
10
+ HSDS_BACKREF_INDEX_LSB, /* least significant byte of index */
11
+ HSDS_BACKREF_COUNT_MSB, /* most significant byte of count */
12
+ HSDS_BACKREF_COUNT_LSB, /* least significant byte of count */
13
+ HSDS_YIELD_BACKREF, /* ready to yield back-reference */
14
+ } HSD_state;
15
+
16
+ #if HEATSHRINK_DEBUGGING_LOGS
17
+ #include <stdio.h>
18
+ #include <ctype.h>
19
+ #include <assert.h>
20
+ #define LOG(...) fprintf(stderr, __VA_ARGS__)
21
+ #define ASSERT(X) assert(X)
22
+ static const char *state_names[] = {
23
+ "tag_bit",
24
+ "yield_literal",
25
+ "backref_index_msb",
26
+ "backref_index_lsb",
27
+ "backref_count_msb",
28
+ "backref_count_lsb",
29
+ "yield_backref",
30
+ };
31
+ #else
32
+ #define LOG(...) /* no-op */
33
+ #define ASSERT(X) /* no-op */
34
+ #endif
35
+
36
+ typedef struct {
37
+ uint8_t *buf; /* output buffer */
38
+ size_t buf_size; /* buffer size */
39
+ size_t *output_size; /* bytes pushed to buffer, so far */
40
+ } output_info;
41
+
42
+ #define NO_BITS ((uint16_t)-1)
43
+
44
+ /* Forward references. */
45
+ static uint16_t get_bits(heatshrink_decoder *hsd, uint8_t count);
46
+ static void push_byte(heatshrink_decoder *hsd, output_info *oi, uint8_t byte);
47
+
48
+ #if HEATSHRINK_DYNAMIC_ALLOC
49
+ heatshrink_decoder *heatshrink_decoder_alloc(uint16_t input_buffer_size,
50
+ uint8_t window_sz2,
51
+ uint8_t lookahead_sz2) {
52
+ if ((window_sz2 < HEATSHRINK_MIN_WINDOW_BITS) ||
53
+ (window_sz2 > HEATSHRINK_MAX_WINDOW_BITS) ||
54
+ (input_buffer_size == 0) ||
55
+ (lookahead_sz2 < HEATSHRINK_MIN_LOOKAHEAD_BITS) ||
56
+ (lookahead_sz2 >= window_sz2)) {
57
+ return NULL;
58
+ }
59
+ size_t buffers_sz = (1 << window_sz2) + input_buffer_size;
60
+ size_t sz = sizeof(heatshrink_decoder) + buffers_sz;
61
+ heatshrink_decoder *hsd = HEATSHRINK_MALLOC(sz);
62
+ if (hsd == NULL) { return NULL; }
63
+ hsd->input_buffer_size = input_buffer_size;
64
+ hsd->window_sz2 = window_sz2;
65
+ hsd->lookahead_sz2 = lookahead_sz2;
66
+ heatshrink_decoder_reset(hsd);
67
+ LOG("-- allocated decoder with buffer size of %zu (%zu + %u + %u)\n",
68
+ sz, sizeof(heatshrink_decoder), (1 << window_sz2), input_buffer_size);
69
+ return hsd;
70
+ }
71
+
72
+ void heatshrink_decoder_free(heatshrink_decoder *hsd) {
73
+ size_t buffers_sz = (1 << hsd->window_sz2) + hsd->input_buffer_size;
74
+ size_t sz = sizeof(heatshrink_decoder) + buffers_sz;
75
+ HEATSHRINK_FREE(hsd, sz);
76
+ (void)sz; /* may not be used by free */
77
+ }
78
+ #endif
79
+
80
+ void heatshrink_decoder_reset(heatshrink_decoder *hsd) {
81
+ size_t buf_sz = 1 << HEATSHRINK_DECODER_WINDOW_BITS(hsd);
82
+ size_t input_sz = HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(hsd);
83
+ memset(hsd->buffers, 0, buf_sz + input_sz);
84
+ hsd->state = HSDS_TAG_BIT;
85
+ hsd->input_size = 0;
86
+ hsd->input_index = 0;
87
+ hsd->bit_index = 0x00;
88
+ hsd->current_byte = 0x00;
89
+ hsd->output_count = 0;
90
+ hsd->output_index = 0;
91
+ hsd->head_index = 0;
92
+ }
93
+
94
+ /* Copy SIZE bytes into the decoder's input buffer, if it will fit. */
95
+ HSD_sink_res heatshrink_decoder_sink(heatshrink_decoder *hsd,
96
+ uint8_t *in_buf, size_t size, size_t *input_size) {
97
+ if ((hsd == NULL) || (in_buf == NULL) || (input_size == NULL)) {
98
+ return HSDR_SINK_ERROR_NULL;
99
+ }
100
+
101
+ size_t rem = HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(hsd) - hsd->input_size;
102
+ if (rem == 0) {
103
+ *input_size = 0;
104
+ return HSDR_SINK_FULL;
105
+ }
106
+
107
+ size = rem < size ? rem : size;
108
+ LOG("-- sinking %zd bytes\n", size);
109
+ /* copy into input buffer (at head of buffers) */
110
+ memcpy(&hsd->buffers[hsd->input_size], in_buf, size);
111
+ hsd->input_size += size;
112
+ *input_size = size;
113
+ return HSDR_SINK_OK;
114
+ }
115
+
116
+
117
+ /*****************
118
+ * Decompression *
119
+ *****************/
120
+
121
+ #define BACKREF_COUNT_BITS(HSD) (HEATSHRINK_DECODER_LOOKAHEAD_BITS(HSD))
122
+ #define BACKREF_INDEX_BITS(HSD) (HEATSHRINK_DECODER_WINDOW_BITS(HSD))
123
+
124
+ // States
125
+ static HSD_state st_tag_bit(heatshrink_decoder *hsd);
126
+ static HSD_state st_yield_literal(heatshrink_decoder *hsd,
127
+ output_info *oi);
128
+ static HSD_state st_backref_index_msb(heatshrink_decoder *hsd);
129
+ static HSD_state st_backref_index_lsb(heatshrink_decoder *hsd);
130
+ static HSD_state st_backref_count_msb(heatshrink_decoder *hsd);
131
+ static HSD_state st_backref_count_lsb(heatshrink_decoder *hsd);
132
+ static HSD_state st_yield_backref(heatshrink_decoder *hsd,
133
+ output_info *oi);
134
+
135
+ HSD_poll_res heatshrink_decoder_poll(heatshrink_decoder *hsd,
136
+ uint8_t *out_buf, size_t out_buf_size, size_t *output_size) {
137
+ if ((hsd == NULL) || (out_buf == NULL) || (output_size == NULL)) {
138
+ return HSDR_POLL_ERROR_NULL;
139
+ }
140
+ *output_size = 0;
141
+
142
+ output_info oi;
143
+ oi.buf = out_buf;
144
+ oi.buf_size = out_buf_size;
145
+ oi.output_size = output_size;
146
+
147
+ while (1) {
148
+ LOG("-- poll, state is %d (%s), input_size %d\n",
149
+ hsd->state, state_names[hsd->state], hsd->input_size);
150
+ uint8_t in_state = hsd->state;
151
+ switch (in_state) {
152
+ case HSDS_TAG_BIT:
153
+ hsd->state = st_tag_bit(hsd);
154
+ break;
155
+ case HSDS_YIELD_LITERAL:
156
+ hsd->state = st_yield_literal(hsd, &oi);
157
+ break;
158
+ case HSDS_BACKREF_INDEX_MSB:
159
+ hsd->state = st_backref_index_msb(hsd);
160
+ break;
161
+ case HSDS_BACKREF_INDEX_LSB:
162
+ hsd->state = st_backref_index_lsb(hsd);
163
+ break;
164
+ case HSDS_BACKREF_COUNT_MSB:
165
+ hsd->state = st_backref_count_msb(hsd);
166
+ break;
167
+ case HSDS_BACKREF_COUNT_LSB:
168
+ hsd->state = st_backref_count_lsb(hsd);
169
+ break;
170
+ case HSDS_YIELD_BACKREF:
171
+ hsd->state = st_yield_backref(hsd, &oi);
172
+ break;
173
+ default:
174
+ return HSDR_POLL_ERROR_UNKNOWN;
175
+ }
176
+
177
+ /* If the current state cannot advance, check if input or output
178
+ * buffer are exhausted. */
179
+ if (hsd->state == in_state) {
180
+ if (*output_size == out_buf_size) { return HSDR_POLL_MORE; }
181
+ return HSDR_POLL_EMPTY;
182
+ }
183
+ }
184
+ }
185
+
186
+ static HSD_state st_tag_bit(heatshrink_decoder *hsd) {
187
+ uint32_t bits = get_bits(hsd, 1); // get tag bit
188
+ if (bits == NO_BITS) {
189
+ return HSDS_TAG_BIT;
190
+ } else if (bits) {
191
+ return HSDS_YIELD_LITERAL;
192
+ } else if (HEATSHRINK_DECODER_WINDOW_BITS(hsd) > 8) {
193
+ return HSDS_BACKREF_INDEX_MSB;
194
+ } else {
195
+ hsd->output_index = 0;
196
+ return HSDS_BACKREF_INDEX_LSB;
197
+ }
198
+ }
199
+
200
+ static HSD_state st_yield_literal(heatshrink_decoder *hsd,
201
+ output_info *oi) {
202
+ /* Emit a repeated section from the window buffer, and add it (again)
203
+ * to the window buffer. (Note that the repetition can include
204
+ * itself.)*/
205
+ if (*oi->output_size < oi->buf_size) {
206
+ uint16_t byte = get_bits(hsd, 8);
207
+ if (byte == NO_BITS) { return HSDS_YIELD_LITERAL; } /* out of input */
208
+ uint8_t *buf = &hsd->buffers[HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(hsd)];
209
+ uint16_t mask = (1 << HEATSHRINK_DECODER_WINDOW_BITS(hsd)) - 1;
210
+ uint8_t c = byte & 0xFF;
211
+ LOG("-- emitting literal byte 0x%02x ('%c')\n", c, isprint(c) ? c : '.');
212
+ buf[hsd->head_index++ & mask] = c;
213
+ push_byte(hsd, oi, c);
214
+ return HSDS_TAG_BIT;
215
+ } else {
216
+ return HSDS_YIELD_LITERAL;
217
+ }
218
+ }
219
+
220
+ static HSD_state st_backref_index_msb(heatshrink_decoder *hsd) {
221
+ uint8_t bit_ct = BACKREF_INDEX_BITS(hsd);
222
+ ASSERT(bit_ct > 8);
223
+ uint16_t bits = get_bits(hsd, bit_ct - 8);
224
+ LOG("-- backref index (msb), got 0x%04x (+1)\n", bits);
225
+ if (bits == NO_BITS) { return HSDS_BACKREF_INDEX_MSB; }
226
+ hsd->output_index = bits << 8;
227
+ return HSDS_BACKREF_INDEX_LSB;
228
+ }
229
+
230
+ static HSD_state st_backref_index_lsb(heatshrink_decoder *hsd) {
231
+ uint8_t bit_ct = BACKREF_INDEX_BITS(hsd);
232
+ uint16_t bits = get_bits(hsd, bit_ct < 8 ? bit_ct : 8);
233
+ LOG("-- backref index (lsb), got 0x%04x (+1)\n", bits);
234
+ if (bits == NO_BITS) { return HSDS_BACKREF_INDEX_LSB; }
235
+ hsd->output_index |= bits;
236
+ hsd->output_index++;
237
+ uint8_t br_bit_ct = BACKREF_COUNT_BITS(hsd);
238
+ hsd->output_count = 0;
239
+ return (br_bit_ct > 8) ? HSDS_BACKREF_COUNT_MSB : HSDS_BACKREF_COUNT_LSB;
240
+ }
241
+
242
+ static HSD_state st_backref_count_msb(heatshrink_decoder *hsd) {
243
+ uint8_t br_bit_ct = BACKREF_COUNT_BITS(hsd);
244
+ ASSERT(br_bit_ct > 8);
245
+ uint16_t bits = get_bits(hsd, br_bit_ct - 8);
246
+ LOG("-- backref count (msb), got 0x%04x (+1)\n", bits);
247
+ if (bits == NO_BITS) { return HSDS_BACKREF_COUNT_MSB; }
248
+ hsd->output_count = bits << 8;
249
+ return HSDS_BACKREF_COUNT_LSB;
250
+ }
251
+
252
+ static HSD_state st_backref_count_lsb(heatshrink_decoder *hsd) {
253
+ uint8_t br_bit_ct = BACKREF_COUNT_BITS(hsd);
254
+ uint16_t bits = get_bits(hsd, br_bit_ct < 8 ? br_bit_ct : 8);
255
+ LOG("-- backref count (lsb), got 0x%04x (+1)\n", bits);
256
+ if (bits == NO_BITS) { return HSDS_BACKREF_COUNT_LSB; }
257
+ hsd->output_count |= bits;
258
+ hsd->output_count++;
259
+ return HSDS_YIELD_BACKREF;
260
+ }
261
+
262
+ static HSD_state st_yield_backref(heatshrink_decoder *hsd,
263
+ output_info *oi) {
264
+ size_t count = oi->buf_size - *oi->output_size;
265
+ if (count > 0) {
266
+ size_t i = 0;
267
+ if (hsd->output_count < count) count = hsd->output_count;
268
+ uint8_t *buf = &hsd->buffers[HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(hsd)];
269
+ uint16_t mask = (1 << HEATSHRINK_DECODER_WINDOW_BITS(hsd)) - 1;
270
+ uint16_t neg_offset = hsd->output_index;
271
+ LOG("-- emitting %zu bytes from -%u bytes back\n", count, neg_offset);
272
+ ASSERT(neg_offset < mask + 1);
273
+ ASSERT(count <= (size_t)(1 << BACKREF_COUNT_BITS(hsd)));
274
+
275
+ for (i=0; i<count; i++) {
276
+ uint8_t c = buf[(hsd->head_index - neg_offset) & mask];
277
+ push_byte(hsd, oi, c);
278
+ buf[hsd->head_index & mask] = c;
279
+ hsd->head_index++;
280
+ LOG(" -- ++ 0x%02x\n", c);
281
+ }
282
+ hsd->output_count -= count;
283
+ if (hsd->output_count == 0) { return HSDS_TAG_BIT; }
284
+ }
285
+ return HSDS_YIELD_BACKREF;
286
+ }
287
+
288
+ /* Get the next COUNT bits from the input buffer, saving incremental progress.
289
+ * Returns NO_BITS on end of input, or if more than 15 bits are requested. */
290
+ static uint16_t get_bits(heatshrink_decoder *hsd, uint8_t count) {
291
+ uint16_t accumulator = 0;
292
+ int i = 0;
293
+ if (count > 15) { return NO_BITS; }
294
+ LOG("-- popping %u bit(s)\n", count);
295
+
296
+ /* If we aren't able to get COUNT bits, suspend immediately, because we
297
+ * don't track how many bits of COUNT we've accumulated before suspend. */
298
+ if (hsd->input_size == 0) {
299
+ if (hsd->bit_index < (1 << (count - 1))) { return NO_BITS; }
300
+ }
301
+
302
+ for (i = 0; i < count; i++) {
303
+ if (hsd->bit_index == 0x00) {
304
+ if (hsd->input_size == 0) {
305
+ LOG(" -- out of bits, suspending w/ accumulator of %u (0x%02x)\n",
306
+ accumulator, accumulator);
307
+ return NO_BITS;
308
+ }
309
+ hsd->current_byte = hsd->buffers[hsd->input_index++];
310
+ LOG(" -- pulled byte 0x%02x\n", hsd->current_byte);
311
+ if (hsd->input_index == hsd->input_size) {
312
+ hsd->input_index = 0; /* input is exhausted */
313
+ hsd->input_size = 0;
314
+ }
315
+ hsd->bit_index = 0x80;
316
+ }
317
+ accumulator <<= 1;
318
+ if (hsd->current_byte & hsd->bit_index) {
319
+ accumulator |= 0x01;
320
+ if (0) {
321
+ LOG(" -- got 1, accumulator 0x%04x, bit_index 0x%02x\n",
322
+ accumulator, hsd->bit_index);
323
+ }
324
+ } else {
325
+ if (0) {
326
+ LOG(" -- got 0, accumulator 0x%04x, bit_index 0x%02x\n",
327
+ accumulator, hsd->bit_index);
328
+ }
329
+ }
330
+ hsd->bit_index >>= 1;
331
+ }
332
+
333
+ if (count > 1) { LOG(" -- accumulated %08x\n", accumulator); }
334
+ return accumulator;
335
+ }
336
+
337
+ HSD_finish_res heatshrink_decoder_finish(heatshrink_decoder *hsd) {
338
+ if (hsd == NULL) { return HSDR_FINISH_ERROR_NULL; }
339
+ switch (hsd->state) {
340
+ case HSDS_TAG_BIT:
341
+ return hsd->input_size == 0 ? HSDR_FINISH_DONE : HSDR_FINISH_MORE;
342
+
343
+ /* If we want to finish with no input, but are in these states, it's
344
+ * because the 0-bit padding to the last byte looks like a backref
345
+ * marker bit followed by all 0s for index and count bits. */
346
+ case HSDS_BACKREF_INDEX_LSB:
347
+ case HSDS_BACKREF_INDEX_MSB:
348
+ case HSDS_BACKREF_COUNT_LSB:
349
+ case HSDS_BACKREF_COUNT_MSB:
350
+ return hsd->input_size == 0 ? HSDR_FINISH_DONE : HSDR_FINISH_MORE;
351
+
352
+ /* If the output stream is padded with 0xFFs (possibly due to being in
353
+ * flash memory), also explicitly check the input size rather than
354
+ * uselessly returning MORE but yielding 0 bytes when polling. */
355
+ case HSDS_YIELD_LITERAL:
356
+ return hsd->input_size == 0 ? HSDR_FINISH_DONE : HSDR_FINISH_MORE;
357
+
358
+ default:
359
+ return HSDR_FINISH_MORE;
360
+ }
361
+ }
362
+
363
+ static void push_byte(heatshrink_decoder *hsd, output_info *oi, uint8_t byte) {
364
+ LOG(" -- pushing byte: 0x%02x ('%c')\n", byte, isprint(byte) ? byte : '.');
365
+ oi->buf[(*oi->output_size)++] = byte;
366
+ (void)hsd;
367
+ }
@@ -0,0 +1,100 @@
1
+ #ifndef HEATSHRINK_DECODER_H
2
+ #define HEATSHRINK_DECODER_H
3
+
4
+ #include <stdint.h>
5
+ #include <stddef.h>
6
+ #include "heatshrink_common.h"
7
+ #include "heatshrink_config.h"
8
+
9
+ typedef enum {
10
+ HSDR_SINK_OK, /* data sunk, ready to poll */
11
+ HSDR_SINK_FULL, /* out of space in internal buffer */
12
+ HSDR_SINK_ERROR_NULL=-1, /* NULL argument */
13
+ } HSD_sink_res;
14
+
15
+ typedef enum {
16
+ HSDR_POLL_EMPTY, /* input exhausted */
17
+ HSDR_POLL_MORE, /* more data remaining, call again w/ fresh output buffer */
18
+ HSDR_POLL_ERROR_NULL=-1, /* NULL arguments */
19
+ HSDR_POLL_ERROR_UNKNOWN=-2,
20
+ } HSD_poll_res;
21
+
22
+ typedef enum {
23
+ HSDR_FINISH_DONE, /* output is done */
24
+ HSDR_FINISH_MORE, /* more output remains */
25
+ HSDR_FINISH_ERROR_NULL=-1, /* NULL arguments */
26
+ } HSD_finish_res;
27
+
28
+ #if HEATSHRINK_DYNAMIC_ALLOC
29
+ #define HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(BUF) \
30
+ ((BUF)->input_buffer_size)
31
+ #define HEATSHRINK_DECODER_WINDOW_BITS(BUF) \
32
+ ((BUF)->window_sz2)
33
+ #define HEATSHRINK_DECODER_LOOKAHEAD_BITS(BUF) \
34
+ ((BUF)->lookahead_sz2)
35
+ #else
36
+ #define HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(_) \
37
+ HEATSHRINK_STATIC_INPUT_BUFFER_SIZE
38
+ #define HEATSHRINK_DECODER_WINDOW_BITS(_) \
39
+ (HEATSHRINK_STATIC_WINDOW_BITS)
40
+ #define HEATSHRINK_DECODER_LOOKAHEAD_BITS(BUF) \
41
+ (HEATSHRINK_STATIC_LOOKAHEAD_BITS)
42
+ #endif
43
+
44
+ typedef struct {
45
+ uint16_t input_size; /* bytes in input buffer */
46
+ uint16_t input_index; /* offset to next unprocessed input byte */
47
+ uint16_t output_count; /* how many bytes to output */
48
+ uint16_t output_index; /* index for bytes to output */
49
+ uint16_t head_index; /* head of window buffer */
50
+ uint8_t state; /* current state machine node */
51
+ uint8_t current_byte; /* current byte of input */
52
+ uint8_t bit_index; /* current bit index */
53
+
54
+ #if HEATSHRINK_DYNAMIC_ALLOC
55
+ /* Fields that are only used if dynamically allocated. */
56
+ uint8_t window_sz2; /* window buffer bits */
57
+ uint8_t lookahead_sz2; /* lookahead bits */
58
+ uint16_t input_buffer_size; /* input buffer size */
59
+
60
+ /* Input buffer, then expansion window buffer */
61
+ uint8_t buffers[];
62
+ #else
63
+ /* Input buffer, then expansion window buffer */
64
+ uint8_t buffers[(1 << HEATSHRINK_DECODER_WINDOW_BITS(_))
65
+ + HEATSHRINK_DECODER_INPUT_BUFFER_SIZE(_)];
66
+ #endif
67
+ } heatshrink_decoder;
68
+
69
+ #if HEATSHRINK_DYNAMIC_ALLOC
70
+ /* Allocate a decoder with an input buffer of INPUT_BUFFER_SIZE bytes,
71
+ * an expansion buffer size of 2^WINDOW_SZ2, and a lookahead
72
+ * size of 2^lookahead_sz2. (The window buffer and lookahead sizes
73
+ * must match the settings used when the data was compressed.)
74
+ * Returns NULL on error. */
75
+ heatshrink_decoder *heatshrink_decoder_alloc(uint16_t input_buffer_size,
76
+ uint8_t expansion_buffer_sz2, uint8_t lookahead_sz2);
77
+
78
+ /* Free a decoder. */
79
+ void heatshrink_decoder_free(heatshrink_decoder *hsd);
80
+ #endif
81
+
82
+ /* Reset a decoder. */
83
+ void heatshrink_decoder_reset(heatshrink_decoder *hsd);
84
+
85
+ /* Sink at most SIZE bytes from IN_BUF into the decoder. *INPUT_SIZE is set to
86
+ * indicate how many bytes were actually sunk (in case a buffer was filled). */
87
+ HSD_sink_res heatshrink_decoder_sink(heatshrink_decoder *hsd,
88
+ uint8_t *in_buf, size_t size, size_t *input_size);
89
+
90
+ /* Poll for output from the decoder, copying at most OUT_BUF_SIZE bytes into
91
+ * OUT_BUF (setting *OUTPUT_SIZE to the actual amount copied). */
92
+ HSD_poll_res heatshrink_decoder_poll(heatshrink_decoder *hsd,
93
+ uint8_t *out_buf, size_t out_buf_size, size_t *output_size);
94
+
95
+ /* Notify the dencoder that the input stream is finished.
96
+ * If the return value is HSDR_FINISH_MORE, there is still more output, so
97
+ * call heatshrink_decoder_poll and repeat. */
98
+ HSD_finish_res heatshrink_decoder_finish(heatshrink_decoder *hsd);
99
+
100
+ #endif