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