xref: /plan9/sys/src/9/port/unthwack.c (revision d98144334cb585e2a3eb025fdc0ef7bbf54fb5dd)
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