ref: 3d14c5f66a2485db6ba7e25393a72e5f142049b6
parent: d1a98f52a81b08b68e9cbb0e78c166f62c936690
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Sun Nov 22 14:29:36 EST 2020
lzw filter
--- a/f_lzw.c
+++ b/f_lzw.c
@@ -2,6 +2,163 @@
#include <libc.h>
#include "pdf.h"
+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;
+
+ USED(aux);
+
+ 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 0;
+}
+
Filter filterLZW = {
.name = "LZWDecode",
+ .readall = flreadall,
};