/* lifted from /sys/src/cmd/ip/ppp/mppc.c (RFC 2118) */ #include #include #include #include "dat.h" #include "fns.h" #define DBG if(0) //#define DBG enum { HistorySize = 8*1024, Preset= 0x80, /* reset history */ Pfront= 0x40, /* move packet to front of history */ Pcompress= 0x20, /* packet is compressed */ Pbulk64= 0x01, /* RPD5 bulk compression (64K history) */ }; enum { Lit7, /* seven bit literal */ Lit8, /* eight bit literal */ Off6, /* six bit offset */ Off8, /* eight bit offset */ Off13, /* thirteen bit offset */ }; /* decode first four bits */ static int decode[16] = { Lit7, Lit7, Lit7, Lit7, Lit7, Lit7, Lit7, Lit7, Lit8, Lit8, Lit8, Lit8, Off13, Off13, Off8, Off6, }; typedef struct Uncstate Uncstate; struct Uncstate { uchar his[HistorySize]; int indx; /* current indx in history */ int size; /* current history size */ }; static Uncstate uncstate; #define NEXTBYTE sreg = (sreg<<8) | *p++; n--; bits += 8 uchar* uncomp(uchar* buf, int nbytes, int flags, int* psize) { int n, bits, off, len, ones, t; ulong sreg; uchar *p, c, *hp, *hs, *he, *hq; Uncstate *s; s = &uncstate; p = buf; n = nbytes; if(flags&Preset){ s->indx = 0; s->size = 0; } if(flags&Pfront) { s->indx = 0; DBG fprint(2, "mppc: front flag set\n"); } if(!(flags&Pcompress)){ *psize = n; return buf; } if(flags&Pbulk64){ werrstr("bigger history is not supported"); return nil; } bits = 0; sreg = 0; hs = s->his; /* history start */ hp = hs+s->indx; /* write pointer in history */ he = hs+sizeof(s->his); /* history end */ for(;;){ if(bits<4){ if(n==0) goto Done; NEXTBYTE; } t = decode[(sreg>>(bits-4))&0xf]; switch(t){ default: sysfatal("mppc: bad decode!"); case Lit7: bits -= 1; if(bits<7){ if(n==0) goto Done; NEXTBYTE; } c = (sreg>>(bits-7))&0x7f; bits -= 7; if(hp >= he) goto His; *hp++ = c; continue; case Lit8: bits -= 2; if(bits<7) { if(n==0) goto Eof; NEXTBYTE; } c = 0x80 | ((sreg>>(bits-7))&0x7f); bits -= 7; if(hp >= he) goto His; *hp++ = c; continue; case Off6: bits -= 4; if(bits<6){ if(n==0) goto Eof; NEXTBYTE; } off = (sreg>>(bits-6))&0x3f; bits -= 6; break; case Off8: bits -= 4; if(bits<8){ if(n==0) goto Eof; NEXTBYTE; } off = ((sreg>>(bits-8))&0xff)+64; bits -= 8; break; case Off13: bits -= 3; while(bits<13){ if(n==0) goto Eof; NEXTBYTE; } off = ((sreg>>(bits-13))&0x1fff)+320; bits -= 13; break; } for(ones=0;;ones++) { if(bits == 0) { if(n==0) goto Eof; NEXTBYTE; } bits--; if(!(sreg&(1<11){ werrstr("bad length %d\n", ones); return nil; } if(ones == 0) { len = 3; } else { ones++; while(bits>(bits-ones))&((1<his); if(hq-hs+len > s->size) goto His; } if(hp+len > he) goto His; while(len) { *hp++ = *hq++; len--; } } Done: hq = hs+s->indx; len = hp-hq; DBG fprint(2, "mppc: len %d bits = %d n=%d\n", len, bits, n); s->indx += len; if(s->indx > s->size) s->size = s->indx; *psize = len; return hq; Eof: werrstr("unexpected end of data"); return nil; His: werrstr("bad history reference"); return nil; }