621 lines
11 KiB
C
621 lines
11 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include "sac.h"
|
|
|
|
typedef struct Huff Huff;
|
|
typedef struct Mtf Mtf;
|
|
typedef struct Decode Decode;
|
|
|
|
enum
|
|
{
|
|
ZBase = 2, /* base of code to encode 0 runs */
|
|
LitBase = ZBase-1, /* base of literal values */
|
|
MaxLit = 256,
|
|
|
|
MaxLeaf = MaxLit+LitBase,
|
|
MaxHuffBits = 16, /* max bits in a huffman code */
|
|
MaxFlatbits = 5, /* max bits decoded in flat table */
|
|
|
|
CombLog = 4,
|
|
CombSpace = 1 << CombLog, /* mtf speedup indices spacing */
|
|
CombMask = CombSpace - 1,
|
|
};
|
|
|
|
struct Mtf
|
|
{
|
|
int maxcomb; /* index of last valid comb */
|
|
uchar prev[MaxLit];
|
|
uchar next[MaxLit];
|
|
uchar comb[MaxLit / CombSpace + 1];
|
|
};
|
|
|
|
struct Huff
|
|
{
|
|
int maxbits;
|
|
int flatbits;
|
|
ulong flat[1<<MaxFlatbits];
|
|
ulong maxcode[MaxHuffBits];
|
|
ulong last[MaxHuffBits];
|
|
ulong decode[MaxLeaf];
|
|
};
|
|
|
|
struct Decode{
|
|
Huff tab;
|
|
Mtf mtf;
|
|
int nbits;
|
|
ulong bits;
|
|
int nzero;
|
|
int base;
|
|
ulong maxblocksym;
|
|
|
|
jmp_buf errjmp;
|
|
|
|
uchar *src; /* input buffer */
|
|
uchar *smax; /* limit */
|
|
};
|
|
|
|
static void fatal(Decode *dec, char*);
|
|
|
|
static int hdec(Decode*);
|
|
static void recvtab(Decode*, Huff*, int, ushort*);
|
|
static ulong bitget(Decode*, int);
|
|
static int mtf(uchar*, int);
|
|
|
|
#define FORWARD 0
|
|
|
|
static void
|
|
mtflistinit(Mtf *m, uchar *front, int n)
|
|
{
|
|
int last, me, f, i, comb;
|
|
|
|
if(n == 0)
|
|
return;
|
|
|
|
/*
|
|
* add all entries to free list
|
|
*/
|
|
last = MaxLit - 1;
|
|
for(i = 0; i < MaxLit; i++){
|
|
m->prev[i] = last;
|
|
m->next[i] = i + 1;
|
|
last = i;
|
|
}
|
|
m->next[last] = 0;
|
|
f = 0;
|
|
|
|
/*
|
|
* pull valid entries off free list and enter into mtf list
|
|
*/
|
|
comb = 0;
|
|
last = front[0];
|
|
for(i = 0; i < n; i++){
|
|
me = front[i];
|
|
|
|
f = m->next[me];
|
|
m->prev[f] = m->prev[me];
|
|
m->next[m->prev[f]] = f;
|
|
|
|
m->next[last] = me;
|
|
m->prev[me] = last;
|
|
last = me;
|
|
if((i & CombMask) == 0)
|
|
m->comb[comb++] = me;
|
|
}
|
|
|
|
/*
|
|
* pad out the list with dummies to the next comb,
|
|
* using free entries
|
|
*/
|
|
for(; i & CombMask; i++){
|
|
me = f;
|
|
|
|
f = m->next[me];
|
|
m->prev[f] = m->prev[me];
|
|
m->next[m->prev[f]] = f;
|
|
|
|
m->next[last] = me;
|
|
m->prev[me] = last;
|
|
last = me;
|
|
}
|
|
me = front[0];
|
|
m->next[last] = me;
|
|
m->prev[me] = last;
|
|
m->comb[comb] = me;
|
|
m->maxcomb = comb;
|
|
}
|
|
|
|
static int
|
|
mtflist(Mtf *m, int pos)
|
|
{
|
|
uchar *next, *prev, *mycomb;
|
|
int c, c0, pc, nc, off;
|
|
|
|
if(pos == 0)
|
|
return m->comb[0];
|
|
|
|
next = m->next;
|
|
prev = m->prev;
|
|
mycomb = &m->comb[pos >> CombLog];
|
|
off = pos & CombMask;
|
|
if(off >= CombSpace / 2){
|
|
c = mycomb[1];
|
|
for(; off < CombSpace; off++)
|
|
c = prev[c];
|
|
}else{
|
|
c = *mycomb;
|
|
for(; off; off--)
|
|
c = next[c];
|
|
}
|
|
|
|
nc = next[c];
|
|
pc = prev[c];
|
|
prev[nc] = pc;
|
|
next[pc] = nc;
|
|
|
|
for(; mycomb > m->comb; mycomb--)
|
|
*mycomb = prev[*mycomb];
|
|
c0 = *mycomb;
|
|
*mycomb = c;
|
|
mycomb[m->maxcomb] = c;
|
|
|
|
next[c] = c0;
|
|
pc = prev[c0];
|
|
prev[c] = pc;
|
|
prev[c0] = c;
|
|
next[pc] = c;
|
|
return c;
|
|
}
|
|
|
|
static void
|
|
hdecblock(Decode *dec, ulong n, ulong I, uchar *buf, ulong *sums, ulong *prev)
|
|
{
|
|
ulong i, nn, sum;
|
|
int m, z, zz, c;
|
|
|
|
nn = I;
|
|
n--;
|
|
i = 0;
|
|
again:
|
|
for(; i < nn; i++){
|
|
while((m = hdec(dec)) == 0 && i + dec->nzero < n)
|
|
;
|
|
if(z = dec->nzero){
|
|
dec->nzero = 0;
|
|
c = dec->mtf.comb[0];
|
|
sum = sums[c];
|
|
sums[c] = sum + z;
|
|
|
|
z += i;
|
|
zz = z;
|
|
if(i < I && z > I){
|
|
zz = I;
|
|
z++;
|
|
}
|
|
|
|
zagain:
|
|
for(; i < zz; i++){
|
|
buf[i] = c;
|
|
prev[i] = sum++;
|
|
}
|
|
if(i != z){
|
|
zz = z;
|
|
nn = ++n;
|
|
i++;
|
|
goto zagain;
|
|
}
|
|
if(i == nn){
|
|
if(i == n)
|
|
return;
|
|
nn = ++n;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
c = mtflist(&dec->mtf, m);
|
|
|
|
buf[i] = c;
|
|
sum = sums[c];
|
|
prev[i] = sum++;
|
|
sums[c] = sum;
|
|
|
|
}
|
|
if(i == n)
|
|
return;
|
|
nn = ++n;
|
|
i++;
|
|
goto again;
|
|
}
|
|
|
|
int
|
|
unsac(uchar *dst, uchar *src, int n, int nsrc)
|
|
{
|
|
Decode *dec;
|
|
uchar *buf, *front;
|
|
ulong *prev, *sums;
|
|
ulong sum, i, I;
|
|
int m, j, c;
|
|
|
|
dec = malloc(sizeof *dec);
|
|
buf = malloc(n+2);
|
|
prev = malloc((n+2) * sizeof *prev);
|
|
front = malloc(MaxLit * sizeof *front);
|
|
sums = malloc(MaxLit * sizeof *sums);
|
|
|
|
if(dec == nil || buf == nil || prev == nil || front == nil || sums == nil || setjmp(dec->errjmp)){
|
|
free(dec);
|
|
free(buf);
|
|
free(prev);
|
|
free(front);
|
|
free(sums);
|
|
return -1;
|
|
}
|
|
|
|
dec->src = src;
|
|
dec->smax = src + nsrc;
|
|
|
|
dec->nbits = 0;
|
|
dec->bits = 0;
|
|
dec->nzero = 0;
|
|
for(i = 0; i < MaxLit; i++)
|
|
front[i] = i;
|
|
|
|
n++;
|
|
I = bitget(dec, 16);
|
|
if(I >= n)
|
|
fatal(dec, "corrupted input");
|
|
|
|
/*
|
|
* decode the character usage map
|
|
*/
|
|
for(i = 0; i < MaxLit; i++)
|
|
sums[i] = 0;
|
|
c = bitget(dec, 1);
|
|
for(i = 0; i < MaxLit; ){
|
|
m = bitget(dec, 8) + 1;
|
|
while(m--){
|
|
if(i >= MaxLit)
|
|
fatal(dec, "corrupted char map");
|
|
front[i++] = c;
|
|
}
|
|
c = c ^ 1;
|
|
}
|
|
|
|
/*
|
|
* initialize mtf state
|
|
*/
|
|
c = 0;
|
|
for(i = 0; i < MaxLit; i++)
|
|
if(front[i])
|
|
front[c++] = i;
|
|
mtflistinit(&dec->mtf, front, c);
|
|
dec->maxblocksym = c + LitBase;
|
|
|
|
/*
|
|
* huffman decoding, move to front decoding,
|
|
* along with character counting
|
|
*/
|
|
dec->base = 1;
|
|
recvtab(dec, &dec->tab, MaxLeaf, nil);
|
|
hdecblock(dec, n, I, buf, sums, prev);
|
|
|
|
sum = 1;
|
|
for(i = 0; i < MaxLit; i++){
|
|
c = sums[i];
|
|
sums[i] = sum;
|
|
sum += c;
|
|
}
|
|
|
|
i = 0;
|
|
for(j = n - 2; j >= 0; j--){
|
|
if(i > n || i < 0 || i == I)
|
|
fatal(dec, "corrupted data");
|
|
c = buf[i];
|
|
dst[j] = c;
|
|
i = prev[i] + sums[c];
|
|
}
|
|
|
|
free(dec);
|
|
free(buf);
|
|
free(prev);
|
|
free(front);
|
|
free(sums);
|
|
return n;
|
|
}
|
|
|
|
static ulong
|
|
bitget(Decode *dec, int nb)
|
|
{
|
|
int c;
|
|
|
|
while(dec->nbits < nb){
|
|
if(dec->src >= dec->smax)
|
|
fatal(dec, "premature eof 1");
|
|
c = *dec->src++;
|
|
dec->bits <<= 8;
|
|
dec->bits |= c;
|
|
dec->nbits += 8;
|
|
}
|
|
dec->nbits -= nb;
|
|
return (dec->bits >> dec->nbits) & ((1 << nb) - 1);
|
|
}
|
|
|
|
static void
|
|
fillbits(Decode *dec)
|
|
{
|
|
int c;
|
|
|
|
while(dec->nbits < 24){
|
|
if(dec->src >= dec->smax)
|
|
fatal(dec, "premature eof 2");
|
|
c = *dec->src++;
|
|
dec->bits <<= 8;
|
|
dec->bits |= c;
|
|
dec->nbits += 8;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* decode one symbol
|
|
*/
|
|
static int
|
|
hdecsym(Decode *dec, Huff *h, int b)
|
|
{
|
|
long c;
|
|
ulong bits;
|
|
int nbits;
|
|
|
|
bits = dec->bits;
|
|
nbits = dec->nbits;
|
|
for(; (c = bits >> (nbits - b)) > h->maxcode[b]; b++)
|
|
;
|
|
if(b > h->maxbits)
|
|
fatal(dec, "too many bits consumed");
|
|
dec->nbits = nbits - b;
|
|
return h->decode[h->last[b] - c];
|
|
}
|
|
|
|
static int
|
|
hdec(Decode *dec)
|
|
{
|
|
ulong c;
|
|
int nbits, nb;
|
|
|
|
if(dec->nbits < dec->tab.maxbits)
|
|
fillbits(dec);
|
|
nbits = dec->nbits;
|
|
dec->bits &= (1 << nbits) - 1;
|
|
c = dec->tab.flat[dec->bits >> (nbits - dec->tab.flatbits)];
|
|
nb = c & 0xff;
|
|
c >>= 8;
|
|
if(nb == 0xff)
|
|
c = hdecsym(dec, &dec->tab, c);
|
|
else
|
|
dec->nbits = nbits - nb;
|
|
|
|
/*
|
|
* reverse funny run-length coding
|
|
*/
|
|
if(c < ZBase){
|
|
dec->nzero += dec->base << c;
|
|
dec->base <<= 1;
|
|
return 0;
|
|
}
|
|
|
|
dec->base = 1;
|
|
c -= LitBase;
|
|
return c;
|
|
}
|
|
|
|
static void
|
|
hufftab(Decode *dec, Huff *h, char *hb, ulong *bitcount, int maxleaf, int maxbits, int flatbits)
|
|
{
|
|
ulong c, mincode, code, nc[MaxHuffBits];
|
|
int i, b, ec;
|
|
|
|
h->maxbits = maxbits;
|
|
if(maxbits < 0)
|
|
return;
|
|
|
|
code = 0;
|
|
c = 0;
|
|
for(b = 0; b <= maxbits; b++){
|
|
h->last[b] = c;
|
|
c += bitcount[b];
|
|
mincode = code << 1;
|
|
nc[b] = mincode;
|
|
code = mincode + bitcount[b];
|
|
if(code > (1 << b))
|
|
fatal(dec, "corrupted huffman table");
|
|
h->maxcode[b] = code - 1;
|
|
h->last[b] += code - 1;
|
|
}
|
|
if(code != (1 << maxbits))
|
|
fatal(dec, "huffman table not full");
|
|
if(flatbits > maxbits)
|
|
flatbits = maxbits;
|
|
h->flatbits = flatbits;
|
|
|
|
b = 1 << flatbits;
|
|
for(i = 0; i < b; i++)
|
|
h->flat[i] = ~0;
|
|
|
|
/*
|
|
* initialize the flat table to include the minimum possible
|
|
* bit length for each code prefix
|
|
*/
|
|
for(b = maxbits; b > flatbits; b--){
|
|
code = h->maxcode[b];
|
|
if(code == -1)
|
|
break;
|
|
mincode = code + 1 - bitcount[b];
|
|
mincode >>= b - flatbits;
|
|
code >>= b - flatbits;
|
|
for(; mincode <= code; mincode++)
|
|
h->flat[mincode] = (b << 8) | 0xff;
|
|
}
|
|
|
|
for(i = 0; i < maxleaf; i++){
|
|
b = hb[i];
|
|
if(b == -1)
|
|
continue;
|
|
c = nc[b]++;
|
|
if(b <= flatbits){
|
|
code = (i << 8) | b;
|
|
ec = (c + 1) << (flatbits - b);
|
|
if(ec > (1<<flatbits))
|
|
fatal(dec, "flat code too big");
|
|
for(c <<= (flatbits - b); c < ec; c++)
|
|
h->flat[c] = code;
|
|
}else{
|
|
c = h->last[b] - c;
|
|
if(c >= maxleaf)
|
|
fatal(dec, "corrupted huffman table");
|
|
h->decode[c] = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
elimBit(int b, char *tmtf, int maxbits)
|
|
{
|
|
int bb;
|
|
|
|
for(bb = 0; bb < maxbits; bb++)
|
|
if(tmtf[bb] == b)
|
|
break;
|
|
while(++bb <= maxbits)
|
|
tmtf[bb - 1] = tmtf[bb];
|
|
}
|
|
|
|
static int
|
|
elimBits(int b, ulong *bused, char *tmtf, int maxbits)
|
|
{
|
|
int bb, elim;
|
|
|
|
if(b < 0)
|
|
return 0;
|
|
|
|
elim = 0;
|
|
|
|
/*
|
|
* increase bits counts for all descendants
|
|
*/
|
|
for(bb = b + 1; bb < maxbits; bb++){
|
|
bused[bb] += 1 << (bb - b);
|
|
if(bused[bb] == (1 << bb)){
|
|
elim++;
|
|
elimBit(bb, tmtf, maxbits);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* steal bits from parent & check for fullness
|
|
*/
|
|
for(; b >= 0; b--){
|
|
bused[b]++;
|
|
if(bused[b] == (1 << b)){
|
|
elim++;
|
|
elimBit(b, tmtf, maxbits);
|
|
}
|
|
if((bused[b] & 1) == 0)
|
|
break;
|
|
}
|
|
return elim;
|
|
}
|
|
|
|
static void
|
|
recvtab(Decode *dec, Huff *tab, int maxleaf, ushort *map)
|
|
{
|
|
ulong bitcount[MaxHuffBits+1], bused[MaxHuffBits+1];
|
|
char tmtf[MaxHuffBits+1], *hb;
|
|
int i, b, ttb, m, maxbits, max, elim;
|
|
|
|
hb = malloc(MaxLeaf * sizeof *hb);
|
|
if(hb == nil)
|
|
fatal(dec, "out of memory");
|
|
|
|
/*
|
|
* read the tables for the tables
|
|
*/
|
|
max = 8;
|
|
for(i = 0; i <= MaxHuffBits; i++){
|
|
bitcount[i] = 0;
|
|
tmtf[i] = i;
|
|
bused[i] = 0;
|
|
}
|
|
tmtf[0] = -1;
|
|
tmtf[max] = 0;
|
|
elim = 0;
|
|
maxbits = -1;
|
|
for(i = 0; i <= MaxHuffBits && elim != max; i++){
|
|
ttb = 4;
|
|
while(max - elim < (1 << (ttb-1)))
|
|
ttb--;
|
|
b = bitget(dec, ttb);
|
|
if(b > max - elim)
|
|
fatal(dec, "corrupted huffman table table");
|
|
b = tmtf[b];
|
|
hb[i] = b;
|
|
bitcount[b]++;
|
|
if(b > maxbits)
|
|
maxbits = b;
|
|
|
|
elim += elimBits(b, bused, tmtf, max);
|
|
}
|
|
if(elim != max)
|
|
fatal(dec, "incomplete huffman table table");
|
|
hufftab(dec, tab, hb, bitcount, i, maxbits, MaxFlatbits);
|
|
for(i = 0; i <= MaxHuffBits; i++){
|
|
tmtf[i] = i;
|
|
bitcount[i] = 0;
|
|
bused[i] = 0;
|
|
}
|
|
tmtf[0] = -1;
|
|
tmtf[MaxHuffBits] = 0;
|
|
elim = 0;
|
|
maxbits = -1;
|
|
for(i = 0; i < maxleaf && elim != MaxHuffBits; i++){
|
|
if(dec->nbits <= tab->maxbits)
|
|
fillbits(dec);
|
|
dec->bits &= (1 << dec->nbits) - 1;
|
|
m = tab->flat[dec->bits >> (dec->nbits - tab->flatbits)];
|
|
b = m & 0xff;
|
|
m >>= 8;
|
|
if(b == 0xff)
|
|
m = hdecsym(dec, tab, m);
|
|
else
|
|
dec->nbits -= b;
|
|
b = tmtf[m];
|
|
for(; m > 0; m--)
|
|
tmtf[m] = tmtf[m-1];
|
|
tmtf[0] = b;
|
|
|
|
if(b > MaxHuffBits)
|
|
fatal(dec, "bit length too big");
|
|
m = i;
|
|
if(map != nil)
|
|
m = map[m];
|
|
hb[m] = b;
|
|
bitcount[b]++;
|
|
if(b > maxbits)
|
|
maxbits = b;
|
|
elim += elimBits(b, bused, tmtf, MaxHuffBits);
|
|
}
|
|
if(elim != MaxHuffBits && elim != 0)
|
|
fatal(dec, "incomplete huffman table");
|
|
if(map != nil)
|
|
for(; i < maxleaf; i++)
|
|
hb[map[i]] = -1;
|
|
|
|
hufftab(dec, tab, hb, bitcount, i, maxbits, MaxFlatbits);
|
|
|
|
free(hb);
|
|
}
|
|
|
|
static void
|
|
fatal(Decode *dec, char *msg)
|
|
{
|
|
print("%s: %s\n", argv0, msg);
|
|
longjmp(dec->errjmp, 1);
|
|
}
|