698 lines
19 KiB
C
698 lines
19 KiB
C
// Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License.
|
|
// See LICENSE.md for license information.
|
|
// SPDX-License-Identifier: MIT
|
|
//
|
|
// toolZlib.c - DEFLATE for the JoeyLib host tools (toolZlib.h).
|
|
//
|
|
// Inflate decodes canonical Huffman codes a bit at a time (RFC 1951's own
|
|
// construction): small, and plenty fast for asset files. Deflate is one
|
|
// fixed-Huffman block over a greedy LZ77 parse with hash chains.
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "toolZlib.h"
|
|
|
|
#define MAX_BITS 15
|
|
#define MAX_LIT_CODES 288
|
|
#define MAX_DIST_CODES 30
|
|
#define MAX_CODE_LEN_CODES 19
|
|
#define END_OF_BLOCK 256
|
|
#define FIRST_LENGTH_CODE 257
|
|
#define BLOCK_STORED 0
|
|
#define BLOCK_FIXED 1
|
|
#define BLOCK_DYNAMIC 2
|
|
#define OUT_START_BYTES 4096u
|
|
#define ADLER_MOD 65521u
|
|
#define ADLER_NMAX 5552u
|
|
#define CRC_POLY 0xEDB88320u
|
|
#define GZIP_ID1 0x1Fu
|
|
#define GZIP_ID2 0x8Bu
|
|
#define GZIP_CM_DEFLATE 8u
|
|
#define GZIP_HEADER_BYTES 10u
|
|
#define GZIP_TRAILER_BYTES 8u
|
|
#define GZIP_FHCRC 0x02u
|
|
#define GZIP_FEXTRA 0x04u
|
|
#define GZIP_FNAME 0x08u
|
|
#define GZIP_FCOMMENT 0x10u
|
|
#define ZLIB_CM_DEFLATE 8u
|
|
#define ZLIB_FDICT 0x20u
|
|
#define ZLIB_CHECK 31u
|
|
#define ZLIB_HEADER_0 0x78u
|
|
#define ZLIB_HEADER_1 0x01u
|
|
#define WINDOW_BYTES 32768u
|
|
#define HASH_BITS 15u
|
|
#define HASH_SIZE (1u << HASH_BITS)
|
|
#define MIN_MATCH 3u
|
|
#define MAX_MATCH 258u
|
|
#define MAX_CHAIN 128u
|
|
#define NO_POS 0xFFFFFFFFu
|
|
|
|
typedef struct HuffmanT {
|
|
uint16_t counts[MAX_BITS + 1];
|
|
uint16_t symbols[MAX_LIT_CODES];
|
|
} HuffmanT;
|
|
|
|
typedef struct InflateT {
|
|
const uint8_t *in;
|
|
size_t inLen;
|
|
size_t inPos;
|
|
uint32_t bitBuf;
|
|
uint32_t bitCount;
|
|
uint8_t *out;
|
|
size_t outLen;
|
|
size_t outCap;
|
|
bool error;
|
|
} InflateT;
|
|
|
|
typedef struct DeflateT {
|
|
uint8_t *out;
|
|
size_t outLen;
|
|
size_t outCap;
|
|
uint32_t bitBuf;
|
|
uint32_t bitCount;
|
|
bool error;
|
|
} DeflateT;
|
|
|
|
static const uint16_t kLengthBase[29] = { 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 uint8_t kLengthExtra[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 };
|
|
static const uint16_t kDistBase[30] = { 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 uint8_t kDistExtra[30] = { 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 uint8_t kCodeLenOrder[MAX_CODE_LEN_CODES] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
|
|
|
|
static void deflateBits(DeflateT *d, uint32_t value, uint32_t count);
|
|
static void deflateByte(DeflateT *d, uint8_t b);
|
|
static void deflateCode(DeflateT *d, uint32_t code, uint32_t len);
|
|
static void deflateDistance(DeflateT *d, uint32_t dist);
|
|
static void deflateFlush(DeflateT *d);
|
|
static void deflateLength(DeflateT *d, uint32_t len);
|
|
static void deflateLiteral(DeflateT *d, uint32_t sym);
|
|
static uint32_t hashAt(const uint8_t *p);
|
|
static uint32_t inflateBits(InflateT *s, uint32_t count);
|
|
static bool inflateBlockCodes(InflateT *s, const HuffmanT *lit, const HuffmanT *dist);
|
|
static bool inflateBuild(HuffmanT *h, const uint8_t *lengths, uint16_t n);
|
|
static int32_t inflateDecode(InflateT *s, const HuffmanT *h);
|
|
static bool inflateDynamic(InflateT *s);
|
|
static bool inflateFixed(InflateT *s);
|
|
static bool inflateOut(InflateT *s, uint8_t b);
|
|
static bool inflateRaw(InflateT *s);
|
|
static bool inflateStored(InflateT *s);
|
|
static uint32_t readBe32(const uint8_t *p);
|
|
static uint32_t readLe32(const uint8_t *p);
|
|
static uint32_t reverseBits(uint32_t code, uint32_t len);
|
|
|
|
|
|
static void deflateBits(DeflateT *d, uint32_t value, uint32_t count) {
|
|
d->bitBuf |= value << d->bitCount;
|
|
d->bitCount += count;
|
|
while (d->bitCount >= 8u) {
|
|
deflateByte(d, (uint8_t)d->bitBuf);
|
|
d->bitBuf >>= 8;
|
|
d->bitCount -= 8u;
|
|
}
|
|
}
|
|
|
|
|
|
static void deflateByte(DeflateT *d, uint8_t b) {
|
|
uint8_t *grown;
|
|
|
|
if (d->outLen == d->outCap) {
|
|
grown = (uint8_t *)realloc(d->out, d->outCap * 2u);
|
|
if (grown == NULL) {
|
|
d->error = true;
|
|
return;
|
|
}
|
|
d->out = grown;
|
|
d->outCap *= 2u;
|
|
}
|
|
d->out[d->outLen++] = b;
|
|
}
|
|
|
|
|
|
// A Huffman code goes out most significant bit first.
|
|
static void deflateCode(DeflateT *d, uint32_t code, uint32_t len) {
|
|
deflateBits(d, reverseBits(code, len), len);
|
|
}
|
|
|
|
|
|
static void deflateDistance(DeflateT *d, uint32_t dist) {
|
|
uint32_t c;
|
|
|
|
for (c = MAX_DIST_CODES - 1u; kDistBase[c] > dist; c--) {
|
|
}
|
|
deflateCode(d, c, 5u);
|
|
deflateBits(d, dist - kDistBase[c], kDistExtra[c]);
|
|
}
|
|
|
|
|
|
static void deflateFlush(DeflateT *d) {
|
|
if (d->bitCount > 0u) {
|
|
deflateByte(d, (uint8_t)d->bitBuf);
|
|
d->bitBuf = 0u;
|
|
d->bitCount = 0u;
|
|
}
|
|
}
|
|
|
|
|
|
static void deflateLength(DeflateT *d, uint32_t len) {
|
|
uint32_t c;
|
|
|
|
for (c = 28u; kLengthBase[c] > len; c--) {
|
|
}
|
|
deflateLiteral(d, FIRST_LENGTH_CODE + c);
|
|
deflateBits(d, len - kLengthBase[c], kLengthExtra[c]);
|
|
}
|
|
|
|
|
|
// The fixed literal/length code (RFC 1951 3.2.6).
|
|
static void deflateLiteral(DeflateT *d, uint32_t sym) {
|
|
if (sym < 144u) {
|
|
deflateCode(d, 0x30u + sym, 8u);
|
|
} else if (sym < 256u) {
|
|
deflateCode(d, 0x190u + (sym - 144u), 9u);
|
|
} else if (sym < 280u) {
|
|
deflateCode(d, sym - 256u, 7u);
|
|
} else {
|
|
deflateCode(d, 0xC0u + (sym - 280u), 8u);
|
|
}
|
|
}
|
|
|
|
|
|
static uint32_t hashAt(const uint8_t *p) {
|
|
return ((uint32_t)p[0] << 10 ^ (uint32_t)p[1] << 5 ^ (uint32_t)p[2]) & (HASH_SIZE - 1u);
|
|
}
|
|
|
|
|
|
static uint32_t inflateBits(InflateT *s, uint32_t count) {
|
|
uint32_t value;
|
|
|
|
while (s->bitCount < count) {
|
|
if (s->inPos >= s->inLen) {
|
|
s->error = true;
|
|
return 0u;
|
|
}
|
|
s->bitBuf |= (uint32_t)s->in[s->inPos++] << s->bitCount;
|
|
s->bitCount += 8u;
|
|
}
|
|
value = s->bitBuf & ((1u << count) - 1u);
|
|
s->bitBuf >>= count;
|
|
s->bitCount -= count;
|
|
return value;
|
|
}
|
|
|
|
|
|
static bool inflateBlockCodes(InflateT *s, const HuffmanT *lit, const HuffmanT *dist) {
|
|
int32_t sym;
|
|
uint32_t len;
|
|
uint32_t back;
|
|
uint32_t i;
|
|
|
|
for (;;) {
|
|
sym = inflateDecode(s, lit);
|
|
if (sym < 0) {
|
|
return false;
|
|
}
|
|
if (sym < END_OF_BLOCK) {
|
|
if (!inflateOut(s, (uint8_t)sym)) {
|
|
return false;
|
|
}
|
|
continue;
|
|
}
|
|
if (sym == END_OF_BLOCK) {
|
|
return true;
|
|
}
|
|
sym -= FIRST_LENGTH_CODE;
|
|
if (sym >= 29) {
|
|
return false;
|
|
}
|
|
len = kLengthBase[sym] + inflateBits(s, kLengthExtra[sym]);
|
|
sym = inflateDecode(s, dist);
|
|
if (sym < 0 || sym >= MAX_DIST_CODES) {
|
|
return false;
|
|
}
|
|
back = kDistBase[sym] + inflateBits(s, kDistExtra[sym]);
|
|
if (s->error || back > s->outLen) {
|
|
return false;
|
|
}
|
|
for (i = 0; i < len; i++) {
|
|
if (!inflateOut(s, s->out[s->outLen - back])) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Canonical codes from code lengths: counts of each length, symbols in code
|
|
// order. False when the lengths over-subscribe the code space.
|
|
static bool inflateBuild(HuffmanT *h, const uint8_t *lengths, uint16_t n) {
|
|
uint16_t offsets[MAX_BITS + 1];
|
|
int32_t left;
|
|
uint16_t i;
|
|
|
|
memset(h->counts, 0, sizeof(h->counts));
|
|
for (i = 0; i < n; i++) {
|
|
h->counts[lengths[i]]++;
|
|
}
|
|
left = 1;
|
|
for (i = 1; i <= MAX_BITS; i++) {
|
|
left = (left << 1) - h->counts[i];
|
|
if (left < 0) {
|
|
return false;
|
|
}
|
|
}
|
|
offsets[1] = 0;
|
|
for (i = 1; i < MAX_BITS; i++) {
|
|
offsets[i + 1] = (uint16_t)(offsets[i] + h->counts[i]);
|
|
}
|
|
for (i = 0; i < n; i++) {
|
|
if (lengths[i] != 0u) {
|
|
h->symbols[offsets[lengths[i]]++] = i;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
static int32_t inflateDecode(InflateT *s, const HuffmanT *h) {
|
|
int32_t code;
|
|
int32_t first;
|
|
int32_t index;
|
|
int32_t count;
|
|
uint32_t len;
|
|
|
|
code = 0;
|
|
first = 0;
|
|
index = 0;
|
|
for (len = 1; len <= MAX_BITS; len++) {
|
|
code |= (int32_t)inflateBits(s, 1u);
|
|
if (s->error) {
|
|
return -1;
|
|
}
|
|
count = h->counts[len];
|
|
if (code - count < first) {
|
|
return h->symbols[index + (code - first)];
|
|
}
|
|
index += count;
|
|
first += count;
|
|
first <<= 1;
|
|
code <<= 1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
static bool inflateDynamic(InflateT *s) {
|
|
HuffmanT lit;
|
|
HuffmanT dist;
|
|
uint8_t lengths[MAX_LIT_CODES + MAX_DIST_CODES];
|
|
uint32_t nLit;
|
|
uint32_t nDist;
|
|
uint32_t nCode;
|
|
uint32_t i;
|
|
uint32_t repeat;
|
|
int32_t sym;
|
|
uint8_t value;
|
|
|
|
nLit = inflateBits(s, 5u) + 257u;
|
|
nDist = inflateBits(s, 5u) + 1u;
|
|
nCode = inflateBits(s, 4u) + 4u;
|
|
if (s->error || nLit > MAX_LIT_CODES || nDist > MAX_DIST_CODES) {
|
|
return false;
|
|
}
|
|
memset(lengths, 0, sizeof(lengths));
|
|
for (i = 0; i < nCode; i++) {
|
|
lengths[kCodeLenOrder[i]] = (uint8_t)inflateBits(s, 3u);
|
|
}
|
|
if (!inflateBuild(&lit, lengths, MAX_CODE_LEN_CODES)) {
|
|
return false;
|
|
}
|
|
i = 0;
|
|
while (i < nLit + nDist) {
|
|
sym = inflateDecode(s, &lit);
|
|
if (sym < 0) {
|
|
return false;
|
|
}
|
|
if (sym < 16) {
|
|
lengths[i++] = (uint8_t)sym;
|
|
continue;
|
|
}
|
|
value = 0u;
|
|
if (sym == 16) {
|
|
if (i == 0u) {
|
|
return false;
|
|
}
|
|
value = lengths[i - 1u];
|
|
repeat = 3u + inflateBits(s, 2u);
|
|
} else if (sym == 17) {
|
|
repeat = 3u + inflateBits(s, 3u);
|
|
} else {
|
|
repeat = 11u + inflateBits(s, 7u);
|
|
}
|
|
if (s->error || i + repeat > nLit + nDist) {
|
|
return false;
|
|
}
|
|
while (repeat-- > 0u) {
|
|
lengths[i++] = value;
|
|
}
|
|
}
|
|
if (lengths[END_OF_BLOCK] == 0u) {
|
|
return false;
|
|
}
|
|
if (!inflateBuild(&lit, lengths, (uint16_t)nLit) || !inflateBuild(&dist, lengths + nLit, (uint16_t)nDist)) {
|
|
return false;
|
|
}
|
|
return inflateBlockCodes(s, &lit, &dist);
|
|
}
|
|
|
|
|
|
static bool inflateFixed(InflateT *s) {
|
|
HuffmanT lit;
|
|
HuffmanT dist;
|
|
uint8_t lengths[MAX_LIT_CODES];
|
|
uint16_t i;
|
|
|
|
for (i = 0; i < 144u; i++) {
|
|
lengths[i] = 8u;
|
|
}
|
|
for (; i < 256u; i++) {
|
|
lengths[i] = 9u;
|
|
}
|
|
for (; i < 280u; i++) {
|
|
lengths[i] = 7u;
|
|
}
|
|
for (; i < MAX_LIT_CODES; i++) {
|
|
lengths[i] = 8u;
|
|
}
|
|
inflateBuild(&lit, lengths, MAX_LIT_CODES);
|
|
for (i = 0; i < MAX_DIST_CODES; i++) {
|
|
lengths[i] = 5u;
|
|
}
|
|
inflateBuild(&dist, lengths, MAX_DIST_CODES);
|
|
return inflateBlockCodes(s, &lit, &dist);
|
|
}
|
|
|
|
|
|
static bool inflateOut(InflateT *s, uint8_t b) {
|
|
uint8_t *grown;
|
|
|
|
if (s->outLen == s->outCap) {
|
|
grown = (uint8_t *)realloc(s->out, s->outCap * 2u);
|
|
if (grown == NULL) {
|
|
return false;
|
|
}
|
|
s->out = grown;
|
|
s->outCap *= 2u;
|
|
}
|
|
s->out[s->outLen++] = b;
|
|
return true;
|
|
}
|
|
|
|
|
|
static bool inflateRaw(InflateT *s) {
|
|
uint32_t last;
|
|
uint32_t type;
|
|
bool ok;
|
|
|
|
do {
|
|
last = inflateBits(s, 1u);
|
|
type = inflateBits(s, 2u);
|
|
if (s->error) {
|
|
return false;
|
|
}
|
|
if (type == BLOCK_STORED) {
|
|
ok = inflateStored(s);
|
|
} else if (type == BLOCK_FIXED) {
|
|
ok = inflateFixed(s);
|
|
} else if (type == BLOCK_DYNAMIC) {
|
|
ok = inflateDynamic(s);
|
|
} else {
|
|
ok = false;
|
|
}
|
|
if (!ok) {
|
|
return false;
|
|
}
|
|
} while (last == 0u);
|
|
// The wrapper's trailer starts at the next whole byte.
|
|
s->bitBuf = 0u;
|
|
s->bitCount = 0u;
|
|
return true;
|
|
}
|
|
|
|
|
|
static bool inflateStored(InflateT *s) {
|
|
uint32_t len;
|
|
uint32_t nlen;
|
|
|
|
s->bitBuf = 0u;
|
|
s->bitCount = 0u;
|
|
if (s->inPos + 4u > s->inLen) {
|
|
return false;
|
|
}
|
|
len = (uint32_t)s->in[s->inPos] | (uint32_t)s->in[s->inPos + 1u] << 8;
|
|
nlen = (uint32_t)s->in[s->inPos + 2u] | (uint32_t)s->in[s->inPos + 3u] << 8;
|
|
s->inPos += 4u;
|
|
if ((len ^ 0xFFFFu) != nlen || s->inPos + len > s->inLen) {
|
|
return false;
|
|
}
|
|
while (len-- > 0u) {
|
|
if (!inflateOut(s, s->in[s->inPos++])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
static uint32_t readBe32(const uint8_t *p) {
|
|
return (uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | (uint32_t)p[2] << 8 | (uint32_t)p[3];
|
|
}
|
|
|
|
|
|
static uint32_t readLe32(const uint8_t *p) {
|
|
return (uint32_t)p[0] | (uint32_t)p[1] << 8 | (uint32_t)p[2] << 16 | (uint32_t)p[3] << 24;
|
|
}
|
|
|
|
|
|
static uint32_t reverseBits(uint32_t code, uint32_t len) {
|
|
uint32_t out;
|
|
uint32_t i;
|
|
|
|
out = 0u;
|
|
for (i = 0; i < len; i++) {
|
|
out = (out << 1) | (code & 1u);
|
|
code >>= 1;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
uint32_t toolAdler32(uint32_t seed, const uint8_t *data, size_t len) {
|
|
uint32_t a;
|
|
uint32_t b;
|
|
size_t chunk;
|
|
|
|
a = seed & 0xFFFFu;
|
|
b = seed >> 16;
|
|
while (len > 0u) {
|
|
chunk = len < ADLER_NMAX ? len : ADLER_NMAX;
|
|
len -= chunk;
|
|
while (chunk-- > 0u) {
|
|
a += *data++;
|
|
b += a;
|
|
}
|
|
a %= ADLER_MOD;
|
|
b %= ADLER_MOD;
|
|
}
|
|
return b << 16 | a;
|
|
}
|
|
|
|
|
|
uint32_t toolCrc32(uint32_t seed, const uint8_t *data, size_t len) {
|
|
static uint32_t table[256];
|
|
static bool built = false;
|
|
uint32_t c;
|
|
uint32_t n;
|
|
uint32_t k;
|
|
|
|
if (!built) {
|
|
for (n = 0; n < 256u; n++) {
|
|
c = n;
|
|
for (k = 0; k < 8u; k++) {
|
|
c = (c & 1u) != 0u ? CRC_POLY ^ (c >> 1) : c >> 1;
|
|
}
|
|
table[n] = c;
|
|
}
|
|
built = true;
|
|
}
|
|
c = seed ^ 0xFFFFFFFFu;
|
|
while (len-- > 0u) {
|
|
c = table[(c ^ *data++) & 0xFFu] ^ (c >> 8);
|
|
}
|
|
return c ^ 0xFFFFFFFFu;
|
|
}
|
|
|
|
|
|
bool toolDeflateZlib(const uint8_t *in, size_t inLen, uint8_t **out, size_t *outLen) {
|
|
DeflateT d;
|
|
uint32_t *head;
|
|
uint32_t *prev;
|
|
uint32_t adler;
|
|
uint32_t h;
|
|
uint32_t cand;
|
|
uint32_t chain;
|
|
uint32_t bestLen;
|
|
uint32_t bestDist;
|
|
uint32_t len;
|
|
uint32_t limit;
|
|
size_t pos;
|
|
size_t k;
|
|
|
|
memset(&d, 0, sizeof(d));
|
|
d.outCap = OUT_START_BYTES;
|
|
d.out = (uint8_t *)malloc(d.outCap);
|
|
head = (uint32_t *)malloc(HASH_SIZE * sizeof(uint32_t));
|
|
prev = (uint32_t *)malloc(WINDOW_BYTES * sizeof(uint32_t));
|
|
if (d.out == NULL || head == NULL || prev == NULL) {
|
|
free(d.out);
|
|
free(head);
|
|
free(prev);
|
|
return false;
|
|
}
|
|
for (k = 0; k < HASH_SIZE; k++) {
|
|
head[k] = NO_POS;
|
|
}
|
|
deflateByte(&d, ZLIB_HEADER_0);
|
|
deflateByte(&d, ZLIB_HEADER_1);
|
|
deflateBits(&d, 1u, 1u);
|
|
deflateBits(&d, BLOCK_FIXED, 2u);
|
|
pos = 0;
|
|
while (pos < inLen) {
|
|
bestLen = 0u;
|
|
bestDist = 0u;
|
|
if (pos + MIN_MATCH <= inLen) {
|
|
h = hashAt(in + pos);
|
|
cand = head[h];
|
|
limit = (uint32_t)(inLen - pos < MAX_MATCH ? inLen - pos : MAX_MATCH);
|
|
for (chain = 0; cand != NO_POS && chain < MAX_CHAIN && pos - cand <= WINDOW_BYTES; chain++) {
|
|
for (len = 0; len < limit && in[cand + len] == in[pos + len]; len++) {
|
|
}
|
|
if (len > bestLen) {
|
|
bestLen = len;
|
|
bestDist = (uint32_t)(pos - cand);
|
|
if (len == limit) {
|
|
break;
|
|
}
|
|
}
|
|
cand = prev[cand % WINDOW_BYTES];
|
|
}
|
|
}
|
|
if (bestLen >= MIN_MATCH) {
|
|
deflateLength(&d, bestLen);
|
|
deflateDistance(&d, bestDist);
|
|
} else {
|
|
bestLen = 1u;
|
|
deflateLiteral(&d, in[pos]);
|
|
}
|
|
for (k = 0; k < bestLen; k++, pos++) {
|
|
if (pos + MIN_MATCH <= inLen) {
|
|
h = hashAt(in + pos);
|
|
prev[pos % WINDOW_BYTES] = head[h];
|
|
head[h] = (uint32_t)pos;
|
|
}
|
|
}
|
|
}
|
|
deflateLiteral(&d, END_OF_BLOCK);
|
|
deflateFlush(&d);
|
|
adler = toolAdler32(1u, in, inLen);
|
|
deflateByte(&d, (uint8_t)(adler >> 24));
|
|
deflateByte(&d, (uint8_t)(adler >> 16));
|
|
deflateByte(&d, (uint8_t)(adler >> 8));
|
|
deflateByte(&d, (uint8_t)adler);
|
|
free(head);
|
|
free(prev);
|
|
if (d.error) {
|
|
free(d.out);
|
|
return false;
|
|
}
|
|
*out = d.out;
|
|
*outLen = d.outLen;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool toolInflate(const uint8_t *in, size_t inLen, ToolZlibFormatE fmt, uint8_t **out, size_t *outLen) {
|
|
InflateT s;
|
|
size_t pos;
|
|
uint8_t flags;
|
|
uint32_t xlen;
|
|
|
|
pos = 0;
|
|
if (fmt == TOOL_ZLIB_AUTO) {
|
|
fmt = (inLen >= 2u && in[0] == GZIP_ID1 && in[1] == GZIP_ID2) ? TOOL_ZLIB_GZIP : TOOL_ZLIB_ZLIB;
|
|
}
|
|
if (fmt == TOOL_ZLIB_ZLIB) {
|
|
if (inLen < 6u || (in[0] & 0x0Fu) != ZLIB_CM_DEFLATE || ((uint32_t)in[0] << 8 | in[1]) % ZLIB_CHECK != 0u || (in[1] & ZLIB_FDICT) != 0u) {
|
|
return false;
|
|
}
|
|
pos = 2u;
|
|
} else if (fmt == TOOL_ZLIB_GZIP) {
|
|
if (inLen < GZIP_HEADER_BYTES + GZIP_TRAILER_BYTES || in[0] != GZIP_ID1 || in[1] != GZIP_ID2 || in[2] != GZIP_CM_DEFLATE) {
|
|
return false;
|
|
}
|
|
flags = in[3];
|
|
pos = GZIP_HEADER_BYTES;
|
|
if ((flags & GZIP_FEXTRA) != 0u) {
|
|
if (pos + 2u > inLen) {
|
|
return false;
|
|
}
|
|
xlen = (uint32_t)in[pos] | (uint32_t)in[pos + 1u] << 8;
|
|
pos += 2u + xlen;
|
|
}
|
|
if ((flags & GZIP_FNAME) != 0u) {
|
|
while (pos < inLen && in[pos] != 0u) {
|
|
pos++;
|
|
}
|
|
pos++;
|
|
}
|
|
if ((flags & GZIP_FCOMMENT) != 0u) {
|
|
while (pos < inLen && in[pos] != 0u) {
|
|
pos++;
|
|
}
|
|
pos++;
|
|
}
|
|
if ((flags & GZIP_FHCRC) != 0u) {
|
|
pos += 2u;
|
|
}
|
|
if (pos >= inLen) {
|
|
return false;
|
|
}
|
|
}
|
|
memset(&s, 0, sizeof(s));
|
|
s.in = in;
|
|
s.inLen = inLen;
|
|
s.inPos = pos;
|
|
s.outCap = OUT_START_BYTES;
|
|
s.out = (uint8_t *)malloc(s.outCap);
|
|
if (s.out == NULL) {
|
|
return false;
|
|
}
|
|
if (!inflateRaw(&s)) {
|
|
free(s.out);
|
|
return false;
|
|
}
|
|
if (fmt == TOOL_ZLIB_ZLIB) {
|
|
if (s.inPos + 4u > inLen || readBe32(in + s.inPos) != toolAdler32(1u, s.out, s.outLen)) {
|
|
free(s.out);
|
|
return false;
|
|
}
|
|
} else if (fmt == TOOL_ZLIB_GZIP) {
|
|
if (s.inPos + GZIP_TRAILER_BYTES > inLen || readLe32(in + s.inPos) != toolCrc32(0u, s.out, s.outLen) || readLe32(in + s.inPos + 4u) != (uint32_t)s.outLen) {
|
|
free(s.out);
|
|
return false;
|
|
}
|
|
}
|
|
*out = s.out;
|
|
*outLen = s.outLen;
|
|
return true;
|
|
}
|