HelenOS sources
This source file includes following definitions.
- get_bits
- inflate_stored
- huffman_decode
- huffman_construct
- inflate_codes
- inflate_fixed
- inflate_dynamic
- inflate
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <mem.h>
#include "inflate.h"
#define MAX_HUFFMAN_BIT 15
#define MAX_LEN 29
#define MAX_DIST 30
#define MAX_ORDER 19
#define MAX_LITLEN 286
#define MAX_FIXED_LITLEN 288
#define MAX_CODE (MAX_LITLEN + MAX_DIST)
#define CHECK_OVERRUN(state) \
do { \
if ((state).overrun) \
return ELIMIT; \
} while (false)
typedef struct {
uint8_t *dest;
size_t destlen;
size_t destcnt;
uint8_t *src;
size_t srclen;
size_t srccnt;
uint16_t bitbuf;
size_t bitlen;
bool overrun;
} inflate_state_t;
typedef struct {
uint16_t *count;
uint16_t *symbol;
} huffman_t;
static const uint16_t lens[MAX_LEN] = {
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
};
static const uint16_t lens_ext[MAX_LEN] = {
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
};
static const uint16_t dists[MAX_DIST] = {
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577
};
static const uint16_t dists_ext[MAX_DIST] = {
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13
};
static const short order[MAX_ORDER] = {
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
};
static uint16_t len_count[MAX_HUFFMAN_BIT + 1] = {
0, 0, 0, 0, 0, 0, 0, 24, 152, 112, 0, 0, 0, 0, 0, 0
};
static uint16_t len_symbol[MAX_FIXED_LITLEN] = {
256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268,
269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
140, 141, 142, 143, 280, 281, 282, 283, 284, 285, 286, 287, 144,
145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157,
158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170,
171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196,
197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222,
223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235,
236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248,
249, 250, 251, 252, 253, 254, 255
};
static uint16_t dist_count[MAX_HUFFMAN_BIT + 1] = {
0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static uint16_t dist_symbol[MAX_DIST] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
};
static huffman_t len_code = {
.count = len_count,
.symbol = len_symbol
};
static huffman_t dist_code = {
.count = dist_count,
.symbol = dist_symbol
};
static inline uint16_t get_bits(inflate_state_t *state, size_t cnt)
{
uint32_t val = state->bitbuf;
while (state->bitlen < cnt) {
if (state->srccnt == state->srclen) {
state->overrun = true;
return 0;
}
val |= ((uint32_t) state->src[state->srccnt]) << state->bitlen;
state->srccnt++;
state->bitlen += 8;
}
state->bitbuf = (uint16_t) (val >> cnt);
state->bitlen -= cnt;
return ((uint16_t) (val & ((1 << cnt) - 1)));
}
static errno_t inflate_stored(inflate_state_t *state)
{
state->bitbuf = 0;
state->bitlen = 0;
if (state->srccnt + 4 > state->srclen)
return ELIMIT;
uint16_t len =
state->src[state->srccnt] | (state->src[state->srccnt + 1] << 8);
uint16_t len_compl =
state->src[state->srccnt + 2] | (state->src[state->srccnt + 3] << 8);
if (((int16_t) len) != ~((int16_t) len_compl))
return EINVAL;
state->srccnt += 4;
if (state->srccnt + len > state->srclen)
return ELIMIT;
if (state->destcnt + len > state->destlen)
return ENOMEM;
memcpy(state->dest + state->destcnt, state->src + state->srccnt, len);
state->srccnt += len;
state->destcnt += len;
return EOK;
}
static errno_t huffman_decode(inflate_state_t *state, huffman_t *huffman,
uint16_t *symbol)
{
uint16_t code = 0;
size_t first = 0;
size_t index = 0;
size_t len;
for (len = 1; len <= MAX_HUFFMAN_BIT; len++) {
code |= get_bits(state, 1);
CHECK_OVERRUN(*state);
uint16_t count = huffman->count[len];
if (code < first + count) {
*symbol = huffman->symbol[index + code - first];
return EOK;
}
index += count;
first += count;
first <<= 1;
code <<= 1;
}
return EINVAL;
}
static int16_t huffman_construct(huffman_t *huffman, uint16_t *length, size_t n)
{
size_t len;
for (len = 0; len <= MAX_HUFFMAN_BIT; len++)
huffman->count[len] = 0;
size_t symbol;
for (symbol = 0; symbol < n; symbol++)
huffman->count[length[symbol]]++;
if (huffman->count[0] == n) {
return 0;
}
int16_t left = 1;
for (len = 1; len <= MAX_HUFFMAN_BIT; len++) {
left <<= 1;
left -= huffman->count[len];
if (left < 0) {
return left;
}
}
uint16_t offs[MAX_HUFFMAN_BIT + 1];
offs[1] = 0;
for (len = 1; len < MAX_HUFFMAN_BIT; len++)
offs[len + 1] = offs[len] + huffman->count[len];
for (symbol = 0; symbol < n; symbol++) {
if (length[symbol] != 0) {
huffman->symbol[offs[length[symbol]]] = symbol;
offs[length[symbol]]++;
}
}
return left;
}
static errno_t inflate_codes(inflate_state_t *state, huffman_t *len_code,
huffman_t *dist_code)
{
uint16_t symbol;
do {
errno_t err = huffman_decode(state, len_code, &symbol);
if (err != EOK) {
return err;
}
if (symbol < 256) {
if (state->destcnt == state->destlen)
return ENOMEM;
state->dest[state->destcnt] = (uint8_t) symbol;
state->destcnt++;
} else if (symbol > 256) {
symbol -= 257;
if (symbol >= 29)
return EINVAL;
size_t len = lens[symbol] + get_bits(state, lens_ext[symbol]);
CHECK_OVERRUN(*state);
err = huffman_decode(state, dist_code, &symbol);
if (err != EOK)
return err;
size_t dist = dists[symbol] + get_bits(state, dists_ext[symbol]);
if (dist > state->destcnt)
return ENOENT;
if (state->destcnt + len > state->destlen)
return ENOMEM;
while (len > 0) {
state->dest[state->destcnt] =
state->dest[state->destcnt - dist];
state->destcnt++;
len--;
}
}
} while (symbol != 256);
return EOK;
}
static errno_t inflate_fixed(inflate_state_t *state, huffman_t *len_code,
huffman_t *dist_code)
{
return inflate_codes(state, len_code, dist_code);
}
static errno_t inflate_dynamic(inflate_state_t *state)
{
uint16_t length[MAX_CODE];
uint16_t dyn_len_count[MAX_HUFFMAN_BIT + 1];
uint16_t dyn_len_symbol[MAX_LITLEN];
uint16_t dyn_dist_count[MAX_HUFFMAN_BIT + 1];
uint16_t dyn_dist_symbol[MAX_DIST];
huffman_t dyn_len_code;
huffman_t dyn_dist_code;
dyn_len_code.count = dyn_len_count;
dyn_len_code.symbol = dyn_len_symbol;
dyn_dist_code.count = dyn_dist_count;
dyn_dist_code.symbol = dyn_dist_symbol;
uint16_t nlen = get_bits(state, 5) + 257;
CHECK_OVERRUN(*state);
uint16_t ndist = get_bits(state, 5) + 1;
CHECK_OVERRUN(*state);
uint16_t ncode = get_bits(state, 4) + 4;
CHECK_OVERRUN(*state);
if ((nlen > MAX_LITLEN) || (ndist > MAX_DIST) ||
(ncode > MAX_ORDER))
return EINVAL;
uint16_t index;
for (index = 0; index < ncode; index++) {
length[order[index]] = get_bits(state, 3);
CHECK_OVERRUN(*state);
}
for (index = ncode; index < MAX_ORDER; index++)
length[order[index]] = 0;
int16_t rc = huffman_construct(&dyn_len_code, length, MAX_ORDER);
if (rc != 0)
return EINVAL;
index = 0;
while (index < nlen + ndist) {
uint16_t symbol;
errno_t err = huffman_decode(state, &dyn_len_code, &symbol);
if (err != EOK)
return EOK;
if (symbol < 16) {
length[index] = symbol;
index++;
} else {
uint16_t len = 0;
if (symbol == 16) {
if (index == 0)
return EINVAL;
len = length[index - 1];
symbol = get_bits(state, 2) + 3;
CHECK_OVERRUN(*state);
} else if (symbol == 17) {
symbol = get_bits(state, 3) + 3;
CHECK_OVERRUN(*state);
} else {
symbol = get_bits(state, 7) + 11;
CHECK_OVERRUN(*state);
}
if (index + symbol > nlen + ndist)
return EINVAL;
while (symbol > 0) {
length[index] = len;
index++;
symbol--;
}
}
}
if (length[256] == 0)
return EINVAL;
rc = huffman_construct(&dyn_len_code, length, nlen);
if ((rc < 0) || ((rc > 0) && (dyn_len_code.count[0] + 1 != nlen)))
return EINVAL;
rc = huffman_construct(&dyn_dist_code, length + nlen, ndist);
if ((rc < 0) || ((rc > 0) && (dyn_dist_code.count[0] + 1 != ndist)))
return EINVAL;
return inflate_codes(state, &dyn_len_code, &dyn_dist_code);
}
errno_t inflate(void *src, size_t srclen, void *dest, size_t destlen)
{
inflate_state_t state;
state.dest = (uint8_t *) dest;
state.destlen = destlen;
state.destcnt = 0;
state.src = (uint8_t *) src;
state.srclen = srclen;
state.srccnt = 0;
state.bitbuf = 0;
state.bitlen = 0;
state.overrun = false;
uint16_t last;
errno_t ret = EOK;
do {
last = get_bits(&state, 1);
CHECK_OVERRUN(state);
uint16_t type = get_bits(&state, 2);
CHECK_OVERRUN(state);
switch (type) {
case 0:
ret = inflate_stored(&state);
break;
case 1:
ret = inflate_fixed(&state, &len_code, &dist_code);
break;
case 2:
ret = inflate_dynamic(&state);
break;
default:
ret = EINVAL;
}
} while ((!last) && (ret == 0));
return ret;
}
HelenOS homepage, sources at GitHub