Skip to content

Commit

Permalink
restore full deflate compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
vurtun committed Jan 4, 2021
1 parent ba74d5d commit 85d2cd7
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 66 deletions.
76 changes: 47 additions & 29 deletions sdefl.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ struct sdefl_seqt {
int off, len;
};
struct sdefl {
int bits, cnt;
int bits, bitcnt;
int tbl[SDEFL_HASH_SIZ];
int prv[SDEFL_WIN_SIZ];

Expand Down Expand Up @@ -231,13 +231,13 @@ sdefl_hash32(const void *p) {
}
static void
sdefl_put(unsigned char **dst, struct sdefl *s, int code, int bitcnt) {
s->bits |= (code << s->cnt);
s->cnt += bitcnt;
while (s->cnt >= 8) {
s->bits |= (code << s->bitcnt);
s->bitcnt += bitcnt;
while (s->bitcnt >= 8) {
unsigned char *tar = *dst;
*tar = (unsigned char)(s->bits & 0xFF);
s->bits >>= 8;
s->cnt -= 8;
s->bitcnt -= 8;
*dst = *dst + 1;
}
}
Expand Down Expand Up @@ -379,15 +379,31 @@ sdefl_huff(unsigned char *lens, unsigned *codes, unsigned *freqs,
codes[c] = sdefl_rev(codes[c], lens[c]);
}
}
struct sdefl_symcnt {
int items;
int lit;
int off;
};
static void
sdefl_precode(unsigned *freqs, unsigned *items, unsigned *item_cnt,
const unsigned char *lens, const unsigned cnt) {
sdefl_precode(struct sdefl_symcnt *cnt, unsigned *freqs, unsigned *items,
const unsigned char *litlen, const unsigned char *offlen) {
unsigned *at = items;
unsigned run_start = 0;

unsigned total = 0;
unsigned char lens[SDEFL_SYM_MAX + SDEFL_OFF_MAX];
for (cnt->lit = SDEFL_SYM_MAX; cnt->lit > 257; cnt->lit--)
if (litlen[cnt->lit - 1]) break;
for (cnt->off = SDEFL_OFF_MAX; cnt->off > 1; cnt->off--)
if (offlen[cnt->off - 1]) break;

total = (unsigned)(cnt->lit + cnt->off);
memcpy(lens, litlen, sizeof(unsigned char) * cnt->lit);
memcpy(lens + cnt->lit, offlen, sizeof(unsigned char) * cnt->off);
do {
unsigned len = lens[run_start];
unsigned run_end = run_start;
do run_end++; while (run_end != cnt && len == lens[run_end]);
do run_end++; while (run_end != total && len == lens[run_end]);
if (!len) {
while ((run_end - run_start) >= 11) {
unsigned n = (run_end - run_start) - 11;
Expand Down Expand Up @@ -420,8 +436,8 @@ sdefl_precode(unsigned *freqs, unsigned *items, unsigned *item_cnt,
*at++ = len;
run_start++;
}
} while (run_start != cnt);
*item_cnt = (unsigned)(at - items);
} while (run_start != total);
cnt->items = (int)(at - items);
}
static void
sdefl_match_codes(int *ls, int *lc, int *dx, int *dc, int dist, int len) {
Expand Down Expand Up @@ -466,8 +482,8 @@ sdefl_match(unsigned char **dst, struct sdefl *s, int dist, int len) {
static void
sdefl_flush(unsigned char **dst, struct sdefl *s, int is_last,
const unsigned char *in) {
int j, n = 0;
unsigned i, item_cnt = 0;
int j, i = 0, item_cnt = 0;
struct sdefl_symcnt symcnt = {0};
unsigned codes[SDEFL_PRE_MAX];
unsigned char lens[SDEFL_PRE_MAX];
unsigned freqs[SDEFL_PRE_MAX] = {0};
Expand All @@ -479,18 +495,20 @@ sdefl_flush(unsigned char **dst, struct sdefl *s, int is_last,
s->freq.lit[SDEFL_EOB]++;
sdefl_huff(s->cod.len.lit, s->cod.word.lit, s->freq.lit, SDEFL_SYM_MAX, SDEFL_LIT_LEN_CODES);
sdefl_huff(s->cod.len.off, s->cod.word.off, s->freq.off, SDEFL_OFF_MAX, SDEFL_OFF_CODES);
sdefl_precode(freqs, items, &item_cnt, s->cod.len.lit, SDEFL_SYM_MAX+SDEFL_OFF_MAX);
sdefl_precode(&symcnt, freqs, items, s->cod.len.lit, s->cod.len.off);
sdefl_huff(lens, codes, freqs, SDEFL_PRE_MAX, SDEFL_PRE_CODES);

for (item_cnt = SDEFL_PRE_MAX; item_cnt > 4; item_cnt--) {
if (lens[perm[item_cnt - 1]]) break;
}
/* block header */
sdefl_put(dst, s, is_last ? 0x01 : 0x00, 1); /* block */
sdefl_put(dst, s, 0x02, 2); /* dynamic huffman */
sdefl_put(dst, s, SDEFL_SYM_MAX - 257, 5);
sdefl_put(dst, s, SDEFL_OFF_MAX - 1, 5);
sdefl_put(dst, s, SDEFL_PRE_MAX - 4, 4);
for (i = 0; i < SDEFL_PRE_MAX; ++i)
sdefl_put(dst, s, symcnt.lit - 257, 5);
sdefl_put(dst, s, symcnt.off - 1, 5);
sdefl_put(dst, s, item_cnt - 4, 4);
for (i = 0; i < item_cnt; ++i)
sdefl_put(dst, s, lens[perm[i]], 3);
for (i = 0; i < item_cnt; ++i) {
for (i = 0; i < symcnt.items; ++i) {
unsigned sym = items[i] & 0x1F;
sdefl_put(dst, s, (int)codes[sym], lens[sym]);
if (sym < 16) continue;
Expand All @@ -499,13 +517,13 @@ sdefl_flush(unsigned char **dst, struct sdefl *s, int is_last,
else sdefl_put(dst, s, items[i] >> 5, 7);
}
/* block sequences */
for (n = 0; n < s->seq_cnt; ++n) {
if (s->seq[n].off >= 0)
for (j = 0; j < s->seq[n].len; ++j) {
int c = in[s->seq[n].off + j];
for (i = 0; i < s->seq_cnt; ++i) {
if (s->seq[i].off >= 0)
for (j = 0; j < s->seq[i].len; ++j) {
int c = in[s->seq[i].off + j];
sdefl_put(dst, s, (int)s->cod.word.lit[c], s->cod.len.lit[c]);
}
else sdefl_match(dst, s, -s->seq[n].off, s->seq[n].len);
else sdefl_match(dst, s, -s->seq[i].off, s->seq[i].len);
}
sdefl_put(dst, s, (int)(s)->cod.word.lit[SDEFL_EOB], (s)->cod.len.lit[SDEFL_EOB]);
memset(&s->freq, 0, sizeof(s->freq));
Expand Down Expand Up @@ -553,7 +571,7 @@ sdefl_compr(struct sdefl *s, unsigned char *out, const unsigned char *in,
int in_len, int lvl) {
unsigned char *q = out;
static const unsigned char pref[] = {8,10,14,24,30,48,65,96,130};
int max_chain = (lvl < 8) ? (1<<(lvl+1)): (1<<13);
int max_chain = (lvl < 8) ? (1 << (lvl + 1)): (1 << 13);
int n, i = 0, litlen = 0;
for (n = 0; n < SDEFL_HASH_SIZ; ++n) {
s->tbl[n] = SDEFL_NIL;
Expand Down Expand Up @@ -606,13 +624,13 @@ sdefl_compr(struct sdefl *s, unsigned char *out, const unsigned char *in,
sdefl_flush(&q, s, blk_end == in_len, in);
} while (i < in_len);

if (s->cnt)
sdefl_put(&q, s, 0x00, 8 - s->cnt);
if (s->bitcnt)
sdefl_put(&q, s, 0x00, 8 - s->bitcnt);
return (int)(q - out);
}
extern int
sdeflate(struct sdefl *s, void *out, const void *in, int n, int lvl) {
s->bits = s->cnt = 0;
s->bits = s->bitcnt = 0;
return sdefl_compr(s, (unsigned char*)out, (const unsigned char*)in, n, lvl);
}
static unsigned
Expand Down Expand Up @@ -652,7 +670,7 @@ zsdeflate(struct sdefl *s, void *out, const void *in, int n, int lvl) {
unsigned a = 0;
unsigned char *q = (unsigned char*)out;

s->bits = s->cnt = 0;
s->bits = s->bitcnt = 0;
sdefl_put(&q, s, 0x78, 8); /* deflate, 32k window */
sdefl_put(&q, s, 0x01, 8); /* fast compression */
q += sdefl_compr(s, q, (const unsigned char*)in, n, lvl);
Expand Down
78 changes: 41 additions & 37 deletions sinfl.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ extern "C" {
#define SINFL_OFF_TBL_SIZE 402

struct sinfl {
int bits, bitcnt;
unsigned lits[SINFL_LIT_TBL_SIZE];
unsigned dsts[SINFL_OFF_TBL_SIZE];
int bits, bitcnt;
unsigned lits[SINFL_LIT_TBL_SIZE];
unsigned dsts[SINFL_OFF_TBL_SIZE];
};
extern int sinflate(void *out, const void *in, int size);
extern int zsinflate(void *out, const void *in, int size);
Expand Down Expand Up @@ -281,6 +281,7 @@ sinfl_decode(const unsigned char **in, const unsigned char *end,
int idx = s->bits & ((1 << bit_len) - 1);
unsigned key = tbl[idx];
if (key & 0x10) {
/* sub-table lookup */
int len = key & 0x0f;
sinfl_get(in, end, s, bit_len);
idx = s->bits & ((1 << len)-1);
Expand Down Expand Up @@ -327,7 +328,8 @@ sinfl_decompress(unsigned char *out, const unsigned char *in, int size) {
nlen = sinfl_get(&in,e,&s,16);
in -= 2; s.bitcnt = 0;

if (len > (e-in) || !len) return (int)(out-o);
if (len > (e-in) || !len)
return (int)(out-o);
memcpy(out, in, (size_t)len);
in += len, out += len;
state = hdr;
Expand Down Expand Up @@ -373,41 +375,43 @@ sinfl_decompress(unsigned char *out, const unsigned char *in, int size) {
} break;
case blk: {
/* decompress block */
while (in < e || s.bitcnt) {
int i, sym = sinfl_decode(&in, e, &s, s.lits, 10);
if (sym > 256) {sym -= 257; /* match symbol */
{int len = sinfl_get(&in, e, &s, lbits[sym]) + lbase[sym];
int dsym = sinfl_decode(&in, e, &s, s.dsts, 8);
int offs = sinfl_get(&in, e, &s, dbits[dsym]) + dbase[dsym];
if (offs > (int)(out-o)) {
return (int)(out-o);
} else if (offs == 1) {
unsigned char c = *(out - offs);
unsigned long w = (c << 24) | (c << 16) | (c << 8) | c;
for (i = 0; i < len >> 2; ++i) {
memcpy(out, &w, 4);
out += 4;
}
len = len & 3;
} else if (offs >= 4) {
int wcnt = len >> 2;
for (i = 0; i < wcnt; ++i) {
unsigned long w = 0;
memcpy(&w, out - offs, 4);
memcpy(out, &w, 4);
out += 4;
}
len = len & 3;
int i, sym = sinfl_decode(&in, e, &s, s.lits, 10);
if (sym > 256) {sym -= 257; /* match symbol */
{int len = sinfl_get(&in, e, &s, lbits[sym]) + lbase[sym];
int dsym = sinfl_decode(&in, e, &s, s.dsts, 8);
int offs = sinfl_get(&in, e, &s, dbits[dsym]) + dbase[dsym];
if (offs > (int)(out-o)) {
return (int)(out-o);
} else if (offs == 1) {
/* rle match copying */
unsigned char c = *(out - offs);
unsigned long w = (c << 24) | (c << 16) | (c << 8) | c;
for (i = 0; i < len >> 2; ++i) {
memcpy(out, &w, 4);
out += 4;
}
for (i = 0; i < len; ++i)
{*out = *(out-offs), out++;}
len = len & 3;
} else if (offs >= 4) {
/* copy match */
int wcnt = len >> 2;
for (i = 0; i < wcnt; ++i) {
unsigned long w = 0;
memcpy(&w, out - offs, 4);
memcpy(out, &w, 4);
out += 4;
}
} else if (sym == 256) {
if (last) return (int)(out-o);
state = hdr;
break;
} else *out++ = (unsigned char)sym;
}
len = len & 3;
}
for (i = 0; i < len; ++i)
{*out = *(out-offs), out++;}
}
} else if (sym == 256) {
/* end of block */
if (last) return (int)(out-o);
state = hdr;
break;
/* literal */
} else *out++ = (unsigned char)sym;
} break;}
}
return (int)(out-o);
Expand Down

0 comments on commit 85d2cd7

Please sign in to comment.