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