35#define PC_MAX_MATCH 258
36#define PC_HASH_MASK (SSH_ZLIB_HASH_SIZE - 1)
37#define PC_WINDOW PC_SSH_ZLIB_WINDOW
38#define PC_MAX_CHAIN 128
42const short LEN_BASE[29] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27,
43 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
44const short LEN_EXTRA[29] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
47const short DIST_BASE[30] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129,
48 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
49const short DIST_EXTRA[30] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6,
50 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
53uint16_t reverse_bits(uint16_t code,
int len)
56 for (
int k = 0; k < len; k++)
58 r = (uint16_t)((r << 1) | (code & 1));
66void build_fixed(SshDeflate *z)
69 for (; sym < 144; sym++)
73 for (; sym < 256; sym++)
77 for (; sym < 280; sym++)
81 for (; sym < 288; sym++)
85 for (sym = 0; sym < 30; sym++)
90 uint16_t bl_count[16];
91 memset(bl_count, 0,
sizeof(bl_count));
92 for (sym = 0; sym < 288; sym++)
94 bl_count[z->ll_len[sym]]++;
96 uint16_t next_code[16];
99 for (
int b = 1; b <= 15; b++)
101 code = (uint16_t)((code + bl_count[b - 1]) << 1);
104 for (sym = 0; sym < 288; sym++)
106 int len = z->ll_len[sym];
107 z->ll_code[sym] = reverse_bits(next_code[len]++, len);
109 for (sym = 0; sym < 30; sym++)
111 z->d_code[sym] = reverse_bits((uint16_t)sym, 5);
127inline int hash3(
const uint8_t *p)
129 return (
int)(((uint32_t)p[0] << 10 ^ (uint32_t)p[1] << 5 ^ (uint32_t)p[2]) & PC_HASH_MASK);
132void emit_literal(
pc_bit_writer *w,
const SshDeflate *z, uint8_t b)
137void emit_match(
pc_bit_writer *w,
const SshDeflate *z,
int len,
int dist)
140 while (li < 28 && len >= LEN_BASE[li + 1])
148 pc_bitw_put(w, (uint32_t)(len - LEN_BASE[li]), LEN_EXTRA[li]);
152 while (di < 29 && dist >= DIST_BASE[di + 1])
159 pc_bitw_put(w, (uint32_t)(dist - DIST_BASE[di]), DIST_EXTRA[di]);
165void zlib_chain_match(
const SshDeflate *z,
const uint8_t *buf,
size_t i, uint16_t cand,
int chain,
size_t max_len,
166 int *best_len,
int *best_dist)
170 while (cand != PC_NONE && chain > 0)
173 size_t dist = i - cand;
174 if (dist > (
size_t)PC_WINDOW)
179 while (l < max_len && buf[cand + l] == buf[i + l])
183 if ((
int)l > *best_len)
186 *best_dist = (int)dist;
192 cand = z->prev[cand];
197void ssh_deflate_init(SshDeflate *z, uint8_t *work, uint16_t *head, uint16_t *prev, uint16_t *ll_code, uint8_t *ll_len,
198 uint16_t *d_code, uint8_t *d_len)
203 z->ll_code = ll_code;
208 z->header_sent =
false;
212int ssh_deflate_packet(SshDeflate *z,
const uint8_t *src,
size_t src_len, uint8_t *dst,
size_t dst_cap,
size_t *out_len)
220 size_t hist = z->hist;
221 if (hist + src_len > SSH_ZLIB_WORK_SIZE)
225 memcpy(z->work + hist, src, src_len);
226 size_t total = hist + src_len;
227 const uint8_t *buf = z->work;
230 for (
int b = 0; b < SSH_ZLIB_HASH_SIZE; b++)
232 z->head[b] = PC_NONE;
234 for (
size_t p = 0; p + PC_MIN_MATCH <= total && p < hist; p++)
236 int h = hash3(buf + p);
237 z->prev[p] = z->head[h];
238 z->head[h] = (uint16_t)p;
255 z->header_sent =
true;
268 if (i + PC_MIN_MATCH <= total)
270 int h = hash3(buf + i);
271 uint16_t cand = z->head[h];
272 size_t max_len = total - i;
273 if (max_len > (
size_t)PC_MAX_MATCH)
275 max_len = PC_MAX_MATCH;
277 zlib_chain_match(z, buf, i, cand, PC_MAX_CHAIN, max_len, &best_len, &best_dist);
281 if (best_len >= PC_MIN_MATCH)
283 emit_match(&w, z, best_len, best_dist);
284 advance = (size_t)best_len;
288 emit_literal(&w, z, buf[i]);
294 size_t end = i + advance;
297 if (i + PC_MIN_MATCH <= total)
299 int h = hash3(buf + i);
300 z->prev[i] = z->head[h];
301 z->head[h] = (uint16_t)i;
325 if (keep > (
size_t)PC_WINDOW)
331 memmove(z->work, z->work + total - keep, keep);
LSB-first bit writer over a caller-owned byte buffer - one source of truth.
void pc_bitw_align(pc_bit_writer *w)
Flush any partial byte, padding the high bits with zero (byte alignment).
void pc_bitw_put(pc_bit_writer *w, uint32_t bits, int n)
Append the low n bits of bits, LSB-first, spilling any completed bytes to the output.
#define PC_SSH_ZLIB_MAX_IN
Largest uncompressed payload the s2c compressor accepts in one call (bytes). Outbound SSH payloads ar...
SSH server-to-client compression: a context-takeover DEFLATE stream (no heap).
LSB-first bit writer over the caller's output buffer; overflow latches once cap is exceeded.
int nbits
bits currently buffered (< 8 between calls)
size_t cnt
bytes written so far
uint32_t acc
bit accumulator (LSB-first)