ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
rfc1951.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file rfc1951.h
6 * @brief The RFC 1951 sec 3.2.5 length and distance tables, and the fixed-Huffman coder over them.
7 *
8 * The four tables are defined once in rfc1951.c and read off this namespace. The DEFLATE encoder and
9 * decoder (codec/deflate, codec/inflate) and the SSH zlib@openssh.com stream codecs
10 * (ssh/transport/ssh_zlib, ssh/transport/ssh_inflate) read them.
11 *
12 * @author Douglas Quigg (dstroy0)
13 * @date 2026
14 */
15
16#ifndef PROTOCORE_RFC1951_H
17#define PROTOCORE_RFC1951_H
18
19#include "protocore_config.h" // the entry point: the enable gate below, and the widths
20
21#if PROTOCORE_ENABLE_DEFLATE_RFC1951
22
23#include "bitorum_introitus_exitus/bitorum_introitus_exitus.h" // mmgr_bitor - what the emitters write through
24
26
27// This module holds nothing between calls, so it carves no borrow and states none. An entry
28// takes one all the same, and never reads it, so every namespace in the tree is invoked the
29// same way.
30
31/** @brief What reverse_bits takes: a code, and how many of its low bits to reverse. */
32typedef struct
33{
34 uint16_t code; ///< the code whose low @c len bits are reversed
35 int len; ///< how many low bits to reverse
36} Rfc1951ReverseBitsArgs;
37
38/** @brief What build_fixed takes: the four tables it fills. */
39typedef struct
40{
41 uint16_t *ll_code; ///< 288 entries: the lit/length code, bit-reversed
42 uint8_t *ll_len; ///< 288 entries: its bit length
43 uint16_t *d_code; ///< 30 entries: the distance code, bit-reversed
44 uint8_t *d_len; ///< 30 entries: its bit length
45} Rfc1951BuildFixedArgs;
46
47/** @brief What emit_literal takes: the writer, the lit/length code tables, and the byte. */
48typedef struct
49{
50 mmgr_bitor *w; ///< the bit writer the code goes out through
51 const uint16_t *ll_code; ///< 288 entries, from build_fixed
52 const uint8_t *ll_len; ///< 288 entries, from build_fixed
53 uint8_t b; ///< the literal byte
54} Rfc1951EmitLiteralArgs;
55
56/** @brief What emit_match takes: the writer, all four code tables, and the back-reference. */
57typedef struct
58{
59 mmgr_bitor *w; ///< the bit writer the codes go out through
60 const uint16_t *ll_code; ///< 288 entries, from build_fixed
61 const uint8_t *ll_len; ///< 288 entries, from build_fixed
62 const uint16_t *d_code; ///< 30 entries, from build_fixed
63 const uint8_t *d_len; ///< 30 entries, from build_fixed
64 int len; ///< match length, 3..258
65 int dist; ///< match distance, 1..32768
66} Rfc1951EmitMatchArgs;
67
68/**
69 * @brief The RFC 1951 sec 3.2.5 tables, and the fixed Huffman coder of sec 3.2.6 over them.
70 *
71 * A caller sets the members a call takes, invokes it through ::Rfc1951 with the bytes it runs out
72 * of, and reads the outcome off the same handle. The four tables are read straight off it.
73 *
74 * Rfc1951.emit_literal_args.w = &w;
75 * Rfc1951.emit_literal_args.ll_code = ll_code;
76 * Rfc1951.emit_literal_args.ll_len = ll_len;
77 * Rfc1951.emit_literal_args.b = src[i];
78 * Rfc1951.emit_literal(work);
79 *
80 * @var Rfc1951Ns::len_base 29 entries: base length for codes 257..285
81 * @var Rfc1951Ns::len_extra 29 entries: extra bits read after each of those codes
82 * @var Rfc1951Ns::dist_base 30 entries: base distance for codes 0..29
83 * @var Rfc1951Ns::dist_extra 30 entries: extra bits read after each of those codes
84 * @var Rfc1951Ns::reverse_bits_args what reverse_bits takes: a code, and how many of its low bits to reverse
85 * @var Rfc1951Ns::build_fixed_args what build_fixed takes: the four tables it fills
86 * @var Rfc1951Ns::emit_literal_args what emit_literal takes: the writer, the lit/length code tables, and the byte
87 * @var Rfc1951Ns::emit_match_args what emit_match takes: the writer, all four code tables, and the back-reference
88 * @var Rfc1951Ns::u16 the reversed code the last reverse_bits produced
89 * @var Rfc1951Ns::reverse_bits reverse the low @c len bits of @c code, MSB-first on the wire
90 * @var Rfc1951Ns::build_fixed fill the fixed Huffman code/length tables (sec 3.2.6), each code bit-reversed
91 * @var Rfc1951Ns::emit_literal emit one literal byte through the fixed lit/length code
92 * @var Rfc1951Ns::emit_match emit a (length, distance) back-reference through the fixed code tables
93 *
94 * @c work is bytes the CALLER holds. This module reads none of them: it carries nothing between
95 * calls, so there is no state to keep and nothing to wipe. The parameter is there so a caller
96 * drives every namespace the same way.
97 */
98typedef struct
99{
100 const short *len_base;
101 const short *len_extra;
102 const short *dist_base;
103 const short *dist_extra;
104 Rfc1951ReverseBitsArgs reverse_bits_args;
105 Rfc1951BuildFixedArgs build_fixed_args;
106 Rfc1951EmitLiteralArgs emit_literal_args;
107 Rfc1951EmitMatchArgs emit_match_args;
108 uint16_t u16;
109} Rfc1951Vars;
110
111/** @brief The operands and the outcome. */
112extern Rfc1951Vars Rfc1951V;
113
114/** @brief The entries. */
115typedef struct
116{
117 void (*const reverse_bits)(uint8_t *work);
118 void (*const build_fixed)(uint8_t *work);
119 void (*const emit_literal)(uint8_t *work);
120 void (*const emit_match)(uint8_t *work);
121} Rfc1951Ns;
122
123// What the table binds, defined once in the .c and taking one parameter each: everything
124// else an entry needs is an operand in Rfc1951V or a region of the borrow at a fixed offset.
125void protocore_rfc1951_reverse_bits(uint8_t *work);
126void protocore_rfc1951_build_fixed(uint8_t *work);
127void protocore_rfc1951_emit_literal(uint8_t *work);
128void protocore_rfc1951_emit_match(uint8_t *work);
129
130// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
131// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
132// `Rfc1951.reverse_bits(work)` resolves to a named function and becomes a DIRECT call. An extern table
133// leaves the call indirect and the symbol live at every level, -O2 -flto included.
134static const Rfc1951Ns Rfc1951 __attribute__((unused)) = {
135 .reverse_bits = protocore_rfc1951_reverse_bits,
136 .build_fixed = protocore_rfc1951_build_fixed,
137 .emit_literal = protocore_rfc1951_emit_literal,
138 .emit_match = protocore_rfc1951_emit_match,
139};
140
142
143#endif // PROTOCORE_ENABLE_DEFLATE_RFC1951
144
145#endif // PROTOCORE_RFC1951_H
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
#define PROTOCORE_END_DECLS
Definition types.h:97