8 typedef struct Huff Huff;
13 BigLenCode = 0x1f4, /* minimum code for large lenth encoding */
15 BigLenBase = 4 /* starting items to encode for big lens */
35 short bits; /* length of the code */
36 ulong encode; /* the code */
39 static Huff lentab[MaxFastLen] =
43 {5, 0x1c}, /* 11100 */
44 {5, 0x1d}, /* 11101 */
45 {6, 0x3c}, /* 111100 */
46 {7, 0x7a}, /* 1111010 */
47 {7, 0x7b}, /* 1111011 */
48 {8, 0xf8}, /* 11111000 */
49 {8, 0xf9}, /* 11111001 */
53 thwackinit(Thwack *tw)
59 memset(tw->hash, 0, sizeof(tw->hash));
60 memset(tw->blocks, 0, sizeof(tw->blocks));
61 for(i = 0; i < EWinBlocks; i++){
62 tw->blocks[i].hash = tw->hash[i];
63 if(tw->data[i] != nil){
68 qunlock(&tw->acklock);
72 thwackcleanup(Thwack *tw)
77 for(i = 0; i < EWinBlocks; i++){
78 if(tw->data[i] != nil){
83 qunlock(&tw->acklock);
87 * acknowledgement for block seq & nearby preds
90 thwackack(Thwack *tw, ulong seq, ulong mask)
102 if(tw->blocks[slot].seq != seq)
105 tw->blocks[slot].acked = 1;
115 qunlock(&tw->acklock);
119 * find a string in the dictionary
122 thwmatch(ThwBlock *b, ThwBlock *eblocks, uchar **ss, uchar *esrc, ulong h)
124 int then, toff, w, ok;
128 if(esrc < s + MinMatch)
132 for(; b < eblocks; b++){
133 then = b->hash[(h ^ b->seq) & HashMask];
135 w = (ushort)(then - b->begin);
142 * don't need to check for the end because
143 * 1) s too close check above
144 * 2) entries too close not added to hash tables
147 if(s[0] != t[0] || s[1] != t[1] || s[2] != t[2])
154 for(s += 3; s < esrc; s++){
166 * knuth vol. 3 multiplicative hashing
167 * each byte x chosen according to rules
168 * 1/4 < x < 3/10, 1/3 x < < 3/7, 4/7 < x < 2/3, 7/10 < x < 3/4
169 * with reasonable spread between the bytes & their complements
171 * the 3 byte value appears to be as almost good as the 4 byte value,
172 * and might be faster on some machines
175 #define hashit(c) (((ulong)(c) * 0x6b43a9) >> (24 - HashLog))
177 #define hashit(c) ((((ulong)(c) & 0xffffff) * 0x6b43a9b5) >> (32 - HashLog))
180 * lz77 compression with single lookup in a hash table for each block
183 thwack(Thwack *tw, int mustadd, uchar *dst, int ndst, Block *bsrc, ulong seq, ulong stats[ThwStats])
185 ThwBlock *eblocks, *b, blocks[CompBlocks];
186 uchar *s, *ss, *sss, *esrc, *half, *twdst, *twdmax;
187 ulong cont, cseq, bseq, cmask, code, twbits;
188 int n, now, toff, lithist, h, len, slot, bits, use, twnbits, lits, matches, offbits, lenbits, nhist;
191 if(n > ThwMaxBlock || n < MinMatch)
198 * add source to the coding window
199 * there is always enough space
203 b = &tw->blocks[slot];
206 now = b->begin + b->maxoff;
207 if(tw->data[slot] != nil){
208 freeb(tw->data[slot]);
209 tw->data[slot] = nil;
218 * set up the history blocks
227 while(b < blocks + CompBlocks){
233 if(tw->data[slot] == nil || !tw->blocks[slot].acked)
235 bseq = tw->blocks[slot].seq;
237 if(seq - bseq >= MaxSeqStart)
240 }else if(cseq - bseq > MaxSeqMask)
243 cmask |= 1 << (cseq - bseq - 1);
244 *b = tw->blocks[slot];
248 qunlock(&tw->acklock);
250 *twdst++ = seq - cseq;
253 cont = (s[0] << 16) | (s[1] << 8) | s[2];
268 toff = thwmatch(blocks, eblocks, &sss, esrc, h);
272 for(; twnbits >= 8; twnbits -= 8){
274 *twdst++ = twbits >> (twnbits - 8);
280 lithist = (lithist << 1) | (toff < 32) | (toff > 127);
282 twbits = (twbits << 9) | toff;
284 }else if(lithist & 1){
285 toff = (toff + 64) & 0xff;
287 twbits = (twbits << 10) | toff;
290 twbits = (twbits << 11) | toff;
294 twbits = (twbits << 8) | toff;
302 * check for compression progress, bail if none achieved
305 if(!mustadd && 4 * blocks->maxoff < 5 * lits)
310 if(s + MinMatch <= esrc){
311 blocks->hash[(h ^ blocks->seq) & HashMask] = now;
312 if(s + MinMatch < esrc)
313 cont = (cont << 8) | s[MinMatch];
320 blocks->maxoff += len;
327 if(len < MaxFastLen){
328 bits = lentab[len].bits;
329 twbits = (twbits << bits) | lentab[len].encode;
339 code = (code + use) << 1;
340 use <<= (bits & 1) ^ 1;
343 twbits = (twbits << bits) | (code + len);
347 for(; twnbits >= 8; twnbits -= 8){
349 *twdst++ = twbits >> (twnbits - 8);
359 for(bits = OffBase; toff >= (1 << bits); bits++)
361 if(bits < MaxOff+OffBase-1){
362 twbits = (twbits << 3) | (bits - OffBase);
368 twbits = (twbits << 4) | 0xe | (bits - (MaxOff+OffBase-1));
373 twbits = (twbits << bits) | toff & ((1 << bits) - 1);
376 if(s + MinMatch <= esrc){
378 blocks->hash[(h ^ blocks->seq) & HashMask] = now;
379 if(s + MinMatch < esrc)
380 cont = (cont << 8) | s[MinMatch];
387 twbits <<= 8 - (twnbits & 7);
388 twnbits += 8 - (twnbits & 7);
390 for(; twnbits >= 8; twnbits -= 8){
392 *twdst++ = twbits >> (twnbits - 8);
397 if(twdst >= twdmax && !mustadd)
401 tw->data[tw->slot] = bsrc;
403 if(tw->slot >= EWinBlocks)
405 qunlock(&tw->acklock);
410 stats[StatBytes] += blocks->maxoff;
411 stats[StatLits] += lits;
412 stats[StatMatches] += matches;
413 stats[StatOffBits] += offbits;
414 stats[StatLenBits] += lenbits;
415 stats[StatDelay] = stats[StatDelay]*7/8 + dst[0];
416 stats[StatHist] = stats[StatHist]*7/8 + nhist;
417 stats[StatOutBytes] += twdst - dst;