Skip to content

Commit 102c6c9

Browse files
committed
gzip: add clean-room RFC 1951/1952 inflater + libcheck tests
New src/gzip.c implements DEFLATE (RFC 1951) plus the gzip wrapper (RFC 1952) from the RFC text only. Single-pass inflate, no allocations: the output buffer doubles as the LZ77 sliding window, so back-references read from out[out_pos - distance]. Canonical Huffman decode using counts[] / symbols[] tables, ~10x smaller code than fast lookup tables which matters in the bootloader. CRC32 + ISIZE verified against the gzip trailer. Gated by WOLFBOOT_GZIP. include/gzip.h carries the public entry point plus the RFC-canonical constants (magic bytes, CM=DEFLATE, fixed Huffman boundaries, EOB symbol, dynamic block field widths, run-length repeat metadata, CRC32 init/final-XOR, header/trailer sizes, alphabet sizes) so future maintainers can cross-reference the RFC sections by name instead of chasing literal numbers. Tests in tools/unit-tests/unit-gzip.c round-trip 6 corpora through host gzip(1) and back through wolfBoot_gunzip (empty, short text, all-zeros, structured text, pseudo-random, ~2 MB kernel-sized). 9 negative cases cover bad magic, bad CM, reserved FLG bits, truncated header, truncated DEFLATE body, CRC32 mismatch, ISIZE mismatch, output overflow, and NULL parameters. All 15 pass under libcheck.
1 parent 8c7b864 commit 102c6c9

4 files changed

Lines changed: 1230 additions & 1 deletion

File tree

include/gzip.h

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/* gzip.h
2+
*
3+
* Native gzip decompression for wolfBoot FIT subimages.
4+
*
5+
* Clean-room implementation of RFC 1951 (DEFLATE) and RFC 1952 (gzip).
6+
*
7+
* Compile with GZIP=1.
8+
*
9+
*
10+
* Copyright (C) 2026 wolfSSL Inc.
11+
*
12+
* This file is part of wolfBoot.
13+
*
14+
* wolfBoot is free software; you can redistribute it and/or modify
15+
* it under the terms of the GNU General Public License as published by
16+
* the Free Software Foundation; either version 3 of the License, or
17+
* (at your option) any later version.
18+
*
19+
* wolfBoot is distributed in the hope that it will be useful,
20+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
* GNU General Public License for more details.
23+
*
24+
* You should have received a copy of the GNU General Public License
25+
* along with this program; if not, write to the Free Software
26+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
27+
*/
28+
#ifndef WOLFBOOT_GZIP_H
29+
#define WOLFBOOT_GZIP_H
30+
31+
#include <stdint.h>
32+
33+
/* error codes */
34+
#define WOLFBOOT_GZIP_E_FORMAT -1 /* bad magic / method / reserved bits */
35+
#define WOLFBOOT_GZIP_E_TRUNCATED -2 /* input ended mid-stream */
36+
#define WOLFBOOT_GZIP_E_OUTPUT -3 /* output would exceed out_max */
37+
#define WOLFBOOT_GZIP_E_HUFFMAN -4 /* invalid Huffman tree / code */
38+
#define WOLFBOOT_GZIP_E_DISTANCE -5 /* back-ref distance > bytes written */
39+
#define WOLFBOOT_GZIP_E_CRC32 -6 /* trailer CRC32 mismatch */
40+
#define WOLFBOOT_GZIP_E_ISIZE -7 /* trailer ISIZE mismatch */
41+
#define WOLFBOOT_GZIP_E_PARAM -8 /* invalid parameter */
42+
43+
/* RFC 1952 gzip wrapper constants */
44+
#define GZIP_MAGIC_ID1 0x1FU /* first magic byte */
45+
#define GZIP_MAGIC_ID2 0x8BU /* second magic byte */
46+
#define GZIP_CM_DEFLATE 8 /* CM = DEFLATE */
47+
#define GZIP_HEADER_MIN_SIZE 10 /* magic+CM+FLG+MTIME+XFL+OS */
48+
#define GZIP_TRAILER_SIZE 8 /* CRC32 + ISIZE */
49+
#define GZIP_CRC32_INIT 0xFFFFFFFFU
50+
#define GZIP_CRC32_FINAL_XOR 0xFFFFFFFFU
51+
#define GZIP_CRC32_POLY 0xEDB88320U /* IEEE 802.3 reflected */
52+
53+
/* RFC 1952 Sec. 2.3.1 header flag bits (FLG byte) */
54+
#define GZIP_FLG_FTEXT 0x01
55+
#define GZIP_FLG_FHCRC 0x02
56+
#define GZIP_FLG_FEXTRA 0x04
57+
#define GZIP_FLG_FNAME 0x08
58+
#define GZIP_FLG_FCOMMENT 0x10
59+
#define GZIP_FLG_RESERVED 0xE0
60+
61+
/* RFC 1951 DEFLATE - alphabet sizes */
62+
#define GZIP_MAX_HUFF_BITS 15 /* max Huffman code length */
63+
#define GZIP_CL_CODES 19 /* code-length alphabet */
64+
#define GZIP_LITLEN_CODES 288 /* literal/length alphabet */
65+
#define GZIP_DIST_CODES 32 /* distance alphabet */
66+
67+
/* RFC 1951 DEFLATE - fixed Huffman boundaries (Sec. 3.2.6) */
68+
#define GZIP_FIXED_LIT_END_8BIT 144 /* 0..143 -> 8 bits */
69+
#define GZIP_FIXED_LIT_END_9BIT 256 /* 144..255 -> 9 bits */
70+
#define GZIP_FIXED_LIT_END_7BIT 280 /* 256..279 -> 7 bits */
71+
#define GZIP_FIXED_LIT_END 288 /* 280..287 -> 8 bits */
72+
#define GZIP_FIXED_DIST_COUNT 30 /* 0..29 -> 5 bits */
73+
74+
/* RFC 1951 DEFLATE - alphabet bounds (Sec. 3.2.4 / 3.2.5) */
75+
#define GZIP_EOB_SYMBOL 256 /* end-of-block marker */
76+
#define GZIP_LENGTH_CODE_BASE 257 /* first length code */
77+
#define GZIP_LENGTH_CODE_COUNT 29 /* 257..285 */
78+
#define GZIP_DIST_CODE_COUNT 30 /* 0..29 */
79+
80+
/* RFC 1951 DEFLATE - dynamic block header (Sec. 3.2.7) */
81+
#define GZIP_HLIT_BITS 5 /* HLIT field width */
82+
#define GZIP_HDIST_BITS 5 /* HDIST field width */
83+
#define GZIP_HCLEN_BITS 4 /* HCLEN field width */
84+
#define GZIP_HLIT_BASE 257 /* HLIT + 257 */
85+
#define GZIP_HDIST_BASE 1 /* HDIST + 1 */
86+
#define GZIP_HCLEN_BASE 4 /* HCLEN + 4 */
87+
#define GZIP_CL_LEN_BITS 3 /* code-length code is 3 bits */
88+
89+
/* RFC 1951 DEFLATE - run-length repeat symbols (Sec. 3.2.7).
90+
* sym 16: 2 extra bits, repeat previous length 3..6 times
91+
* sym 17: 3 extra bits, repeat zero 3..10 times
92+
* sym 18: 7 extra bits, repeat zero 11..138 times
93+
*/
94+
#define GZIP_REPEAT_PREV_EXTRA 2
95+
#define GZIP_REPEAT_PREV_BASE 3
96+
#define GZIP_REPEAT_Z3_EXTRA 3
97+
#define GZIP_REPEAT_Z3_BASE 3
98+
#define GZIP_REPEAT_Z7_EXTRA 7
99+
#define GZIP_REPEAT_Z7_BASE 11
100+
101+
/* Decompress a gzip stream.
102+
*
103+
* in - pointer to gzip stream (RFC 1952 wrapper around RFC 1951 DEFLATE)
104+
* in_len - length of gzip stream in bytes
105+
* out - destination buffer; also used as the DEFLATE sliding window,
106+
* so the output region must be readable as well as writable.
107+
* out_max - maximum bytes that may be written to out
108+
* out_len - on success, set to the number of bytes written
109+
*
110+
* Returns 0 on success, negative WOLFBOOT_GZIP_E_* on error.
111+
*/
112+
int wolfBoot_gunzip(const uint8_t *in, uint32_t in_len,
113+
uint8_t *out, uint32_t out_max,
114+
uint32_t *out_len);
115+
116+
#endif /* WOLFBOOT_GZIP_H */

0 commit comments

Comments
 (0)