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