Blame


1 a0d146ed 2005-07-12 devnull #include "stdinc.h"
2 a0d146ed 2005-07-12 devnull #include "whack.h"
3 a0d146ed 2005-07-12 devnull
4 a0d146ed 2005-07-12 devnull typedef struct Huff Huff;
5 a0d146ed 2005-07-12 devnull int compressblocks = 1;
6 a0d146ed 2005-07-12 devnull
7 a0d146ed 2005-07-12 devnull enum
8 a0d146ed 2005-07-12 devnull {
9 a0d146ed 2005-07-12 devnull MaxFastLen = 9,
10 a0d146ed 2005-07-12 devnull BigLenCode = 0x1f4, /* minimum code for large lenth encoding */
11 a0d146ed 2005-07-12 devnull BigLenBits = 9,
12 a0d146ed 2005-07-12 devnull BigLenBase = 4, /* starting items to encode for big lens */
13 a0d146ed 2005-07-12 devnull
14 a0d146ed 2005-07-12 devnull MinOffBits = 6,
15 a0d146ed 2005-07-12 devnull MaxOffBits = MinOffBits + 8,
16 a0d146ed 2005-07-12 devnull
17 a0d146ed 2005-07-12 devnull MaxLen = 2051 /* max. length encodable in 24 bits */
18 a0d146ed 2005-07-12 devnull };
19 a0d146ed 2005-07-12 devnull
20 a0d146ed 2005-07-12 devnull enum
21 a0d146ed 2005-07-12 devnull {
22 a0d146ed 2005-07-12 devnull StatBytes,
23 a0d146ed 2005-07-12 devnull StatOutBytes,
24 a0d146ed 2005-07-12 devnull StatLits,
25 a0d146ed 2005-07-12 devnull StatMatches,
26 a0d146ed 2005-07-12 devnull StatLitBits,
27 a0d146ed 2005-07-12 devnull StatOffBits,
28 a0d146ed 2005-07-12 devnull StatLenBits,
29 a0d146ed 2005-07-12 devnull
30 a0d146ed 2005-07-12 devnull MaxStat
31 a0d146ed 2005-07-12 devnull };
32 a0d146ed 2005-07-12 devnull
33 a0d146ed 2005-07-12 devnull struct Huff
34 a0d146ed 2005-07-12 devnull {
35 a0d146ed 2005-07-12 devnull short bits; /* length of the code */
36 a0d146ed 2005-07-12 devnull ulong encode; /* the code */
37 a0d146ed 2005-07-12 devnull };
38 a0d146ed 2005-07-12 devnull
39 a0d146ed 2005-07-12 devnull static Huff lentab[MaxFastLen] =
40 a0d146ed 2005-07-12 devnull {
41 a0d146ed 2005-07-12 devnull {2, 0x2}, /* 10 */
42 a0d146ed 2005-07-12 devnull {3, 0x6}, /* 110 */
43 a0d146ed 2005-07-12 devnull {5, 0x1c}, /* 11100 */
44 a0d146ed 2005-07-12 devnull {5, 0x1d}, /* 11101 */
45 a0d146ed 2005-07-12 devnull {6, 0x3c}, /* 111100 */
46 a0d146ed 2005-07-12 devnull {7, 0x7a}, /* 1111010 */
47 a0d146ed 2005-07-12 devnull {7, 0x7b}, /* 1111011 */
48 a0d146ed 2005-07-12 devnull {8, 0xf8}, /* 11111000 */
49 a0d146ed 2005-07-12 devnull {8, 0xf9}, /* 11111001 */
50 a0d146ed 2005-07-12 devnull };
51 a0d146ed 2005-07-12 devnull
52 a0d146ed 2005-07-12 devnull static int thwmaxcheck;
53 a0d146ed 2005-07-12 devnull
54 a0d146ed 2005-07-12 devnull void
55 a0d146ed 2005-07-12 devnull whackinit(Whack *tw, int level)
56 a0d146ed 2005-07-12 devnull {
57 a0d146ed 2005-07-12 devnull thwmaxcheck = (1 << level);
58 a0d146ed 2005-07-12 devnull thwmaxcheck -= thwmaxcheck >> 2;
59 a0d146ed 2005-07-12 devnull if(thwmaxcheck < 2)
60 a0d146ed 2005-07-12 devnull thwmaxcheck = 2;
61 a0d146ed 2005-07-12 devnull else if(thwmaxcheck > 1024)
62 a0d146ed 2005-07-12 devnull thwmaxcheck = 1024;
63 a0d146ed 2005-07-12 devnull memset(tw, 0, sizeof *tw);
64 a0d146ed 2005-07-12 devnull tw->begin = 2 * WhackMaxOff;
65 a0d146ed 2005-07-12 devnull }
66 a0d146ed 2005-07-12 devnull
67 a0d146ed 2005-07-12 devnull /*
68 a0d146ed 2005-07-12 devnull * find a string in the dictionary
69 a0d146ed 2005-07-12 devnull */
70 a0d146ed 2005-07-12 devnull static int
71 a0d146ed 2005-07-12 devnull whackmatch(Whack *b, uchar **ss, uchar *esrc, ulong h, ulong now)
72 a0d146ed 2005-07-12 devnull {
73 a0d146ed 2005-07-12 devnull ushort then, off, last;
74 a0d146ed 2005-07-12 devnull int bestoff, bestlen, check;
75 a0d146ed 2005-07-12 devnull uchar *s, *t;
76 a0d146ed 2005-07-12 devnull
77 a0d146ed 2005-07-12 devnull s = *ss;
78 a0d146ed 2005-07-12 devnull if(esrc < s + MinMatch)
79 a0d146ed 2005-07-12 devnull return -1;
80 a0d146ed 2005-07-12 devnull if(s + MaxLen < esrc)
81 a0d146ed 2005-07-12 devnull esrc = s + MaxLen;
82 a0d146ed 2005-07-12 devnull
83 a0d146ed 2005-07-12 devnull bestoff = 0;
84 a0d146ed 2005-07-12 devnull bestlen = 0;
85 a0d146ed 2005-07-12 devnull check = thwmaxcheck;
86 a0d146ed 2005-07-12 devnull last = 0;
87 a0d146ed 2005-07-12 devnull for(then = b->hash[h]; check-- > 0; then = b->next[then & (WhackMaxOff - 1)]){
88 a0d146ed 2005-07-12 devnull off = now - then;
89 a0d146ed 2005-07-12 devnull if(off <= last || off > WhackMaxOff)
90 a0d146ed 2005-07-12 devnull break;
91 a0d146ed 2005-07-12 devnull
92 a0d146ed 2005-07-12 devnull /*
93 a0d146ed 2005-07-12 devnull * don't need to check for the end because
94 a0d146ed 2005-07-12 devnull * 1) s too close check above
95 a0d146ed 2005-07-12 devnull */
96 a0d146ed 2005-07-12 devnull t = s - off;
97 a0d146ed 2005-07-12 devnull if(s[0] == t[0] && s[1] == t[1] && s[2] == t[2]){
98 a0d146ed 2005-07-12 devnull if(!bestlen || esrc - s > bestlen && s[bestlen] == t[bestlen]){
99 a0d146ed 2005-07-12 devnull t += 3;
100 a0d146ed 2005-07-12 devnull for(s += 3; s < esrc; s++){
101 a0d146ed 2005-07-12 devnull if(*s != *t)
102 a0d146ed 2005-07-12 devnull break;
103 a0d146ed 2005-07-12 devnull t++;
104 a0d146ed 2005-07-12 devnull }
105 a0d146ed 2005-07-12 devnull if(s - *ss > bestlen){
106 a0d146ed 2005-07-12 devnull bestlen = s - *ss;
107 a0d146ed 2005-07-12 devnull bestoff = off;
108 a0d146ed 2005-07-12 devnull if(bestlen > thwmaxcheck)
109 a0d146ed 2005-07-12 devnull break;
110 a0d146ed 2005-07-12 devnull }
111 a0d146ed 2005-07-12 devnull }
112 a0d146ed 2005-07-12 devnull }
113 a0d146ed 2005-07-12 devnull s = *ss;
114 a0d146ed 2005-07-12 devnull last = off;
115 a0d146ed 2005-07-12 devnull }
116 a0d146ed 2005-07-12 devnull *ss += bestlen;
117 a0d146ed 2005-07-12 devnull return bestoff;
118 a0d146ed 2005-07-12 devnull }
119 a0d146ed 2005-07-12 devnull
120 a0d146ed 2005-07-12 devnull /*
121 a0d146ed 2005-07-12 devnull * knuth vol. 3 multiplicative hashing
122 a0d146ed 2005-07-12 devnull * each byte x chosen according to rules
123 a0d146ed 2005-07-12 devnull * 1/4 < x < 3/10, 1/3 x < < 3/7, 4/7 < x < 2/3, 7/10 < x < 3/4
124 a0d146ed 2005-07-12 devnull * with reasonable spread between the bytes & their complements
125 a0d146ed 2005-07-12 devnull *
126 a0d146ed 2005-07-12 devnull * the 3 byte value appears to be as almost good as the 4 byte value,
127 a0d146ed 2005-07-12 devnull * and might be faster on some machines
128 a0d146ed 2005-07-12 devnull */
129 a0d146ed 2005-07-12 devnull /*
130 a0d146ed 2005-07-12 devnull #define hashit(c) ((((ulong)(c) * 0x6b43a9) >> (24 - HashLog)) & HashMask)
131 a0d146ed 2005-07-12 devnull */
132 a0d146ed 2005-07-12 devnull #define hashit(c) (((((ulong)(c) & 0xffffff) * 0x6b43a9b5) >> (32 - HashLog)) & HashMask)
133 a0d146ed 2005-07-12 devnull
134 a0d146ed 2005-07-12 devnull /*
135 a0d146ed 2005-07-12 devnull * lz77 compression with single lookup in a hash table for each block
136 a0d146ed 2005-07-12 devnull */
137 a0d146ed 2005-07-12 devnull int
138 a0d146ed 2005-07-12 devnull whack(Whack *w, uchar *dst, uchar *src, int n, ulong stats[WhackStats])
139 a0d146ed 2005-07-12 devnull {
140 a0d146ed 2005-07-12 devnull uchar *s, *ss, *sss, *esrc, *half, *wdst, *wdmax;
141 a0d146ed 2005-07-12 devnull ulong cont, code, wbits;
142 a0d146ed 2005-07-12 devnull ushort now;
143 a0d146ed 2005-07-12 devnull int toff, lithist, h, len, bits, use, wnbits, lits, matches, offbits, lenbits;
144 a0d146ed 2005-07-12 devnull
145 a0d146ed 2005-07-12 devnull if(!compressblocks || n < MinMatch)
146 a0d146ed 2005-07-12 devnull return -1;
147 a0d146ed 2005-07-12 devnull
148 a0d146ed 2005-07-12 devnull wdst = dst;
149 a0d146ed 2005-07-12 devnull wdmax = dst + n;
150 a0d146ed 2005-07-12 devnull
151 a0d146ed 2005-07-12 devnull now = w->begin;
152 a0d146ed 2005-07-12 devnull s = src;
153 a0d146ed 2005-07-12 devnull w->data = s;
154 a0d146ed 2005-07-12 devnull
155 a0d146ed 2005-07-12 devnull cont = (s[0] << 16) | (s[1] << 8) | s[2];
156 a0d146ed 2005-07-12 devnull
157 a0d146ed 2005-07-12 devnull esrc = s + n;
158 a0d146ed 2005-07-12 devnull half = s + (n >> 1);
159 a0d146ed 2005-07-12 devnull wnbits = 0;
160 a0d146ed 2005-07-12 devnull wbits = 0;
161 a0d146ed 2005-07-12 devnull lits = 0;
162 a0d146ed 2005-07-12 devnull matches = 0;
163 a0d146ed 2005-07-12 devnull offbits = 0;
164 a0d146ed 2005-07-12 devnull lenbits = 0;
165 a0d146ed 2005-07-12 devnull lithist = ~0;
166 a0d146ed 2005-07-12 devnull while(s < esrc){
167 a0d146ed 2005-07-12 devnull h = hashit(cont);
168 a0d146ed 2005-07-12 devnull
169 a0d146ed 2005-07-12 devnull sss = s;
170 a0d146ed 2005-07-12 devnull toff = whackmatch(w, &sss, esrc, h, now);
171 a0d146ed 2005-07-12 devnull ss = sss;
172 a0d146ed 2005-07-12 devnull
173 a0d146ed 2005-07-12 devnull len = ss - s;
174 a0d146ed 2005-07-12 devnull for(; wnbits >= 8; wnbits -= 8){
175 a0d146ed 2005-07-12 devnull if(wdst >= wdmax){
176 a0d146ed 2005-07-12 devnull w->begin = now;
177 a0d146ed 2005-07-12 devnull return -1;
178 a0d146ed 2005-07-12 devnull }
179 a0d146ed 2005-07-12 devnull *wdst++ = wbits >> (wnbits - 8);
180 a0d146ed 2005-07-12 devnull }
181 a0d146ed 2005-07-12 devnull if(len < MinMatch){
182 a0d146ed 2005-07-12 devnull toff = *s;
183 a0d146ed 2005-07-12 devnull lithist = (lithist << 1) | toff < 32 | toff > 127;
184 a0d146ed 2005-07-12 devnull if(lithist & 0x1e){
185 a0d146ed 2005-07-12 devnull wbits = (wbits << 9) | toff;
186 a0d146ed 2005-07-12 devnull wnbits += 9;
187 a0d146ed 2005-07-12 devnull }else if(lithist & 1){
188 a0d146ed 2005-07-12 devnull toff = (toff + 64) & 0xff;
189 a0d146ed 2005-07-12 devnull if(toff < 96){
190 a0d146ed 2005-07-12 devnull wbits = (wbits << 10) | toff;
191 a0d146ed 2005-07-12 devnull wnbits += 10;
192 a0d146ed 2005-07-12 devnull }else{
193 a0d146ed 2005-07-12 devnull wbits = (wbits << 11) | toff;
194 a0d146ed 2005-07-12 devnull wnbits += 11;
195 a0d146ed 2005-07-12 devnull }
196 a0d146ed 2005-07-12 devnull }else{
197 a0d146ed 2005-07-12 devnull wbits = (wbits << 8) | toff;
198 a0d146ed 2005-07-12 devnull wnbits += 8;
199 a0d146ed 2005-07-12 devnull }
200 a0d146ed 2005-07-12 devnull lits++;
201 a0d146ed 2005-07-12 devnull
202 a0d146ed 2005-07-12 devnull /*
203 a0d146ed 2005-07-12 devnull * speed hack
204 a0d146ed 2005-07-12 devnull * check for compression progress, bail if none achieved
205 a0d146ed 2005-07-12 devnull */
206 a0d146ed 2005-07-12 devnull if(s > half){
207 a0d146ed 2005-07-12 devnull if(4 * (s - src) < 5 * lits){
208 a0d146ed 2005-07-12 devnull w->begin = now;
209 a0d146ed 2005-07-12 devnull return -1;
210 a0d146ed 2005-07-12 devnull }
211 a0d146ed 2005-07-12 devnull half = esrc;
212 a0d146ed 2005-07-12 devnull }
213 a0d146ed 2005-07-12 devnull
214 a0d146ed 2005-07-12 devnull if(s + MinMatch <= esrc){
215 a0d146ed 2005-07-12 devnull w->next[now & (WhackMaxOff - 1)] = w->hash[h];
216 a0d146ed 2005-07-12 devnull w->hash[h] = now;
217 a0d146ed 2005-07-12 devnull if(s + MinMatch < esrc)
218 a0d146ed 2005-07-12 devnull cont = (cont << 8) | s[MinMatch];
219 a0d146ed 2005-07-12 devnull }
220 a0d146ed 2005-07-12 devnull now++;
221 a0d146ed 2005-07-12 devnull s++;
222 a0d146ed 2005-07-12 devnull continue;
223 a0d146ed 2005-07-12 devnull }
224 a0d146ed 2005-07-12 devnull
225 a0d146ed 2005-07-12 devnull matches++;
226 a0d146ed 2005-07-12 devnull
227 a0d146ed 2005-07-12 devnull /*
228 a0d146ed 2005-07-12 devnull * length of match
229 a0d146ed 2005-07-12 devnull */
230 a0d146ed 2005-07-12 devnull if(len > MaxLen){
231 a0d146ed 2005-07-12 devnull len = MaxLen;
232 a0d146ed 2005-07-12 devnull ss = s + len;
233 a0d146ed 2005-07-12 devnull }
234 a0d146ed 2005-07-12 devnull len -= MinMatch;
235 a0d146ed 2005-07-12 devnull if(len < MaxFastLen){
236 a0d146ed 2005-07-12 devnull bits = lentab[len].bits;
237 a0d146ed 2005-07-12 devnull wbits = (wbits << bits) | lentab[len].encode;
238 a0d146ed 2005-07-12 devnull wnbits += bits;
239 a0d146ed 2005-07-12 devnull lenbits += bits;
240 a0d146ed 2005-07-12 devnull }else{
241 a0d146ed 2005-07-12 devnull code = BigLenCode;
242 a0d146ed 2005-07-12 devnull bits = BigLenBits;
243 a0d146ed 2005-07-12 devnull use = BigLenBase;
244 a0d146ed 2005-07-12 devnull len -= MaxFastLen;
245 a0d146ed 2005-07-12 devnull while(len >= use){
246 a0d146ed 2005-07-12 devnull len -= use;
247 a0d146ed 2005-07-12 devnull code = (code + use) << 1;
248 a0d146ed 2005-07-12 devnull use <<= (bits & 1) ^ 1;
249 a0d146ed 2005-07-12 devnull bits++;
250 a0d146ed 2005-07-12 devnull }
251 a0d146ed 2005-07-12 devnull
252 a0d146ed 2005-07-12 devnull wbits = (wbits << bits) | (code + len);
253 a0d146ed 2005-07-12 devnull wnbits += bits;
254 a0d146ed 2005-07-12 devnull lenbits += bits;
255 a0d146ed 2005-07-12 devnull
256 a0d146ed 2005-07-12 devnull for(; wnbits >= 8; wnbits -= 8){
257 a0d146ed 2005-07-12 devnull if(wdst >= wdmax){
258 a0d146ed 2005-07-12 devnull w->begin = now;
259 a0d146ed 2005-07-12 devnull return -1;
260 a0d146ed 2005-07-12 devnull }
261 a0d146ed 2005-07-12 devnull *wdst++ = wbits >> (wnbits - 8);
262 a0d146ed 2005-07-12 devnull }
263 a0d146ed 2005-07-12 devnull }
264 a0d146ed 2005-07-12 devnull
265 a0d146ed 2005-07-12 devnull /*
266 a0d146ed 2005-07-12 devnull * offset in history
267 a0d146ed 2005-07-12 devnull */
268 a0d146ed 2005-07-12 devnull toff--;
269 a0d146ed 2005-07-12 devnull for(bits = MinOffBits; toff >= (1 << bits); bits++)
270 a0d146ed 2005-07-12 devnull ;
271 a0d146ed 2005-07-12 devnull if(bits < MaxOffBits-1){
272 a0d146ed 2005-07-12 devnull wbits = (wbits << 3) | (bits - MinOffBits);
273 a0d146ed 2005-07-12 devnull if(bits != MinOffBits)
274 a0d146ed 2005-07-12 devnull bits--;
275 a0d146ed 2005-07-12 devnull wnbits += bits + 3;
276 a0d146ed 2005-07-12 devnull offbits += bits + 3;
277 a0d146ed 2005-07-12 devnull }else{
278 a0d146ed 2005-07-12 devnull wbits = (wbits << 4) | 0xe | (bits - (MaxOffBits-1));
279 a0d146ed 2005-07-12 devnull bits--;
280 a0d146ed 2005-07-12 devnull wnbits += bits + 4;
281 a0d146ed 2005-07-12 devnull offbits += bits + 4;
282 a0d146ed 2005-07-12 devnull }
283 a0d146ed 2005-07-12 devnull wbits = (wbits << bits) | toff & ((1 << bits) - 1);
284 a0d146ed 2005-07-12 devnull
285 a0d146ed 2005-07-12 devnull for(; s != ss; s++){
286 a0d146ed 2005-07-12 devnull if(s + MinMatch <= esrc){
287 a0d146ed 2005-07-12 devnull h = hashit(cont);
288 a0d146ed 2005-07-12 devnull w->next[now & (WhackMaxOff - 1)] = w->hash[h];
289 a0d146ed 2005-07-12 devnull w->hash[h] = now;
290 a0d146ed 2005-07-12 devnull if(s + MinMatch < esrc)
291 a0d146ed 2005-07-12 devnull cont = (cont << 8) | s[MinMatch];
292 a0d146ed 2005-07-12 devnull }
293 a0d146ed 2005-07-12 devnull now++;
294 a0d146ed 2005-07-12 devnull }
295 a0d146ed 2005-07-12 devnull }
296 a0d146ed 2005-07-12 devnull
297 a0d146ed 2005-07-12 devnull w->begin = now;
298 a0d146ed 2005-07-12 devnull
299 a0d146ed 2005-07-12 devnull stats[StatBytes] += esrc - src;
300 a0d146ed 2005-07-12 devnull stats[StatLits] += lits;
301 a0d146ed 2005-07-12 devnull stats[StatMatches] += matches;
302 a0d146ed 2005-07-12 devnull stats[StatLitBits] += (wdst - (dst + 2)) * 8 + wnbits - offbits - lenbits;
303 a0d146ed 2005-07-12 devnull stats[StatOffBits] += offbits;
304 a0d146ed 2005-07-12 devnull stats[StatLenBits] += lenbits;
305 a0d146ed 2005-07-12 devnull
306 a0d146ed 2005-07-12 devnull if(wnbits & 7){
307 a0d146ed 2005-07-12 devnull wbits <<= 8 - (wnbits & 7);
308 a0d146ed 2005-07-12 devnull wnbits += 8 - (wnbits & 7);
309 a0d146ed 2005-07-12 devnull }
310 a0d146ed 2005-07-12 devnull for(; wnbits >= 8; wnbits -= 8){
311 a0d146ed 2005-07-12 devnull if(wdst >= wdmax)
312 a0d146ed 2005-07-12 devnull return -1;
313 a0d146ed 2005-07-12 devnull *wdst++ = wbits >> (wnbits - 8);
314 a0d146ed 2005-07-12 devnull }
315 a0d146ed 2005-07-12 devnull
316 a0d146ed 2005-07-12 devnull stats[StatOutBytes] += wdst - dst;
317 a0d146ed 2005-07-12 devnull
318 a0d146ed 2005-07-12 devnull return wdst - dst;
319 a0d146ed 2005-07-12 devnull }
320 a0d146ed 2005-07-12 devnull
321 a0d146ed 2005-07-12 devnull int
322 a0d146ed 2005-07-12 devnull whackblock(uchar *dst, uchar *src, int ssize)
323 a0d146ed 2005-07-12 devnull {
324 a0d146ed 2005-07-12 devnull Whack w;
325 a0d146ed 2005-07-12 devnull ulong stats[MaxStat];
326 a0d146ed 2005-07-12 devnull int r;
327 a0d146ed 2005-07-12 devnull
328 a0d146ed 2005-07-12 devnull whackinit(&w, 6);
329 a0d146ed 2005-07-12 devnull r = whack(&w, dst, src, ssize, stats);
330 a0d146ed 2005-07-12 devnull return r;
331 a0d146ed 2005-07-12 devnull }