17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier
77dd7cddfSDavid du Colombier #include "thwack.h"
87dd7cddfSDavid du Colombier
97dd7cddfSDavid du Colombier enum
107dd7cddfSDavid du Colombier {
117dd7cddfSDavid du Colombier DMaxFastLen = 7,
127dd7cddfSDavid du Colombier DBigLenCode = 0x3c, /* minimum code for large lenth encoding */
137dd7cddfSDavid du Colombier DBigLenBits = 6,
147dd7cddfSDavid du Colombier DBigLenBase = 1 /* starting items to encode for big lens */
157dd7cddfSDavid du Colombier };
167dd7cddfSDavid du Colombier
177dd7cddfSDavid du Colombier static uchar lenval[1 << (DBigLenBits - 1)] =
187dd7cddfSDavid du Colombier {
197dd7cddfSDavid du Colombier 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
207dd7cddfSDavid du Colombier 3, 3, 3, 3, 3, 3, 3, 3,
217dd7cddfSDavid du Colombier 4, 4, 4, 4,
227dd7cddfSDavid du Colombier 5,
237dd7cddfSDavid du Colombier 6,
247dd7cddfSDavid du Colombier 255,
257dd7cddfSDavid du Colombier 255
267dd7cddfSDavid du Colombier };
277dd7cddfSDavid du Colombier
287dd7cddfSDavid du Colombier static uchar lenbits[] =
297dd7cddfSDavid du Colombier {
307dd7cddfSDavid du Colombier 0, 0, 0,
317dd7cddfSDavid du Colombier 2, 3, 5, 5,
327dd7cddfSDavid du Colombier };
337dd7cddfSDavid du Colombier
347dd7cddfSDavid du Colombier static uchar offbits[16] =
357dd7cddfSDavid du Colombier {
367dd7cddfSDavid du Colombier 5, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 12, 13
377dd7cddfSDavid du Colombier };
387dd7cddfSDavid du Colombier
397dd7cddfSDavid du Colombier static ushort offbase[16] =
407dd7cddfSDavid du Colombier {
417dd7cddfSDavid du Colombier 0, 0x20,
427dd7cddfSDavid du Colombier 0x40, 0x60,
437dd7cddfSDavid du Colombier 0x80, 0xc0,
447dd7cddfSDavid du Colombier 0x100, 0x180,
457dd7cddfSDavid du Colombier 0x200, 0x300,
467dd7cddfSDavid du Colombier 0x400, 0x600,
477dd7cddfSDavid du Colombier 0x800, 0xc00,
487dd7cddfSDavid du Colombier 0x1000,
497dd7cddfSDavid du Colombier 0x2000
507dd7cddfSDavid du Colombier };
517dd7cddfSDavid du Colombier
527dd7cddfSDavid du Colombier void
unthwackinit(Unthwack * ut)537dd7cddfSDavid du Colombier unthwackinit(Unthwack *ut)
547dd7cddfSDavid du Colombier {
557dd7cddfSDavid du Colombier int i;
567dd7cddfSDavid du Colombier
577dd7cddfSDavid du Colombier memset(ut, 0, sizeof *ut);
587dd7cddfSDavid du Colombier for(i = 0; i < DWinBlocks; i++)
597dd7cddfSDavid du Colombier ut->blocks[i].data = ut->data[i];
607dd7cddfSDavid du Colombier }
617dd7cddfSDavid du Colombier
6280ee5cbfSDavid du Colombier ulong
unthwackstate(Unthwack * ut,uchar * mask)6380ee5cbfSDavid du Colombier unthwackstate(Unthwack *ut, uchar *mask)
647dd7cddfSDavid du Colombier {
6580ee5cbfSDavid du Colombier ulong bseq, seq;
6680ee5cbfSDavid du Colombier int slot, m;
677dd7cddfSDavid du Colombier
6880ee5cbfSDavid du Colombier seq = ~0UL;
6980ee5cbfSDavid du Colombier m = 0;
7080ee5cbfSDavid du Colombier slot = ut->slot;
7180ee5cbfSDavid du Colombier for(;;){
7280ee5cbfSDavid du Colombier slot--;
7380ee5cbfSDavid du Colombier if(slot < 0)
7480ee5cbfSDavid du Colombier slot += DWinBlocks;
7580ee5cbfSDavid du Colombier if(slot == ut->slot)
7680ee5cbfSDavid du Colombier break;
7780ee5cbfSDavid du Colombier if(ut->blocks[slot].maxoff == 0)
7880ee5cbfSDavid du Colombier continue;
7980ee5cbfSDavid du Colombier bseq = ut->blocks[slot].seq;
8080ee5cbfSDavid du Colombier if(seq == ~0UL)
8180ee5cbfSDavid du Colombier seq = bseq;
8280ee5cbfSDavid du Colombier else if(seq - bseq > MaxSeqMask)
8380ee5cbfSDavid du Colombier break;
8480ee5cbfSDavid du Colombier else
8580ee5cbfSDavid du Colombier m |= 1 << (seq - bseq - 1);
8680ee5cbfSDavid du Colombier }
8780ee5cbfSDavid du Colombier *mask = m;
8880ee5cbfSDavid du Colombier return seq;
8980ee5cbfSDavid du Colombier }
907dd7cddfSDavid du Colombier
917dd7cddfSDavid du Colombier /*
927dd7cddfSDavid du Colombier * insert this block in it's correct sequence number order.
937dd7cddfSDavid du Colombier * replace the oldest block, which is always pointed to by ut->slot.
947dd7cddfSDavid du Colombier * the encoder doesn't use a history at wraparound,
957dd7cddfSDavid du Colombier * so don't worry about that case.
967dd7cddfSDavid du Colombier */
9780ee5cbfSDavid du Colombier static int
unthwackinsert(Unthwack * ut,int len,ulong seq)9880ee5cbfSDavid du Colombier unthwackinsert(Unthwack *ut, int len, ulong seq)
9980ee5cbfSDavid du Colombier {
10080ee5cbfSDavid du Colombier uchar *d;
10180ee5cbfSDavid du Colombier int slot, tslot;
10280ee5cbfSDavid du Colombier
1037dd7cddfSDavid du Colombier tslot = ut->slot;
1047dd7cddfSDavid du Colombier for(;;){
1057dd7cddfSDavid du Colombier slot = tslot - 1;
1067dd7cddfSDavid du Colombier if(slot < 0)
1077dd7cddfSDavid du Colombier slot += DWinBlocks;
10880ee5cbfSDavid du Colombier if(ut->blocks[slot].seq <= seq || ut->blocks[slot].maxoff == 0)
1097dd7cddfSDavid du Colombier break;
1107dd7cddfSDavid du Colombier d = ut->blocks[tslot].data;
1117dd7cddfSDavid du Colombier ut->blocks[tslot] = ut->blocks[slot];
1127dd7cddfSDavid du Colombier ut->blocks[slot].data = d;
1137dd7cddfSDavid du Colombier tslot = slot;
1147dd7cddfSDavid du Colombier }
1157dd7cddfSDavid du Colombier ut->blocks[tslot].seq = seq;
11680ee5cbfSDavid du Colombier ut->blocks[tslot].maxoff = len;
11780ee5cbfSDavid du Colombier
11880ee5cbfSDavid du Colombier ut->slot++;
11980ee5cbfSDavid du Colombier if(ut->slot >= DWinBlocks)
12080ee5cbfSDavid du Colombier ut->slot = 0;
12180ee5cbfSDavid du Colombier
12280ee5cbfSDavid du Colombier ut->blocks[ut->slot].seq = ~0UL;
12380ee5cbfSDavid du Colombier ut->blocks[ut->slot].maxoff = 0;
12480ee5cbfSDavid du Colombier
12580ee5cbfSDavid du Colombier return tslot;
12680ee5cbfSDavid du Colombier }
12780ee5cbfSDavid du Colombier
12880ee5cbfSDavid du Colombier int
unthwack(Unthwack * ut,uchar * dst,int ndst,uchar * src,int nsrc,ulong seq)12980ee5cbfSDavid du Colombier unthwack(Unthwack *ut, uchar *dst, int ndst, uchar *src, int nsrc, ulong seq)
13080ee5cbfSDavid du Colombier {
13180ee5cbfSDavid du Colombier UnthwBlock blocks[CompBlocks], *b, *eblocks;
13280ee5cbfSDavid du Colombier uchar *s, *d, *dmax, *smax, lit;
13380ee5cbfSDavid du Colombier ulong cmask, cseq, bseq, utbits;
13480ee5cbfSDavid du Colombier int i, off, len, bits, slot, use, code, utnbits, overbits, lithist;
13580ee5cbfSDavid du Colombier
13680ee5cbfSDavid du Colombier if(nsrc < 4 || nsrc > ThwMaxBlock)
13780ee5cbfSDavid du Colombier return -1;
13880ee5cbfSDavid du Colombier
13980ee5cbfSDavid du Colombier slot = ut->slot;
14080ee5cbfSDavid du Colombier b = blocks;
14180ee5cbfSDavid du Colombier *b = ut->blocks[slot];
1427dd7cddfSDavid du Colombier d = b->data;
1437dd7cddfSDavid du Colombier dmax = d + ndst;
1447dd7cddfSDavid du Colombier
1457dd7cddfSDavid du Colombier /*
1467dd7cddfSDavid du Colombier * set up the history blocks
1477dd7cddfSDavid du Colombier */
1487dd7cddfSDavid du Colombier cseq = seq - src[0];
1497dd7cddfSDavid du Colombier cmask = src[1];
1507dd7cddfSDavid du Colombier b++;
1517dd7cddfSDavid du Colombier while(cseq != seq && b < blocks + CompBlocks){
1527dd7cddfSDavid du Colombier slot--;
1537dd7cddfSDavid du Colombier if(slot < 0)
1547dd7cddfSDavid du Colombier slot += DWinBlocks;
1557dd7cddfSDavid du Colombier if(slot == ut->slot)
1567dd7cddfSDavid du Colombier break;
1577dd7cddfSDavid du Colombier bseq = ut->blocks[slot].seq;
1587dd7cddfSDavid du Colombier if(bseq == cseq){
1597dd7cddfSDavid du Colombier *b = ut->blocks[slot];
1607dd7cddfSDavid du Colombier b++;
1617dd7cddfSDavid du Colombier if(cmask == 0){
1627dd7cddfSDavid du Colombier cseq = seq;
1637dd7cddfSDavid du Colombier break;
1647dd7cddfSDavid du Colombier }
1657dd7cddfSDavid du Colombier do{
1667dd7cddfSDavid du Colombier bits = cmask & 1;
1677dd7cddfSDavid du Colombier cseq--;
1687dd7cddfSDavid du Colombier cmask >>= 1;
1697dd7cddfSDavid du Colombier }while(!bits);
1707dd7cddfSDavid du Colombier }
1717dd7cddfSDavid du Colombier }
1727dd7cddfSDavid du Colombier eblocks = b;
1737dd7cddfSDavid du Colombier if(cseq != seq){
174*d9814433SDavid du Colombier print("unthwack: blocks dropped: seq=%ld cseq=%ld %d cmask=%#lx %#x\n",
175*d9814433SDavid du Colombier seq, cseq, src[0], cmask, src[1]);
17680ee5cbfSDavid du Colombier return -2;
1777dd7cddfSDavid du Colombier }
1787dd7cddfSDavid du Colombier
1797dd7cddfSDavid du Colombier smax = src + nsrc;
1807dd7cddfSDavid du Colombier src += 2;
1817dd7cddfSDavid du Colombier utnbits = 0;
1827dd7cddfSDavid du Colombier utbits = 0;
1837dd7cddfSDavid du Colombier overbits = 0;
1847dd7cddfSDavid du Colombier lithist = ~0;
1857dd7cddfSDavid du Colombier while(src < smax || utnbits - overbits >= MinDecode){
1867dd7cddfSDavid du Colombier while(utnbits <= 24){
1877dd7cddfSDavid du Colombier utbits <<= 8;
1887dd7cddfSDavid du Colombier if(src < smax)
1897dd7cddfSDavid du Colombier utbits |= *src++;
1907dd7cddfSDavid du Colombier else
1917dd7cddfSDavid du Colombier overbits += 8;
1927dd7cddfSDavid du Colombier utnbits += 8;
1937dd7cddfSDavid du Colombier }
1947dd7cddfSDavid du Colombier
1957dd7cddfSDavid du Colombier /*
1967dd7cddfSDavid du Colombier * literal
1977dd7cddfSDavid du Colombier */
1987dd7cddfSDavid du Colombier len = lenval[(utbits >> (utnbits - 5)) & 0x1f];
1997dd7cddfSDavid du Colombier if(len == 0){
2007dd7cddfSDavid du Colombier if(lithist & 0xf){
2017dd7cddfSDavid du Colombier utnbits -= 9;
2027dd7cddfSDavid du Colombier lit = (utbits >> utnbits) & 0xff;
2037dd7cddfSDavid du Colombier lit &= 255;
2047dd7cddfSDavid du Colombier }else{
2057dd7cddfSDavid du Colombier utnbits -= 8;
2067dd7cddfSDavid du Colombier lit = (utbits >> utnbits) & 0x7f;
2077dd7cddfSDavid du Colombier if(lit < 32){
2087dd7cddfSDavid du Colombier if(lit < 24){
2097dd7cddfSDavid du Colombier utnbits -= 2;
2107dd7cddfSDavid du Colombier lit = (lit << 2) | ((utbits >> utnbits) & 3);
2117dd7cddfSDavid du Colombier }else{
2127dd7cddfSDavid du Colombier utnbits -= 3;
2137dd7cddfSDavid du Colombier lit = (lit << 3) | ((utbits >> utnbits) & 7);
2147dd7cddfSDavid du Colombier }
2157dd7cddfSDavid du Colombier lit = (lit - 64) & 0xff;
2167dd7cddfSDavid du Colombier }
2177dd7cddfSDavid du Colombier }
21880ee5cbfSDavid du Colombier if(d >= dmax)
21980ee5cbfSDavid du Colombier return -1;
2207dd7cddfSDavid du Colombier *d++ = lit;
22159cc4ca5SDavid du Colombier lithist = (lithist << 1) | (lit < 32) | (lit > 127);
2227dd7cddfSDavid du Colombier blocks->maxoff++;
2237dd7cddfSDavid du Colombier continue;
2247dd7cddfSDavid du Colombier }
2257dd7cddfSDavid du Colombier
2267dd7cddfSDavid du Colombier /*
2277dd7cddfSDavid du Colombier * length
2287dd7cddfSDavid du Colombier */
2297dd7cddfSDavid du Colombier if(len < 255)
2307dd7cddfSDavid du Colombier utnbits -= lenbits[len];
2317dd7cddfSDavid du Colombier else{
2327dd7cddfSDavid du Colombier utnbits -= DBigLenBits;
2337dd7cddfSDavid du Colombier code = ((utbits >> utnbits) & ((1 << DBigLenBits) - 1)) - DBigLenCode;
2347dd7cddfSDavid du Colombier len = DMaxFastLen;
2357dd7cddfSDavid du Colombier use = DBigLenBase;
2367dd7cddfSDavid du Colombier bits = (DBigLenBits & 1) ^ 1;
2377dd7cddfSDavid du Colombier while(code >= use){
2387dd7cddfSDavid du Colombier len += use;
2397dd7cddfSDavid du Colombier code -= use;
2407dd7cddfSDavid du Colombier code <<= 1;
2417dd7cddfSDavid du Colombier utnbits--;
24259cc4ca5SDavid du Colombier if(utnbits < 0)
24359cc4ca5SDavid du Colombier return -1;
2447dd7cddfSDavid du Colombier code |= (utbits >> utnbits) & 1;
2457dd7cddfSDavid du Colombier use <<= bits;
2467dd7cddfSDavid du Colombier bits ^= 1;
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier len += code;
2497dd7cddfSDavid du Colombier
2507dd7cddfSDavid du Colombier while(utnbits <= 24){
2517dd7cddfSDavid du Colombier utbits <<= 8;
2527dd7cddfSDavid du Colombier if(src < smax)
2537dd7cddfSDavid du Colombier utbits |= *src++;
2547dd7cddfSDavid du Colombier else
2557dd7cddfSDavid du Colombier overbits += 8;
2567dd7cddfSDavid du Colombier utnbits += 8;
2577dd7cddfSDavid du Colombier }
2587dd7cddfSDavid du Colombier }
2597dd7cddfSDavid du Colombier
2607dd7cddfSDavid du Colombier /*
2617dd7cddfSDavid du Colombier * offset
2627dd7cddfSDavid du Colombier */
2637dd7cddfSDavid du Colombier utnbits -= 4;
2647dd7cddfSDavid du Colombier bits = (utbits >> utnbits) & 0xf;
2657dd7cddfSDavid du Colombier off = offbase[bits];
2667dd7cddfSDavid du Colombier bits = offbits[bits];
2677dd7cddfSDavid du Colombier
2687dd7cddfSDavid du Colombier utnbits -= bits;
2697dd7cddfSDavid du Colombier off |= (utbits >> utnbits) & ((1 << bits) - 1);
2707dd7cddfSDavid du Colombier off++;
2717dd7cddfSDavid du Colombier
2727dd7cddfSDavid du Colombier b = blocks;
2737dd7cddfSDavid du Colombier while(off > b->maxoff){
2747dd7cddfSDavid du Colombier off -= b->maxoff;
2757dd7cddfSDavid du Colombier b++;
2767dd7cddfSDavid du Colombier if(b >= eblocks)
2777dd7cddfSDavid du Colombier return -1;
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier if(d + len > dmax
2807dd7cddfSDavid du Colombier || b != blocks && len > off)
2817dd7cddfSDavid du Colombier return -1;
2827dd7cddfSDavid du Colombier s = b->data + b->maxoff - off;
2837dd7cddfSDavid du Colombier blocks->maxoff += len;
2847dd7cddfSDavid du Colombier
2857dd7cddfSDavid du Colombier for(i = 0; i < len; i++)
2867dd7cddfSDavid du Colombier d[i] = s[i];
2877dd7cddfSDavid du Colombier d += len;
2887dd7cddfSDavid du Colombier }
2897dd7cddfSDavid du Colombier if(utnbits < overbits)
2907dd7cddfSDavid du Colombier return -1;
2917dd7cddfSDavid du Colombier
2927dd7cddfSDavid du Colombier len = d - blocks->data;
2937dd7cddfSDavid du Colombier memmove(dst, blocks->data, len);
2947dd7cddfSDavid du Colombier
29580ee5cbfSDavid du Colombier unthwackinsert(ut, len, seq);
2967dd7cddfSDavid du Colombier
2977dd7cddfSDavid du Colombier return len;
2987dd7cddfSDavid du Colombier }
299