ref: 75ceb243faad4aa529afef047473ece203113eff
dir: /f_flate.c/
#include <u.h> #include <libc.h> #include <flate.h> #include "pdf.h" typedef struct FlateParms FlateParms; struct FlateParms { int predictor; int columns; }; static uchar paeth(uchar a, uchar b, uchar c) { int p, pa, pb, pc; p = a + b - c; pa = abs(p - a); pb = abs(p - b); pc = abs(p - c); if(pa <= pb && pa <= pc) return a; return pb <= pc ? b : c; } static int pngunpredict(int pred, uchar *buf, uchar *up, int len) { int i; switch(pred){ case 0: /* None */ break; case 1: /* Sub */ for(i = 1; i < len; ++i) buf[i] += buf[i-1]; break; case 2: /* Up */ for(i = 0; i < len; ++i) buf[i] += up[i]; break; case 3: /* Average */ buf[0] += up[0]/2; for(i = 1; i < len; ++i) buf[i] += (buf[i-1]+up[i])/2; break; case 4: /* Paeth */ buf[0] += paeth(0, up[0], 0); for(i = 0; i < len; ++i) buf[i] += paeth(buf[i-1], up[i], up[i-1]); break; /* FIXME 5 optimum??? */ default: werrstr("unsupported predictor %d", pred); return -1; } return 0; } static int bw(void *aux, void *d, int n) { return bufput(aux, d, n); } static int bget(void *aux) { uchar c; return bufget(aux, &c, 1) == 1 ? c : -1; } static int flreadall(void *aux, Buffer *bi, Buffer *bo) { int r, i, rows, n; FlateParms *fp; uchar *x, *y, *zero; fp = aux; do{ r = inflatezlib(bo, bw, bi, bget); }while(r == FlateOk && !bufeof(bi)); if(r != FlateOk && bufleft(bo) < 1){ werrstr("%s", flateerr(r)); return -1; } r = 0; /* 7.4.4.4 LZW and Flate predictor functions */ if(fp->predictor >= 10 && fp->columns > 0){ n = fp->columns + 1; rows = bo->sz/n; x = bo->b; y = bo->b; zero = mallocz(fp->columns, 1); for(i = r = 0; i < rows && r == 0; i++, x += n, y += n) r = pngunpredict(x[0], x+1, i < 1 ? zero : y+1-n, fp->columns); free(zero); x = bo->b; y = bo->b+1; for(i = 0; i < rows; i++, x += fp->columns, y += n) memmove(x, y, fp->columns); bo->sz -= rows; } return r; } static int flopen(Filter *f, Object *o) { Object *parms; FlateParms *fp; int predictor, columns; parms = dictget(o, "DecodeParms"); predictor = dictint(parms, "Predictor"); columns = dictint(parms, "Columns"); if((predictor >= 2 && predictor < 10) || predictor >= 15){ werrstr("unsupported flate predictor %d", predictor); return -1; } if(predictor >= 10 && predictor <= 15 && columns < 1){ werrstr("invalid columns %d for predictor %d", columns, predictor); return -1; } if((fp = malloc(sizeof(FlateParms))) == nil) return -1; fp->predictor = predictor; fp->columns = columns; f->aux = fp; return 0; } static void flclose(Filter *f) { free(f->aux); } Filter filterFlate = { .name = "FlateDecode", .readall = flreadall, .open = flopen, .close = flclose, };