#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "thwack.h" typedef struct HuffDec HuffDec; struct HuffDec { ulong maxcode[MaxFastLen]; ulong last[MaxFastLen]; ulong decode[MaxFastLen]; }; static HuffDec lentab = { /* 0 1 2 3 4 5 6 7 */ {0, 0, 0x2, 0, 0xd, 0x1c, 0x3b, 0x79}, {-1, 0+0, 0x2+1, -1, 0xd+2, 0x1c+4, 0x3b+5, 0x79+7}, { 0, 1, 3, 2, 4, 6, 5, 8, 7, }, }; void unthwackinit(Unthwack *ut) { int i; memset(ut, 0, sizeof *ut); for(i = 0; i < EWinBlocks; i++) ut->blocks[i].data = ut->data[i]; } int unthwack(Unthwack *ut, uchar *dst, int ndst, uchar *src, int nsrc, ulong seq) { UnthwBlock blocks[CompBlocks], *b, *eblocks; uchar *s, *es, *d, *dmax, *smax, lit; ulong cmask, cseq, bseq, utbits, lithist; int off, len, bits, slot, tslot, use, code, utnbits, overbits; if(nsrc < 4 || nsrc > ThwMaxBlock) return -1; /* * find the correct slot for this block, * the oldest block around. the encoder * doesn't use a history at wraparound, * so don't worry about that case. */ tslot = ut->slot; for(;;){ slot = tslot - 1; if(slot < 0) slot += DWinBlocks; if(ut->blocks[slot].seq <= seq) break; ut->blocks[slot] = ut->blocks[slot]; tslot = slot; } b = blocks; ut->blocks[tslot].seq = seq; ut->blocks[tslot].maxoff = 0; *b = ut->blocks[tslot]; d = b->data; dmax = d + ndst; /* * set up the history blocks */ cseq = seq - src[0]; cmask = src[1]; b++; slot = tslot; while(cseq != seq && b < blocks + CompBlocks){ slot--; if(slot < 0) slot += DWinBlocks; if(slot == ut->slot) break; bseq = ut->blocks[slot].seq; if(bseq == cseq){ *b = ut->blocks[slot]; b++; if(cmask == 0){ cseq = seq; break; } do{ bits = cmask & 1; cseq--; cmask >>= 1; }while(!bits); } } eblocks = b; if(cseq != seq){ print("blocks not in decompression window: cseq=%ld seq=%ld cmask=%lux nb=%ld\n", cseq, seq, cmask, eblocks - blocks); return -1; } smax = src + nsrc; src += 2; utnbits = 0; utbits = 0; overbits = 0; lithist = ~0; while(src < smax || utnbits - overbits >= MinDecode){ while(utnbits <= 24){ utbits <<= 8; if(src < smax) utbits |= *src++; else overbits += 8; utnbits += 8; } /* * literal */ if(((utbits >> (utnbits - 1)) & 1) == 0){ if(lithist & 0xf){ utnbits -= 9; lit = (utbits >> utnbits) & 0xff; lit &= 255; }else{ utnbits -= 8; lit = (utbits >> utnbits) & 0x7f; if(lit < 32){ if(lit < 24){ utnbits -= 2; lit = (lit << 2) | ((utbits >> utnbits) & 3); }else{ utnbits -= 3; lit = (lit << 3) | ((utbits >> utnbits) & 7); } lit = (lit - 64) & 0xff; } } *d++ = lit; lithist = (lithist << 1) | lit < 32 | lit > 127; blocks->maxoff++; continue; } /* * match; next 3 bits decode offset range */ utnbits -= 4; bits = (utbits >> utnbits) & ((1 << 3) - 1); if(bits){ bits += OffBase - 1; off = 1 << bits; }else{ bits = OffBase; off = 0; } utnbits -= bits; off |= (utbits >> utnbits) & ((1 << bits) - 1); off++; bits = 0; utbits &= (1 << utnbits) - 1; do{ bits++; len = utbits >> (utnbits - bits); }while(bits < BigLenBits && len > lentab.maxcode[bits]); utnbits -= bits; if(bits < BigLenBits) len = lentab.decode[lentab.last[bits] - len]; else{ while(utnbits < MaxLenDecode){ utbits <<= 8; if(src < smax) utbits |= *src++; else overbits += 8; utnbits += 8; } code = len - BigLenCode; len = MaxFastLen; bits = 8; use = BigLenBase; while(code >= use){ len += use; code -= use; code <<= 1; utnbits--; code |= (utbits >> utnbits) & 1; use <<= bits & 1; bits++; } len += code; } len += MinMatch; b = blocks; while(off > b->maxoff){ off -= b->maxoff; b++; if(b >= eblocks) return -1; } if(d + len > dmax || b != blocks && len > off) return -1; s = b->data + b->maxoff - off; es = s + len; while(s < es) *d++ = *s++; blocks->maxoff += len; } if(utnbits < overbits) return -1; len = d - blocks->data; memmove(dst, blocks->data, len); ut->blocks[tslot].maxoff = len; ut->slot++; if(ut->slot >= DWinBlocks) ut->slot = 0; return len; }