17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <ip.h>
4*9a747e4fSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include "ppp.h"
67dd7cddfSDavid du Colombier #include "thwack.h"
77dd7cddfSDavid du Colombier
87dd7cddfSDavid du Colombier typedef struct Huff Huff;
97dd7cddfSDavid du Colombier
107dd7cddfSDavid du Colombier enum
117dd7cddfSDavid du Colombier {
127dd7cddfSDavid du Colombier MaxFastLen = 9,
137dd7cddfSDavid du Colombier BigLenCode = 0x1f4, /* minimum code for large lenth encoding */
147dd7cddfSDavid du Colombier BigLenBits = 9,
157dd7cddfSDavid du Colombier BigLenBase = 4 /* starting items to encode for big lens */
167dd7cddfSDavid du Colombier };
177dd7cddfSDavid du Colombier
187dd7cddfSDavid du Colombier enum
197dd7cddfSDavid du Colombier {
207dd7cddfSDavid du Colombier StatBytes,
217dd7cddfSDavid du Colombier StatOutBytes,
227dd7cddfSDavid du Colombier StatLits,
237dd7cddfSDavid du Colombier StatMatches,
247dd7cddfSDavid du Colombier StatOffBits,
257dd7cddfSDavid du Colombier StatLenBits,
267dd7cddfSDavid du Colombier
277dd7cddfSDavid du Colombier StatDelay,
287dd7cddfSDavid du Colombier StatHist,
297dd7cddfSDavid du Colombier
307dd7cddfSDavid du Colombier MaxStat
317dd7cddfSDavid du Colombier };
327dd7cddfSDavid du Colombier
337dd7cddfSDavid du Colombier struct Huff
347dd7cddfSDavid du Colombier {
357dd7cddfSDavid du Colombier short bits; /* length of the code */
367dd7cddfSDavid du Colombier ulong encode; /* the code */
377dd7cddfSDavid du Colombier };
387dd7cddfSDavid du Colombier
397dd7cddfSDavid du Colombier static Huff lentab[MaxFastLen] =
407dd7cddfSDavid du Colombier {
417dd7cddfSDavid du Colombier {2, 0x2}, /* 10 */
427dd7cddfSDavid du Colombier {3, 0x6}, /* 110 */
437dd7cddfSDavid du Colombier {5, 0x1c}, /* 11100 */
447dd7cddfSDavid du Colombier {5, 0x1d}, /* 11101 */
457dd7cddfSDavid du Colombier {6, 0x3c}, /* 111100 */
467dd7cddfSDavid du Colombier {7, 0x7a}, /* 1111010 */
477dd7cddfSDavid du Colombier {7, 0x7b}, /* 1111011 */
487dd7cddfSDavid du Colombier {8, 0xf8}, /* 11111000 */
497dd7cddfSDavid du Colombier {8, 0xf9}, /* 11111001 */
507dd7cddfSDavid du Colombier };
517dd7cddfSDavid du Colombier
527dd7cddfSDavid du Colombier void
thwackinit(Thwack * tw)537dd7cddfSDavid du Colombier thwackinit(Thwack *tw)
547dd7cddfSDavid du Colombier {
557dd7cddfSDavid du Colombier int i;
567dd7cddfSDavid du Colombier
577dd7cddfSDavid du Colombier qlock(&tw->acklock);
587dd7cddfSDavid du Colombier tw->slot = 0;
597dd7cddfSDavid du Colombier memset(tw->hash, 0, sizeof(tw->hash));
607dd7cddfSDavid du Colombier memset(tw->blocks, 0, sizeof(tw->blocks));
617dd7cddfSDavid du Colombier for(i = 0; i < EWinBlocks; i++){
627dd7cddfSDavid du Colombier tw->blocks[i].hash = tw->hash[i];
637dd7cddfSDavid du Colombier if(tw->data[i] != nil){
647dd7cddfSDavid du Colombier freeb(tw->data[i]);
657dd7cddfSDavid du Colombier tw->data[i] = nil;
667dd7cddfSDavid du Colombier }
677dd7cddfSDavid du Colombier }
687dd7cddfSDavid du Colombier qunlock(&tw->acklock);
697dd7cddfSDavid du Colombier }
707dd7cddfSDavid du Colombier
717dd7cddfSDavid du Colombier void
thwackcleanup(Thwack * tw)727dd7cddfSDavid du Colombier thwackcleanup(Thwack *tw)
737dd7cddfSDavid du Colombier {
747dd7cddfSDavid du Colombier int i;
757dd7cddfSDavid du Colombier
767dd7cddfSDavid du Colombier qlock(&tw->acklock);
777dd7cddfSDavid du Colombier for(i = 0; i < EWinBlocks; i++){
787dd7cddfSDavid du Colombier if(tw->data[i] != nil){
797dd7cddfSDavid du Colombier freeb(tw->data[i]);
807dd7cddfSDavid du Colombier tw->data[i] = nil;
817dd7cddfSDavid du Colombier }
827dd7cddfSDavid du Colombier }
837dd7cddfSDavid du Colombier qunlock(&tw->acklock);
847dd7cddfSDavid du Colombier }
857dd7cddfSDavid du Colombier
867dd7cddfSDavid du Colombier /*
877dd7cddfSDavid du Colombier * acknowledgement for block seq & nearby preds
887dd7cddfSDavid du Colombier */
897dd7cddfSDavid du Colombier void
thwackack(Thwack * tw,ulong seq,ulong mask)907dd7cddfSDavid du Colombier thwackack(Thwack *tw, ulong seq, ulong mask)
917dd7cddfSDavid du Colombier {
927dd7cddfSDavid du Colombier int slot, b;
937dd7cddfSDavid du Colombier
947dd7cddfSDavid du Colombier qlock(&tw->acklock);
957dd7cddfSDavid du Colombier slot = tw->slot;
967dd7cddfSDavid du Colombier for(;;){
977dd7cddfSDavid du Colombier slot--;
987dd7cddfSDavid du Colombier if(slot < 0)
997dd7cddfSDavid du Colombier slot += EWinBlocks;
1007dd7cddfSDavid du Colombier if(slot == tw->slot)
1017dd7cddfSDavid du Colombier break;
1027dd7cddfSDavid du Colombier if(tw->blocks[slot].seq != seq)
1037dd7cddfSDavid du Colombier continue;
1047dd7cddfSDavid du Colombier
1057dd7cddfSDavid du Colombier tw->blocks[slot].acked = 1;
1067dd7cddfSDavid du Colombier
1077dd7cddfSDavid du Colombier if(mask == 0)
1087dd7cddfSDavid du Colombier break;
1097dd7cddfSDavid du Colombier do{
1107dd7cddfSDavid du Colombier b = mask & 1;
1117dd7cddfSDavid du Colombier seq--;
1127dd7cddfSDavid du Colombier mask >>= 1;
1137dd7cddfSDavid du Colombier }while(!b);
1147dd7cddfSDavid du Colombier }
1157dd7cddfSDavid du Colombier qunlock(&tw->acklock);
1167dd7cddfSDavid du Colombier }
1177dd7cddfSDavid du Colombier
1187dd7cddfSDavid du Colombier /*
1197dd7cddfSDavid du Colombier * find a string in the dictionary
1207dd7cddfSDavid du Colombier */
1217dd7cddfSDavid du Colombier static int
thwmatch(ThwBlock * b,ThwBlock * eblocks,uchar ** ss,uchar * esrc,ulong h)1227dd7cddfSDavid du Colombier thwmatch(ThwBlock *b, ThwBlock *eblocks, uchar **ss, uchar *esrc, ulong h)
1237dd7cddfSDavid du Colombier {
1247dd7cddfSDavid du Colombier int then, toff, w, ok;
1257dd7cddfSDavid du Colombier uchar *s, *t;
1267dd7cddfSDavid du Colombier
1277dd7cddfSDavid du Colombier s = *ss;
1287dd7cddfSDavid du Colombier if(esrc < s + MinMatch)
1297dd7cddfSDavid du Colombier return 0;
1307dd7cddfSDavid du Colombier
1317dd7cddfSDavid du Colombier toff = 0;
1327dd7cddfSDavid du Colombier for(; b < eblocks; b++){
1337dd7cddfSDavid du Colombier then = b->hash[(h ^ b->seq) & HashMask];
1347dd7cddfSDavid du Colombier toff += b->maxoff;
1357dd7cddfSDavid du Colombier w = (ushort)(then - b->begin);
1367dd7cddfSDavid du Colombier
1377dd7cddfSDavid du Colombier if(w >= b->maxoff)
1387dd7cddfSDavid du Colombier continue;
1397dd7cddfSDavid du Colombier
1407dd7cddfSDavid du Colombier
1417dd7cddfSDavid du Colombier /*
1427dd7cddfSDavid du Colombier * don't need to check for the end because
1437dd7cddfSDavid du Colombier * 1) s too close check above
1447dd7cddfSDavid du Colombier * 2) entries too close not added to hash tables
1457dd7cddfSDavid du Colombier */
1467dd7cddfSDavid du Colombier t = w + b->data;
1477dd7cddfSDavid du Colombier if(s[0] != t[0] || s[1] != t[1] || s[2] != t[2])
1487dd7cddfSDavid du Colombier continue;
1497dd7cddfSDavid du Colombier ok = b->edata - t;
1507dd7cddfSDavid du Colombier if(esrc - s > ok)
1517dd7cddfSDavid du Colombier esrc = s + ok;
1527dd7cddfSDavid du Colombier
1537dd7cddfSDavid du Colombier t += 3;
1547dd7cddfSDavid du Colombier for(s += 3; s < esrc; s++){
1557dd7cddfSDavid du Colombier if(*s != *t)
1567dd7cddfSDavid du Colombier break;
1577dd7cddfSDavid du Colombier t++;
1587dd7cddfSDavid du Colombier }
1597dd7cddfSDavid du Colombier *ss = s;
1607dd7cddfSDavid du Colombier return toff - w;
1617dd7cddfSDavid du Colombier }
1627dd7cddfSDavid du Colombier return 0;
1637dd7cddfSDavid du Colombier }
1647dd7cddfSDavid du Colombier
1657dd7cddfSDavid du Colombier /*
1667dd7cddfSDavid du Colombier * knuth vol. 3 multiplicative hashing
1677dd7cddfSDavid du Colombier * each byte x chosen according to rules
1687dd7cddfSDavid du Colombier * 1/4 < x < 3/10, 1/3 x < < 3/7, 4/7 < x < 2/3, 7/10 < x < 3/4
1697dd7cddfSDavid du Colombier * with reasonable spread between the bytes & their complements
1707dd7cddfSDavid du Colombier *
1717dd7cddfSDavid du Colombier * the 3 byte value appears to be as almost good as the 4 byte value,
1727dd7cddfSDavid du Colombier * and might be faster on some machines
1737dd7cddfSDavid du Colombier */
1747dd7cddfSDavid du Colombier /*
1757dd7cddfSDavid du Colombier #define hashit(c) (((ulong)(c) * 0x6b43a9) >> (24 - HashLog))
1767dd7cddfSDavid du Colombier */
1777dd7cddfSDavid du Colombier #define hashit(c) ((((ulong)(c) & 0xffffff) * 0x6b43a9b5) >> (32 - HashLog))
1787dd7cddfSDavid du Colombier
1797dd7cddfSDavid du Colombier /*
1807dd7cddfSDavid du Colombier * lz77 compression with single lookup in a hash table for each block
1817dd7cddfSDavid du Colombier */
1827dd7cddfSDavid du Colombier int
thwack(Thwack * tw,int mustadd,uchar * dst,int ndst,Block * bsrc,ulong seq,ulong stats[ThwStats])18359cc4ca5SDavid du Colombier thwack(Thwack *tw, int mustadd, uchar *dst, int ndst, Block *bsrc, ulong seq, ulong stats[ThwStats])
1847dd7cddfSDavid du Colombier {
1857dd7cddfSDavid du Colombier ThwBlock *eblocks, *b, blocks[CompBlocks];
1867dd7cddfSDavid du Colombier uchar *s, *ss, *sss, *esrc, *half, *twdst, *twdmax;
1877dd7cddfSDavid du Colombier ulong cont, cseq, bseq, cmask, code, twbits;
1887dd7cddfSDavid du Colombier int n, now, toff, lithist, h, len, slot, bits, use, twnbits, lits, matches, offbits, lenbits, nhist;
1897dd7cddfSDavid du Colombier
1907dd7cddfSDavid du Colombier n = BLEN(bsrc);
1917dd7cddfSDavid du Colombier if(n > ThwMaxBlock || n < MinMatch)
1927dd7cddfSDavid du Colombier return -1;
1937dd7cddfSDavid du Colombier
1947dd7cddfSDavid du Colombier twdst = dst;
19559cc4ca5SDavid du Colombier twdmax = dst + ndst;
1967dd7cddfSDavid du Colombier
1977dd7cddfSDavid du Colombier /*
1987dd7cddfSDavid du Colombier * add source to the coding window
1997dd7cddfSDavid du Colombier * there is always enough space
2007dd7cddfSDavid du Colombier */
2017dd7cddfSDavid du Colombier qlock(&tw->acklock);
2027dd7cddfSDavid du Colombier slot = tw->slot;
2037dd7cddfSDavid du Colombier b = &tw->blocks[slot];
2047dd7cddfSDavid du Colombier b->seq = seq;
2057dd7cddfSDavid du Colombier b->acked = 0;
2067dd7cddfSDavid du Colombier now = b->begin + b->maxoff;
2077dd7cddfSDavid du Colombier if(tw->data[slot] != nil){
2087dd7cddfSDavid du Colombier freeb(tw->data[slot]);
2097dd7cddfSDavid du Colombier tw->data[slot] = nil;
2107dd7cddfSDavid du Colombier }
2117dd7cddfSDavid du Colombier s = bsrc->rptr;
2127dd7cddfSDavid du Colombier b->data = s;
2137dd7cddfSDavid du Colombier b->edata = s + n;
2147dd7cddfSDavid du Colombier b->begin = now;
2157dd7cddfSDavid du Colombier b->maxoff = n;
2167dd7cddfSDavid du Colombier
2177dd7cddfSDavid du Colombier /*
2187dd7cddfSDavid du Colombier * set up the history blocks
2197dd7cddfSDavid du Colombier */
2207dd7cddfSDavid du Colombier cseq = seq;
2217dd7cddfSDavid du Colombier cmask = 0;
2227dd7cddfSDavid du Colombier *blocks = *b;
2237dd7cddfSDavid du Colombier b = blocks;
2247dd7cddfSDavid du Colombier b->maxoff = 0;
2257dd7cddfSDavid du Colombier b++;
2267dd7cddfSDavid du Colombier nhist = 0;
2277dd7cddfSDavid du Colombier while(b < blocks + CompBlocks){
2287dd7cddfSDavid du Colombier slot--;
2297dd7cddfSDavid du Colombier if(slot < 0)
2307dd7cddfSDavid du Colombier slot += EWinBlocks;
2317dd7cddfSDavid du Colombier if(slot == tw->slot)
2327dd7cddfSDavid du Colombier break;
2337dd7cddfSDavid du Colombier if(tw->data[slot] == nil || !tw->blocks[slot].acked)
2347dd7cddfSDavid du Colombier continue;
2357dd7cddfSDavid du Colombier bseq = tw->blocks[slot].seq;
2367dd7cddfSDavid du Colombier if(cseq == seq){
2377dd7cddfSDavid du Colombier if(seq - bseq >= MaxSeqStart)
2387dd7cddfSDavid du Colombier break;
2397dd7cddfSDavid du Colombier cseq = bseq;
2407dd7cddfSDavid du Colombier }else if(cseq - bseq > MaxSeqMask)
2417dd7cddfSDavid du Colombier break;
2427dd7cddfSDavid du Colombier else
2437dd7cddfSDavid du Colombier cmask |= 1 << (cseq - bseq - 1);
2447dd7cddfSDavid du Colombier *b = tw->blocks[slot];
2457dd7cddfSDavid du Colombier nhist += b->maxoff;
2467dd7cddfSDavid du Colombier b++;
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier qunlock(&tw->acklock);
2497dd7cddfSDavid du Colombier eblocks = b;
2507dd7cddfSDavid du Colombier *twdst++ = seq - cseq;
2517dd7cddfSDavid du Colombier *twdst++ = cmask;
2527dd7cddfSDavid du Colombier
2537dd7cddfSDavid du Colombier cont = (s[0] << 16) | (s[1] << 8) | s[2];
2547dd7cddfSDavid du Colombier
2557dd7cddfSDavid du Colombier esrc = s + n;
2567dd7cddfSDavid du Colombier half = s + (n >> 1);
2577dd7cddfSDavid du Colombier twnbits = 0;
2587dd7cddfSDavid du Colombier twbits = 0;
2597dd7cddfSDavid du Colombier lits = 0;
2607dd7cddfSDavid du Colombier matches = 0;
2617dd7cddfSDavid du Colombier offbits = 0;
2627dd7cddfSDavid du Colombier lenbits = 0;
2637dd7cddfSDavid du Colombier lithist = ~0;
2647dd7cddfSDavid du Colombier while(s < esrc){
2657dd7cddfSDavid du Colombier h = hashit(cont);
2667dd7cddfSDavid du Colombier
2677dd7cddfSDavid du Colombier sss = s;
2687dd7cddfSDavid du Colombier toff = thwmatch(blocks, eblocks, &sss, esrc, h);
2697dd7cddfSDavid du Colombier ss = sss;
2707dd7cddfSDavid du Colombier
2717dd7cddfSDavid du Colombier len = ss - s;
2727dd7cddfSDavid du Colombier for(; twnbits >= 8; twnbits -= 8){
27359cc4ca5SDavid du Colombier if(twdst < twdmax)
2747dd7cddfSDavid du Colombier *twdst++ = twbits >> (twnbits - 8);
27559cc4ca5SDavid du Colombier else if(!mustadd)
27659cc4ca5SDavid du Colombier return -1;
2777dd7cddfSDavid du Colombier }
2787dd7cddfSDavid du Colombier if(len < MinMatch){
2797dd7cddfSDavid du Colombier toff = *s;
2807dd7cddfSDavid du Colombier lithist = (lithist << 1) | (toff < 32) | (toff > 127);
2817dd7cddfSDavid du Colombier if(lithist & 0x1e){
2827dd7cddfSDavid du Colombier twbits = (twbits << 9) | toff;
2837dd7cddfSDavid du Colombier twnbits += 9;
2847dd7cddfSDavid du Colombier }else if(lithist & 1){
2857dd7cddfSDavid du Colombier toff = (toff + 64) & 0xff;
2867dd7cddfSDavid du Colombier if(toff < 96){
2877dd7cddfSDavid du Colombier twbits = (twbits << 10) | toff;
2887dd7cddfSDavid du Colombier twnbits += 10;
2897dd7cddfSDavid du Colombier }else{
2907dd7cddfSDavid du Colombier twbits = (twbits << 11) | toff;
2917dd7cddfSDavid du Colombier twnbits += 11;
2927dd7cddfSDavid du Colombier }
2937dd7cddfSDavid du Colombier }else{
2947dd7cddfSDavid du Colombier twbits = (twbits << 8) | toff;
2957dd7cddfSDavid du Colombier twnbits += 8;
2967dd7cddfSDavid du Colombier }
2977dd7cddfSDavid du Colombier lits++;
2987dd7cddfSDavid du Colombier blocks->maxoff++;
2997dd7cddfSDavid du Colombier
3007dd7cddfSDavid du Colombier /*
3017dd7cddfSDavid du Colombier * speed hack
3027dd7cddfSDavid du Colombier * check for compression progress, bail if none achieved
3037dd7cddfSDavid du Colombier */
3047dd7cddfSDavid du Colombier if(s > half){
30559cc4ca5SDavid du Colombier if(!mustadd && 4 * blocks->maxoff < 5 * lits)
3067dd7cddfSDavid du Colombier return -1;
3077dd7cddfSDavid du Colombier half = esrc;
3087dd7cddfSDavid du Colombier }
3097dd7cddfSDavid du Colombier
3107dd7cddfSDavid du Colombier if(s + MinMatch <= esrc){
3117dd7cddfSDavid du Colombier blocks->hash[(h ^ blocks->seq) & HashMask] = now;
3127dd7cddfSDavid du Colombier if(s + MinMatch < esrc)
3137dd7cddfSDavid du Colombier cont = (cont << 8) | s[MinMatch];
3147dd7cddfSDavid du Colombier }
3157dd7cddfSDavid du Colombier now++;
3167dd7cddfSDavid du Colombier s++;
3177dd7cddfSDavid du Colombier continue;
3187dd7cddfSDavid du Colombier }
3197dd7cddfSDavid du Colombier
3207dd7cddfSDavid du Colombier blocks->maxoff += len;
3217dd7cddfSDavid du Colombier matches++;
3227dd7cddfSDavid du Colombier
3237dd7cddfSDavid du Colombier /*
3247dd7cddfSDavid du Colombier * length of match
3257dd7cddfSDavid du Colombier */
3267dd7cddfSDavid du Colombier len -= MinMatch;
3277dd7cddfSDavid du Colombier if(len < MaxFastLen){
3287dd7cddfSDavid du Colombier bits = lentab[len].bits;
3297dd7cddfSDavid du Colombier twbits = (twbits << bits) | lentab[len].encode;
3307dd7cddfSDavid du Colombier twnbits += bits;
3317dd7cddfSDavid du Colombier lenbits += bits;
3327dd7cddfSDavid du Colombier }else{
3337dd7cddfSDavid du Colombier code = BigLenCode;
3347dd7cddfSDavid du Colombier bits = BigLenBits;
3357dd7cddfSDavid du Colombier use = BigLenBase;
3367dd7cddfSDavid du Colombier len -= MaxFastLen;
3377dd7cddfSDavid du Colombier while(len >= use){
3387dd7cddfSDavid du Colombier len -= use;
3397dd7cddfSDavid du Colombier code = (code + use) << 1;
3407dd7cddfSDavid du Colombier use <<= (bits & 1) ^ 1;
3417dd7cddfSDavid du Colombier bits++;
3427dd7cddfSDavid du Colombier }
3437dd7cddfSDavid du Colombier twbits = (twbits << bits) | (code + len);
3447dd7cddfSDavid du Colombier twnbits += bits;
3457dd7cddfSDavid du Colombier lenbits += bits;
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier for(; twnbits >= 8; twnbits -= 8){
34859cc4ca5SDavid du Colombier if(twdst < twdmax)
3497dd7cddfSDavid du Colombier *twdst++ = twbits >> (twnbits - 8);
35059cc4ca5SDavid du Colombier else if(!mustadd)
35159cc4ca5SDavid du Colombier return -1;
3527dd7cddfSDavid du Colombier }
3537dd7cddfSDavid du Colombier }
3547dd7cddfSDavid du Colombier
3557dd7cddfSDavid du Colombier /*
3567dd7cddfSDavid du Colombier * offset in history
3577dd7cddfSDavid du Colombier */
3587dd7cddfSDavid du Colombier toff--;
3597dd7cddfSDavid du Colombier for(bits = OffBase; toff >= (1 << bits); bits++)
3607dd7cddfSDavid du Colombier ;
3617dd7cddfSDavid du Colombier if(bits < MaxOff+OffBase-1){
3627dd7cddfSDavid du Colombier twbits = (twbits << 3) | (bits - OffBase);
3637dd7cddfSDavid du Colombier if(bits != OffBase)
3647dd7cddfSDavid du Colombier bits--;
3657dd7cddfSDavid du Colombier twnbits += bits + 3;
3667dd7cddfSDavid du Colombier offbits += bits + 3;
3677dd7cddfSDavid du Colombier }else{
3687dd7cddfSDavid du Colombier twbits = (twbits << 4) | 0xe | (bits - (MaxOff+OffBase-1));
3697dd7cddfSDavid du Colombier bits--;
3707dd7cddfSDavid du Colombier twnbits += bits + 4;
3717dd7cddfSDavid du Colombier offbits += bits + 4;
3727dd7cddfSDavid du Colombier }
3737dd7cddfSDavid du Colombier twbits = (twbits << bits) | toff & ((1 << bits) - 1);
3747dd7cddfSDavid du Colombier
3757dd7cddfSDavid du Colombier for(; s != ss; s++){
3767dd7cddfSDavid du Colombier if(s + MinMatch <= esrc){
3777dd7cddfSDavid du Colombier h = hashit(cont);
3787dd7cddfSDavid du Colombier blocks->hash[(h ^ blocks->seq) & HashMask] = now;
3797dd7cddfSDavid du Colombier if(s + MinMatch < esrc)
3807dd7cddfSDavid du Colombier cont = (cont << 8) | s[MinMatch];
3817dd7cddfSDavid du Colombier }
3827dd7cddfSDavid du Colombier now++;
3837dd7cddfSDavid du Colombier }
3847dd7cddfSDavid du Colombier }
3857dd7cddfSDavid du Colombier
3867dd7cddfSDavid du Colombier if(twnbits & 7){
3877dd7cddfSDavid du Colombier twbits <<= 8 - (twnbits & 7);
3887dd7cddfSDavid du Colombier twnbits += 8 - (twnbits & 7);
3897dd7cddfSDavid du Colombier }
3907dd7cddfSDavid du Colombier for(; twnbits >= 8; twnbits -= 8){
39159cc4ca5SDavid du Colombier if(twdst < twdmax)
3927dd7cddfSDavid du Colombier *twdst++ = twbits >> (twnbits - 8);
39359cc4ca5SDavid du Colombier else if(!mustadd)
39459cc4ca5SDavid du Colombier return -1;
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier
397*9a747e4fSDavid du Colombier if(twdst >= twdmax && !mustadd)
398*9a747e4fSDavid du Colombier return -1;
399*9a747e4fSDavid du Colombier
4007dd7cddfSDavid du Colombier qlock(&tw->acklock);
40159cc4ca5SDavid du Colombier tw->data[tw->slot] = bsrc;
4027dd7cddfSDavid du Colombier tw->slot++;
4037dd7cddfSDavid du Colombier if(tw->slot >= EWinBlocks)
4047dd7cddfSDavid du Colombier tw->slot = 0;
4057dd7cddfSDavid du Colombier qunlock(&tw->acklock);
4067dd7cddfSDavid du Colombier
40759cc4ca5SDavid du Colombier if(twdst >= twdmax)
40859cc4ca5SDavid du Colombier return -1;
40959cc4ca5SDavid du Colombier
4107dd7cddfSDavid du Colombier stats[StatBytes] += blocks->maxoff;
4117dd7cddfSDavid du Colombier stats[StatLits] += lits;
4127dd7cddfSDavid du Colombier stats[StatMatches] += matches;
4137dd7cddfSDavid du Colombier stats[StatOffBits] += offbits;
4147dd7cddfSDavid du Colombier stats[StatLenBits] += lenbits;
4157dd7cddfSDavid du Colombier stats[StatDelay] = stats[StatDelay]*7/8 + dst[0];
4167dd7cddfSDavid du Colombier stats[StatHist] = stats[StatHist]*7/8 + nhist;
4177dd7cddfSDavid du Colombier stats[StatOutBytes] += twdst - dst;
4187dd7cddfSDavid du Colombier
4197dd7cddfSDavid du Colombier return twdst - dst;
4207dd7cddfSDavid du Colombier }
421