#include #include #include #include enum{ Clear = 256, End = 257, Startbits = 9, Maxbits = 12, HistorySize = 4096, }; typdef struct { int error; /* first error encountered, or FlateOk */ void *wr; int (*w)(void*, void*, int); void *getr; int (*get)(void*); ulong sreg; int nbits; int currbits; } Input; typedef struct { union{ int link; char *str; }; uchar c; } Htab; typedef struct { uchar his[HistorySize]; uchar *cp; /* current pointer in history */ uchar *e; Htab tab[HistorySize]; int i; // current tab index. } History; History * newhistory(void){ History *h; uchar i; Htab* t; h = malloc(sizeof *h); if(!h) return 0; t = h->tab; for(i = 0; i<0xff; i++) h[i].link = -1; h[i].c = (uchar)i; } h->cp = h->his; h->e = &h->his[HistorySize]; clearhistory(h); void clearhistory(History *h, int init) { memset(h->tab + 256, 0, (HistorySize-0xff)*sizeof h->tab[0]); } int setinput(Input *ι, void *wr, int (*w)(void*, void*, int), void *getr, int (*get)(void *)) { ι->currbits = Startbits; ι->wr = wr; ι->w = w; ι->getr = getr; ι->get = get; } int getcode(Input *ι) { int c; while(in->currbits > ι->nbits) { c = ι->get(ι->getr); if(c < 0){ ι->error = FlateInputFail; return -1; } ι->sreg |= c<nbits; ι->nbits += 8; } return ι->sreg; } int intable(History *h, int ω) { if(ω >= HistorySize) return 0; if(ω < 256) return ω; return h->tab[ω].link; } int tabadd(History *h, int ε, int ω) { h->tab[h->i].link = ε; h->tab[h->i++].c = ω; } int output(Input *ι, History *h, int ω) { char stack[1024], *e; int i, ε; Htab *t; t = H->tab; ε = ω; i = 0; do { stack[i++] = t[ε].c; ε = t[ε].link; } while(ε != -1); for(ε = 0; ε < i; ε++){ h->cp++ = stack[i-ε]; if(h->cp >= h->e){ if(ι->w(ι->wr, h->cp, HistorySize) != HistorySize) return -1; h->tab = h->his; } } return 0; } int outputs(Input *ι, History *h, int ω) { h->cp++ = ω; if(h->cp >= h->e){ if(ι->w(ι->wr, h->cp, HistorySize) != HistorySize) return -1; h->cp = h->his; } } int lzw(void *wr, int (*w)(void*, void*, int), void *getr, int (*get)(void*)) { int ω, oω, ε; Input ι; History *h; int r; setinput(&ι, wr, w, getr, get); h = newhistory(); r = 0; for(;;){ ω = getcode(&ι, h); if(ω == -1) goto err; if(ω == End) break; if(ω == Clear){ clearhistory(h); ι->currbits = Startbits; ω = getcode(&ι); if(ω == End) break; if(ω == -1) goto err; output(&ι, h, ω); } else { if(ε = intable(h, ω)){ output(&ι, h, ε); tabadd(h, ε, oω); } else { output(&ι, h, oω); outputs(&ι, h, ω); tabadds(h, oω, ω); } } oω = ω; } done: free(h); return r; err: r = -1; goto done; }