ref: b3610440c27ad0b930290179daf1f18d5a675686
dir: /f_lzw.c/
#include <u.h> #include <libc.h> #include "pdf.h" /* 7.4.4 LZWDecode filter */ typedef struct Pt Pt; typedef struct Tb Tb; struct Pt { int o, sz; }; struct Tb { Pt *pt; int npt; uchar *p; int max; int off; Pt pr; }; static void tbclean(Tb *tb) { int i; tb->off = 256; tb->npt = 258; if(tb->p == nil){ tb->max = 1024; tb->p = malloc(tb->max); } if(tb->pt == nil){ tb->pt = malloc(sizeof(Pt)*4096); for(i = 0; i < 256; i++){ tb->p[i] = i; tb->pt[i].o = i; tb->pt[i].sz = 1; } } memset(tb->pt+tb->npt, 0, sizeof(Pt)*(4096-tb->npt)); } static int tbputc(Tb *tb, int c, Buffer *o) { uchar *d; Pt *pt; int n; if(tb->pt == nil) tbclean(tb); /* firt, make sure things will fit in */ if(tb->max <= tb->off*2){ tb->max = tb->off*4; tb->p = realloc(tb->p, tb->max); } pt = &tb->pt[c]; if(pt->sz > 0){ d = tb->p + pt->o; n = pt->sz; if(tb->pr.sz > 0){ /* have prefix - insert another point */ pt = &tb->pt[tb->npt++]; pt->o = tb->off; pt->sz = tb->pr.sz + 1; memmove(tb->p + pt->o, tb->p + tb->pr.o, tb->pr.sz); tb->p[pt->o + pt->sz - 1] = d[0]; tb->off += pt->sz; } /* update prefix */ tb->pr.o = d - tb->p; tb->pr.sz = n; }else{ pt = &tb->pt[tb->npt++]; pt->o = tb->off; pt->sz = tb->pr.sz + 1; memmove(tb->p + pt->o, tb->p + tb->pr.o, tb->pr.sz); tb->p[pt->o + pt->sz - 1] = tb->p[tb->pr.o]; tb->off += pt->sz; tb->pr.o = pt->o; tb->pr.sz = pt->sz; d = tb->p + pt->o; n = pt->sz; } bufput(o, d, n); if(tb->npt < 511) return 9; if(tb->npt < 1023) return 10; if(tb->npt < 2047) return 11; if(tb->npt < 4097) return 12; return -1; } static void tbfree(Tb *tb) { free(tb->p); free(tb->pt); memset(tb, 0, sizeof(*tb)); } static int flreadall(void *aux, Buffer *bi, Buffer *bo) { int i, j, x, insz, width, w; uchar *in; Tb tb; memset(&tb, 0, sizeof(tb)); in = bufdata(bi, &insz); width = 9; x = 0; for(i = w = 0, j = 7; i < insz; j--){ x = x<<1 | ((in[i] & (1<<j)) >> j); if(j < 1){ i++; j = 8; } if(++w == width){ if(x == 257) /* EOD */ break; if(x == 256){ /* CLEAR */ tbclean(&tb); width = 9; }else if((width = tbputc(&tb, x, bo)) < 0){ werrstr("points overflow"); tbfree(&tb); return -1; } w = 0; x = 0; } } tbfree(&tb); bi->off = bi->sz; return unpredict(aux, bo); } Filter filterLZW = { .name = "LZWDecode", .readall = flreadall, .open = flopenpredict, .close = flclosepredict, };