xref: /plan9-contrib/sys/src/cmd/venti/srv/unwhack.c (revision 368c31ab13393dea083228fdd1c3445076f83a4b)
1*368c31abSDavid du Colombier #include "stdinc.h"
2*368c31abSDavid du Colombier #include "whack.h"
3*368c31abSDavid du Colombier 
4*368c31abSDavid du Colombier enum
5*368c31abSDavid du Colombier {
6*368c31abSDavid du Colombier 	DMaxFastLen	= 7,
7*368c31abSDavid du Colombier 	DBigLenCode	= 0x3c,		/* minimum code for large lenth encoding */
8*368c31abSDavid du Colombier 	DBigLenBits	= 6,
9*368c31abSDavid du Colombier 	DBigLenBase	= 1		/* starting items to encode for big lens */
10*368c31abSDavid du Colombier };
11*368c31abSDavid du Colombier 
12*368c31abSDavid du Colombier static uchar lenval[1 << (DBigLenBits - 1)] =
13*368c31abSDavid du Colombier {
14*368c31abSDavid du Colombier 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
15*368c31abSDavid du Colombier 	3, 3, 3, 3, 3, 3, 3, 3,
16*368c31abSDavid du Colombier 	4, 4, 4, 4,
17*368c31abSDavid du Colombier 	5,
18*368c31abSDavid du Colombier 	6,
19*368c31abSDavid du Colombier 	255,
20*368c31abSDavid du Colombier 	255
21*368c31abSDavid du Colombier };
22*368c31abSDavid du Colombier 
23*368c31abSDavid du Colombier static uchar lenbits[] =
24*368c31abSDavid du Colombier {
25*368c31abSDavid du Colombier 	0, 0, 0,
26*368c31abSDavid du Colombier 	2, 3, 5, 5,
27*368c31abSDavid du Colombier };
28*368c31abSDavid du Colombier 
29*368c31abSDavid du Colombier static uchar offbits[16] =
30*368c31abSDavid du Colombier {
31*368c31abSDavid du Colombier 	5, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 12, 13
32*368c31abSDavid du Colombier };
33*368c31abSDavid du Colombier 
34*368c31abSDavid du Colombier static ushort offbase[16] =
35*368c31abSDavid du Colombier {
36*368c31abSDavid du Colombier 	0, 0x20,
37*368c31abSDavid du Colombier 	0x40, 0x60,
38*368c31abSDavid du Colombier 	0x80, 0xc0,
39*368c31abSDavid du Colombier 	0x100, 0x180,
40*368c31abSDavid du Colombier 	0x200, 0x300,
41*368c31abSDavid du Colombier 	0x400, 0x600,
42*368c31abSDavid du Colombier 	0x800, 0xc00,
43*368c31abSDavid du Colombier 	0x1000,
44*368c31abSDavid du Colombier 	0x2000
45*368c31abSDavid du Colombier };
46*368c31abSDavid du Colombier 
47*368c31abSDavid du Colombier void
unwhackinit(Unwhack * uw)48*368c31abSDavid du Colombier unwhackinit(Unwhack *uw)
49*368c31abSDavid du Colombier {
50*368c31abSDavid du Colombier 	uw->err[0] = '\0';
51*368c31abSDavid du Colombier }
52*368c31abSDavid du Colombier 
53*368c31abSDavid du Colombier int
unwhack(Unwhack * uw,uchar * dst,int ndst,uchar * src,int nsrc)54*368c31abSDavid du Colombier unwhack(Unwhack *uw, uchar *dst, int ndst, uchar *src, int nsrc)
55*368c31abSDavid du Colombier {
56*368c31abSDavid du Colombier 	uchar *s, *d, *dmax, *smax, lit;
57*368c31abSDavid du Colombier 	ulong uwbits, lithist;
58*368c31abSDavid du Colombier 	int i, off, len, bits, use, code, uwnbits, overbits;
59*368c31abSDavid du Colombier 
60*368c31abSDavid du Colombier 	d = dst;
61*368c31abSDavid du Colombier 	dmax = d + ndst;
62*368c31abSDavid du Colombier 
63*368c31abSDavid du Colombier 	smax = src + nsrc;
64*368c31abSDavid du Colombier 	uwnbits = 0;
65*368c31abSDavid du Colombier 	uwbits = 0;
66*368c31abSDavid du Colombier 	overbits = 0;
67*368c31abSDavid du Colombier 	lithist = ~0;
68*368c31abSDavid du Colombier 	while(src < smax || uwnbits - overbits >= MinDecode){
69*368c31abSDavid du Colombier 		while(uwnbits <= 24){
70*368c31abSDavid du Colombier 			uwbits <<= 8;
71*368c31abSDavid du Colombier 			if(src < smax)
72*368c31abSDavid du Colombier 				uwbits |= *src++;
73*368c31abSDavid du Colombier 			else
74*368c31abSDavid du Colombier 				overbits += 8;
75*368c31abSDavid du Colombier 			uwnbits += 8;
76*368c31abSDavid du Colombier 		}
77*368c31abSDavid du Colombier 
78*368c31abSDavid du Colombier 		/*
79*368c31abSDavid du Colombier 		 * literal
80*368c31abSDavid du Colombier 		 */
81*368c31abSDavid du Colombier 		len = lenval[(uwbits >> (uwnbits - 5)) & 0x1f];
82*368c31abSDavid du Colombier 		if(len == 0){
83*368c31abSDavid du Colombier 			if(lithist & 0xf){
84*368c31abSDavid du Colombier 				uwnbits -= 9;
85*368c31abSDavid du Colombier 				lit = (uwbits >> uwnbits) & 0xff;
86*368c31abSDavid du Colombier 				lit &= 255;
87*368c31abSDavid du Colombier 			}else{
88*368c31abSDavid du Colombier 				uwnbits -= 8;
89*368c31abSDavid du Colombier 				lit = (uwbits >> uwnbits) & 0x7f;
90*368c31abSDavid du Colombier 				if(lit < 32){
91*368c31abSDavid du Colombier 					if(lit < 24){
92*368c31abSDavid du Colombier 						uwnbits -= 2;
93*368c31abSDavid du Colombier 						lit = (lit << 2) | ((uwbits >> uwnbits) & 3);
94*368c31abSDavid du Colombier 					}else{
95*368c31abSDavid du Colombier 						uwnbits -= 3;
96*368c31abSDavid du Colombier 						lit = (lit << 3) | ((uwbits >> uwnbits) & 7);
97*368c31abSDavid du Colombier 					}
98*368c31abSDavid du Colombier 					lit = (lit - 64) & 0xff;
99*368c31abSDavid du Colombier 				}
100*368c31abSDavid du Colombier 			}
101*368c31abSDavid du Colombier 			if(d >= dmax){
102*368c31abSDavid du Colombier 				snprint(uw->err, WhackErrLen, "too much output");
103*368c31abSDavid du Colombier 				return -1;
104*368c31abSDavid du Colombier 			}
105*368c31abSDavid du Colombier 			*d++ = lit;
106*368c31abSDavid du Colombier 			lithist = (lithist << 1) | (lit < 32) | (lit > 127);
107*368c31abSDavid du Colombier 			continue;
108*368c31abSDavid du Colombier 		}
109*368c31abSDavid du Colombier 
110*368c31abSDavid du Colombier 		/*
111*368c31abSDavid du Colombier 		 * length
112*368c31abSDavid du Colombier 		 */
113*368c31abSDavid du Colombier 		if(len < 255)
114*368c31abSDavid du Colombier 			uwnbits -= lenbits[len];
115*368c31abSDavid du Colombier 		else{
116*368c31abSDavid du Colombier 			uwnbits -= DBigLenBits;
117*368c31abSDavid du Colombier 			code = ((uwbits >> uwnbits) & ((1 << DBigLenBits) - 1)) - DBigLenCode;
118*368c31abSDavid du Colombier 			len = DMaxFastLen;
119*368c31abSDavid du Colombier 			use = DBigLenBase;
120*368c31abSDavid du Colombier 			bits = (DBigLenBits & 1) ^ 1;
121*368c31abSDavid du Colombier 			while(code >= use){
122*368c31abSDavid du Colombier 				len += use;
123*368c31abSDavid du Colombier 				code -= use;
124*368c31abSDavid du Colombier 				code <<= 1;
125*368c31abSDavid du Colombier 				uwnbits--;
126*368c31abSDavid du Colombier 				if(uwnbits < 0){
127*368c31abSDavid du Colombier 					snprint(uw->err, WhackErrLen, "len out of range");
128*368c31abSDavid du Colombier 					return -1;
129*368c31abSDavid du Colombier 				}
130*368c31abSDavid du Colombier 				code |= (uwbits >> uwnbits) & 1;
131*368c31abSDavid du Colombier 				use <<= bits;
132*368c31abSDavid du Colombier 				bits ^= 1;
133*368c31abSDavid du Colombier 			}
134*368c31abSDavid du Colombier 			len += code;
135*368c31abSDavid du Colombier 
136*368c31abSDavid du Colombier 			while(uwnbits <= 24){
137*368c31abSDavid du Colombier 				uwbits <<= 8;
138*368c31abSDavid du Colombier 				if(src < smax)
139*368c31abSDavid du Colombier 					uwbits |= *src++;
140*368c31abSDavid du Colombier 				else
141*368c31abSDavid du Colombier 					overbits += 8;
142*368c31abSDavid du Colombier 				uwnbits += 8;
143*368c31abSDavid du Colombier 			}
144*368c31abSDavid du Colombier 		}
145*368c31abSDavid du Colombier 
146*368c31abSDavid du Colombier 		/*
147*368c31abSDavid du Colombier 		 * offset
148*368c31abSDavid du Colombier 		 */
149*368c31abSDavid du Colombier 		uwnbits -= 4;
150*368c31abSDavid du Colombier 		bits = (uwbits >> uwnbits) & 0xf;
151*368c31abSDavid du Colombier 		off = offbase[bits];
152*368c31abSDavid du Colombier 		bits = offbits[bits];
153*368c31abSDavid du Colombier 
154*368c31abSDavid du Colombier 		uwnbits -= bits;
155*368c31abSDavid du Colombier 		off |= (uwbits >> uwnbits) & ((1 << bits) - 1);
156*368c31abSDavid du Colombier 		off++;
157*368c31abSDavid du Colombier 
158*368c31abSDavid du Colombier 		if(off > d - dst){
159*368c31abSDavid du Colombier 			snprint(uw->err, WhackErrLen, "offset out of range: off=%d d=%ld len=%d nbits=%d", off, d - dst, len, uwnbits);
160*368c31abSDavid du Colombier 			return -1;
161*368c31abSDavid du Colombier 		}
162*368c31abSDavid du Colombier 		if(d + len > dmax){
163*368c31abSDavid du Colombier 			snprint(uw->err, WhackErrLen, "len out of range");
164*368c31abSDavid du Colombier 			return -1;
165*368c31abSDavid du Colombier 		}
166*368c31abSDavid du Colombier 		s = d - off;
167*368c31abSDavid du Colombier 		for(i = 0; i < len; i++)
168*368c31abSDavid du Colombier 			d[i] = s[i];
169*368c31abSDavid du Colombier 		d += len;
170*368c31abSDavid du Colombier 	}
171*368c31abSDavid du Colombier 	if(uwnbits < overbits){
172*368c31abSDavid du Colombier 		snprint(uw->err, WhackErrLen, "compressed data overrun");
173*368c31abSDavid du Colombier 		return -1;
174*368c31abSDavid du Colombier 	}
175*368c31abSDavid du Colombier 
176*368c31abSDavid du Colombier 	len = d - dst;
177*368c31abSDavid du Colombier 
178*368c31abSDavid du Colombier 	return len;
179*368c31abSDavid du Colombier }
180