Unified · Split
| @@ -47,7 +47,13 @@ buffree(Buffer *b) · 46 unmodified lines | ||
| 47 | 47 | int |
| 48 | 48 | bufeof(Buffer *b) |
| 49 | 49 | { |
| 50 | − return b->off == b->sz; | |
| 50 | + return bufleft(b) == 0; | |
| 51 | +} | |
| 52 | + | |
| 53 | +int | |
| 54 | +bufleft(Buffer *b) | |
| 55 | +{ | |
| 56 | + return b->sz - b->off; | |
| 51 | 57 | } |
| 52 | 58 | |
| 53 | 59 | uchar * |
| @@ -4,6 +4,69 @@ · 3 unmodified lines | ||
| 4 | 4 | #include <flate.h> |
| 5 | 5 | #include "pdf.h" |
| 6 | 6 | |
| 7 | +typedef struct FlateParms FlateParms; | |
| 8 | + | |
| 9 | +struct FlateParms { | |
| 10 | + int predictor; | |
| 11 | + int columns; | |
| 12 | +}; | |
| 13 | + | |
| 14 | +static uchar | |
| 15 | +paeth(uchar a, uchar b, uchar c) | |
| 16 | +{ | |
| 17 | + int p, pa, pb, pc; | |
| 18 | + | |
| 19 | + p = a + b - c; | |
| 20 | + pa = abs(p - a); | |
| 21 | + pb = abs(p - b); | |
| 22 | + pc = abs(p - c); | |
| 23 | + | |
| 24 | + if(pa <= pb && pa <= pc) | |
| 25 | + return a; | |
| 26 | + return pb <= pc ? b : c; | |
| 27 | +} | |
| 28 | + | |
| 29 | +static int | |
| 30 | +pngunpredict(int pred, uchar *buf, uchar *up, int len) | |
| 31 | +{ | |
| 32 | + int i; | |
| 33 | + | |
| 34 | + switch(pred){ | |
| 35 | + case 0: /* None */ | |
| 36 | + break; | |
| 37 | + | |
| 38 | + case 1: /* Sub */ | |
| 39 | + for(i = 1; i < len; ++i) | |
| 40 | + buf[i] += buf[i-1]; | |
| 41 | + break; | |
| 42 | + | |
| 43 | + case 2: /* Up */ | |
| 44 | + for(i = 0; i < len; ++i) | |
| 45 | + buf[i] += up[i]; | |
| 46 | + break; | |
| 47 | + | |
| 48 | + case 3: /* Average */ | |
| 49 | + buf[0] += up[0]/2; | |
| 50 | + for(i = 1; i < len; ++i) | |
| 51 | + buf[i] += (buf[i-1]+up[i])/2; | |
| 52 | + break; | |
| 53 | + | |
| 54 | + case 4: /* Paeth */ | |
| 55 | + buf[0] += paeth(0, up[0], 0); | |
| 56 | + for(i = 0; i < len; ++i) | |
| 57 | + buf[i] += paeth(buf[i-1], up[i], up[i-1]); | |
| 58 | + break; | |
| 59 | + | |
| 60 | + /* FIXME 5 optimum??? */ | |
| 61 | + | |
| 62 | + default: | |
| 63 | + werrstr("unsupported predictor %d", pred); | |
| 64 | + return -1; | |
| 65 | + } | |
| 66 | + | |
| 67 | + return 0; | |
| 68 | +} | |
| 69 | + | |
| 7 | 70 | static int |
| 8 | 71 | bw(void *aux, void *d, int n) |
| 9 | 72 | { |
| @@ -21,9 +84,11 @@ bget(void *aux) · 11 unmodified lines | ||
| 21 | 84 | int |
| 22 | 85 | fFlate(void *aux, Buffer *bi, Buffer *bo) |
| 23 | 86 | { |
| 24 | − int r; | |
| 87 | + int r, i, rows, n; | |
| 88 | + FlateParms *fp; | |
| 89 | + uchar *x, *y, *zero; | |
| 25 | 90 | |
| 26 | − USED(aux); | |
| 91 | + fp = aux; | |
| 27 | 92 | |
| 28 | 93 | do{ |
| 29 | 94 | r = inflatezlib(bo, bw, bi, bget); |
| @@ -34,5 +99,57 @@ fFlate(void *aux, Buffer *bi, Buffer *bo) · 4 unmodified lines | ||
| 34 | 99 | return -1; |
| 35 | 100 | } |
| 36 | 101 | |
| 102 | + /* 7.4.4.4 LZW and Flate predictor functions */ | |
| 103 | + if(fp->predictor >= 10 && fp->columns > 0){ | |
| 104 | + n = fp->columns + 1; | |
| 105 | + rows = bo->sz/n; | |
| 106 | + x = bo->b; | |
| 107 | + y = bo->b; | |
| 108 | + zero = mallocz(fp->columns, 1); | |
| 109 | + for(i = r = 0; i < rows && r == 0; i++, x += n, y += n) | |
| 110 | + r = pngunpredict(x[0], x+1, i < 1 ? zero : y+1-n, fp->columns); | |
| 111 | + free(zero); | |
| 112 | + | |
| 113 | + x = bo->b; | |
| 114 | + y = bo->b+1; | |
| 115 | + for(i = 0; i < rows; i++, x += fp->columns, y += n) | |
| 116 | + memmove(x, y, fp->columns); | |
| 117 | + bo->sz -= rows; | |
| 118 | + } | |
| 119 | + | |
| 120 | + return r; | |
| 121 | +} | |
| 122 | + | |
| 123 | +int | |
| 124 | +openFlate(Filter *f, Object *o) | |
| 125 | +{ | |
| 126 | + Object *parms; | |
| 127 | + FlateParms *fp; | |
| 128 | + int predictor, columns; | |
| 129 | + | |
| 130 | + parms = dictget(o, "DecodeParms"); | |
| 131 | + predictor = dictint(parms, "Predictor"); | |
| 132 | + columns = dictint(parms, "Columns"); | |
| 133 | + if((predictor >= 2 && predictor < 10) || predictor >= 15){ | |
| 134 | + werrstr("unsupported flate predictor %d", predictor); | |
| 135 | + return -1; | |
| 136 | + } | |
| 137 | + if(predictor >= 10 && predictor <= 15 && columns < 1){ | |
| 138 | + werrstr("invalid columns %d for predictor %d", columns, predictor); | |
| 139 | + return -1; | |
| 140 | + } | |
| 141 | + | |
| 142 | + if((fp = malloc(sizeof(FlateParms))) == nil) | |
| 143 | + return -1; | |
| 144 | + fp->predictor = predictor; | |
| 145 | + fp->columns = columns; | |
| 146 | + f->aux = fp; | |
| 147 | + | |
| 37 | 148 | return 0; |
| 38 | 149 | } |
| 150 | + | |
| 151 | +void | |
| 152 | +closeFlate(Filter *f) | |
| 153 | +{ | |
| 154 | + free(f->aux); | |
| 155 | +} | |
| @@ -5,15 +5,9 @@ · 4 unmodified lines | ||
| 5 | 5 | |
| 6 | 6 | /* 7.4 Filters */ |
| 7 | 7 | |
| 8 | −struct Filter { | |
| 9 | − char *name; | |
| 10 | − int (*readall)(void *aux, Buffer *bi, Buffer *bo); | |
| 11 | − int (*open)(Filter *f, Object *o); | |
| 12 | − void (*close)(Filter *f); | |
| 13 | − void *aux; | |
| 14 | −}; | |
| 15 | − | |
| 16 | 8 | int fFlate(void *aux, Buffer *bi, Buffer *bo); |
| 9 | +int openFlate(Filter *f, Object *o); | |
| 10 | +void closeFlate(Filter *f); | |
| 17 | 11 | |
| 18 | 12 | static Filter filters[] = { |
| 19 | 13 | {"ASCII85Decode", nil, nil, nil}, |
| @@ -21,7 +15,7 @@ static Filter filters[] = { · 1 unmodified line | ||
| 21 | 15 | {"CCITTFaxDecode", nil, nil, nil}, |
| 22 | 16 | {"CryptDecode", nil, nil, nil}, |
| 23 | 17 | {"DCTDecode", nil, nil, nil}, |
| 24 | − {"FlateDecode", fFlate}, | |
| 18 | + {"FlateDecode", fFlate, openFlate, closeFlate}, | |
| 25 | 19 | {"JBIG2Decode", nil, nil, nil}, |
| 26 | 20 | {"JPXDecode", nil, nil, nil}, |
| 27 | 21 | {"LZWDecode", nil, nil, nil}, |
| @@ -15,6 +15,12 @@ static char *otypes[] = { · 14 unmodified lines | ||
| 15 | 15 | [Oindir] = "indir", |
| 16 | 16 | }; |
| 17 | 17 | |
| 18 | +static char *xtypes[] = { | |
| 19 | + [Xusual] = "usual", | |
| 20 | + [Xuncompressed] = "uncompressed", | |
| 21 | + [Xcompressed] = "compressed", | |
| 22 | +}; | |
| 23 | + | |
| 18 | 24 | Object null = { |
| 19 | 25 | .type = Onull, |
| 20 | 26 | }; |
| @@ -32,6 +38,24 @@ Tfmt(Fmt *f) · 11 unmodified lines | ||
| 32 | 38 | return fmtprint(f, "%s", otypes[o->type]); |
| 33 | 39 | } |
| 34 | 40 | |
| 41 | +int | |
| 42 | +⊗fmt(Fmt *f) | |
| 43 | +{ | |
| 44 | + Xref x; | |
| 45 | + | |
| 46 | + x = va_arg(f->args, Xref); | |
| 47 | + | |
| 48 | + switch(x.type){ | |
| 49 | + case Xusual: | |
| 50 | + return fmtprint(f, "<%s id=%d gen=%d off=%d>", xtypes[x.type], x.id, x.gen, x.off); | |
| 51 | + case Xuncompressed: | |
| 52 | + return fmtprint(f, "<%s gen=%d off=%d>", xtypes[x.type], x.gen, x.off); | |
| 53 | + case Xcompressed: | |
| 54 | + return fmtprint(f, "<%s id=%d objnum=%d>", xtypes[x.type], x.id, x.objnum); | |
| 55 | + } | |
| 56 | + return -1; | |
| 57 | +} | |
| 58 | + | |
| 35 | 59 | int |
| 36 | 60 | isws(int c) |
| 37 | 61 | { |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | #include "pdf.h" |
| 6 | 6 | |
| 7 | 7 | int Tfmt(Fmt *f); |
| 8 | +int ⊗fmt(Fmt *f); | |
| 8 | 9 | |
| 9 | 10 | /* |
| 10 | 11 | * pre-1.5 xref section reader |
| @@ -41,6 +42,8 @@ xrefread(Pdf *pdf, int xref0, int nxref) · 30 unmodified lines | ||
| 41 | 42 | } |
| 42 | 43 | xref.id = xref0 + i; |
| 43 | 44 | xref.off = strtoul(e, nil, 10); |
| 45 | + /* FIXME xref.gen */ | |
| 46 | + xref.type = Xusual; | |
| 44 | 47 | |
| 45 | 48 | /* search in already existing xrefs, update if found */ |
| 46 | 49 | for(j = 0; j < pdf->nxref; j++){ |
| @@ -97,6 +100,104 @@ err: · 50 unmodified lines | ||
| 97 | 100 | return -1; |
| 98 | 101 | } |
| 99 | 102 | |
| 103 | +static int | |
| 104 | +getint(uchar *b, int sz, int dflt) | |
| 105 | +{ | |
| 106 | + int x, i; | |
| 107 | + | |
| 108 | + if(sz == 0) | |
| 109 | + return dflt; | |
| 110 | + x = 0; | |
| 111 | + for(i = 0; i < sz; i++) | |
| 112 | + x = x<<8 | b[i]; | |
| 113 | + | |
| 114 | + return x; | |
| 115 | +} | |
| 116 | + | |
| 117 | +/* 7.5.8.3 */ | |
| 118 | +static int | |
| 119 | +xrefstreamread(Pdf *pdf) | |
| 120 | +{ | |
| 121 | + Object *o; | |
| 122 | + Stream *s; | |
| 123 | + Xref *x; | |
| 124 | + uchar buf[32]; | |
| 125 | + int w[8], nw, i, c, n, nxref, newnxref, prev, extra; | |
| 126 | + | |
| 127 | + s = nil; | |
| 128 | + if((o = pdfobj(pdf, pdf->bio)) == nil){ | |
| 129 | + werrstr("xref stream obj: %r"); | |
| 130 | + goto err; | |
| 131 | + } | |
| 132 | + if((prev = dictint(o, "Prev")) > 0){ | |
| 133 | + if(Bseek(pdf->bio, prev, 0) != prev){ | |
| 134 | + werrstr("xref stream prev seek failed"); | |
| 135 | + goto err; | |
| 136 | + } | |
| 137 | + if(xrefstreamread(pdf) != 0){ | |
| 138 | + pdfobjfree(o); | |
| 139 | + return -1; | |
| 140 | + } | |
| 141 | + } | |
| 142 | + if((s = streamopen(o)) == nil){ | |
| 143 | + werrstr("failed to stream xref: %r"); | |
| 144 | + goto err; | |
| 145 | + } | |
| 146 | + if((nw = dictints(o, "W", w, nelem(w))) < 3 || nw >= nelem(w)){ | |
| 147 | + werrstr("nW=%d", nw); | |
| 148 | + goto err; | |
| 149 | + } | |
| 150 | + | |
| 151 | + for(n = i = 0; i < nw; i++) | |
| 152 | + n += w[i]; /* size of each element. w[i] MAY be 0 */ | |
| 153 | + if(n > sizeof(buf)){ | |
| 154 | + werrstr("W is beyond imaginable: %d bytes", n); | |
| 155 | + goto err; | |
| 156 | + } | |
| 157 | + if((nxref = streamsize(s)/n) < 1){ | |
| 158 | + werrstr("no xref elements in the stream"); | |
| 159 | + goto err; | |
| 160 | + } | |
| 161 | + extra = streamsize(s) % (nxref*n); | |
| 162 | + if(extra != 0) | |
| 163 | + fprint(2, "extra %d bytes in xref stream", extra); | |
| 164 | + | |
| 165 | + newnxref = pdf->nxref + nxref; | |
| 166 | + if((x = realloc(pdf->xref, newnxref*sizeof(Xref))) == nil) | |
| 167 | + goto err; | |
| 168 | + pdf->xref = x; | |
| 169 | + x += pdf->nxref; | |
| 170 | + while(Bread(s->bio, buf, n) == n){ /* stop on short read or error */ | |
| 171 | + c = getint(buf, w[0], 1); /* default type is 1 */ | |
| 172 | + if(c == 1){ /* not compressed */ | |
| 173 | + x->off = getint(buf+w[0], w[1], 0); | |
| 174 | + x->gen = getint(buf+w[0]+w[1], w[2], 0); | |
| 175 | + x->type = Xuncompressed; | |
| 176 | + pdf->nxref++; | |
| 177 | + fprint(2, "xref %⊗\n", *x); | |
| 178 | + x++; | |
| 179 | + }else if(c == 2){ /* compressed */ | |
| 180 | + x->objnum = getint(buf+w[0], w[1], 0); | |
| 181 | + x->id = getint(buf+w[0]+w[1], w[2], 0); | |
| 182 | + x->type = Xcompressed; | |
| 183 | + pdf->nxref++; | |
| 184 | + fprint(2, "xref %⊗\n", *x); | |
| 185 | + x++; | |
| 186 | + } | |
| 187 | + } | |
| 188 | + | |
| 189 | + streamclose(s); | |
| 190 | + pdf->root = pdfref(dictget(o, "Root")); | |
| 191 | + pdf->info = pdfref(dictget(o, "Info")); | |
| 192 | + pdfobjfree(o); | |
| 193 | + | |
| 194 | + return 0; | |
| 195 | +err: | |
| 196 | + streamclose(s); | |
| 197 | + pdfobjfree(o); | |
| 198 | + return -1; | |
| 199 | +} | |
| 200 | + | |
| 100 | 201 | Pdf * |
| 101 | 202 | pdfopen(Biobuf *b) |
| 102 | 203 | { |
| @@ -106,10 +207,10 @@ pdfopen(Biobuf *b) · 3 unmodified lines | ||
| 106 | 207 | int xref0; /* 7.5.4 xref subsection first object number */ |
| 107 | 208 | int nxref; /* 7.5.4 xref subsection number of objects */ |
| 108 | 209 | int xreftb; /* 7.5.4 xref table offset from the beginning of the file */ |
| 109 | − int i, n, off, w[3]; | |
| 110 | − Stream *stream; | |
| 210 | + int i, n, off; | |
| 111 | 211 | |
| 112 | 212 | fmtinstall('T', Tfmt); |
| 213 | + fmtinstall(L'⊗', ⊗fmt); | |
| 113 | 214 | |
| 114 | 215 | o = nil; |
| 115 | 216 | if((pdf = calloc(1, sizeof(*pdf))) == nil) |
| @@ -181,22 +282,14 @@ badxref: · 65 unmodified lines | ||
| 181 | 282 | goto err; |
| 182 | 283 | } |
| 183 | 284 | }else if(isdigit(tmp[0])){ /* could be 7.5.8 xref stream (since PDF 1.5) */ |
| 184 | − Bseek(b, xreftb, 0); | |
| 185 | − if((o = pdfobj(pdf, b)) == nil || (stream = streamopen(o)) == nil){ | |
| 186 | − werrstr("failed to stream xref: %r"); | |
| 187 | − goto badxref; | |
| 188 | − } | |
| 189 | − if(dictints(o, "W", w, nelem(w)) != 3){ | |
| 190 | − werrstr("W isn't 3 elements"); | |
| 285 | + if(Bseek(b, xreftb, 0) != xreftb) | |
| 191 | 286 | goto badxref; |
| 192 | − } | |
| 193 | − streamclose(stream); | |
| 194 | − pdf->root = dictget(o, "Root"); | |
| 195 | − pdf->info = dictget(o, "Info"); | |
| 287 | + if(xrefstreamread(pdf) != 0) | |
| 288 | + goto err; | |
| 196 | 289 | } |
| 197 | 290 | |
| 198 | 291 | /* root is required, info is optional */ |
| 199 | − if(pdf->root == nil){ | |
| 292 | + if(pdf->root == &null){ | |
| 200 | 293 | werrstr("no root"); |
| 201 | 294 | goto err; |
| 202 | 295 | } |
| @@ -8,6 +8,10 @@ enum { · 7 unmodified lines | ||
| 8 | 8 | Ostream, /* 7.3.8 */ |
| 9 | 9 | Onull, /* 7.3.9 */ |
| 10 | 10 | Oindir, /* 7.3.10 */ |
| 11 | + | |
| 12 | + Xusual = 0, | |
| 13 | + Xuncompressed, | |
| 14 | + Xcompressed, | |
| 11 | 15 | }; |
| 12 | 16 | |
| 13 | 17 | typedef struct Buffer Buffer; |
| @@ -19,7 +23,8 @@ typedef struct Stream Stream; · 5 unmodified lines | ||
| 19 | 23 | typedef struct Xref Xref; |
| 20 | 24 | #pragma incomplete Filter |
| 21 | 25 | |
| 22 | −#pragma varargck type "T" Object * | |
| 26 | +#pragma varargck type "T" Object* | |
| 27 | +#pragma varargck type "⊗" Xref | |
| 23 | 28 | |
| 24 | 29 | struct Buffer { |
| 25 | 30 | uchar *b; |
| @@ -30,6 +35,14 @@ struct Buffer { · 4 unmodified lines | ||
| 30 | 35 | int eof; |
| 31 | 36 | }; |
| 32 | 37 | |
| 38 | +struct Filter { | |
| 39 | + char *name; | |
| 40 | + int (*readall)(void *aux, Buffer *bi, Buffer *bo); | |
| 41 | + int (*open)(Filter *f, Object *o); | |
| 42 | + void (*close)(Filter *f); | |
| 43 | + void *aux; | |
| 44 | +}; | |
| 45 | + | |
| 33 | 46 | struct Object { |
| 34 | 47 | int type; |
| 35 | 48 | int ref; |
| @@ -83,8 +96,12 @@ struct Pdf { · 47 unmodified lines | ||
| 83 | 96 | |
| 84 | 97 | struct Xref { |
| 85 | 98 | u32int id; |
| 86 | − u32int off; | |
| 99 | + union{ | |
| 100 | + u32int off; | |
| 101 | + u32int objnum; | |
| 102 | + }; | |
| 87 | 103 | u16int gen; |
| 104 | + u16int type; | |
| 88 | 105 | }; |
| 89 | 106 | |
| 90 | 107 | struct Stream { |
| @@ -140,6 +157,7 @@ Object *dictdict(Object *o, char *name); · 49 unmodified lines | ||
| 140 | 157 | int dictints(Object *o, char *name, int *el, int nel); |
| 141 | 158 | |
| 142 | 159 | Stream *streamopen(Object *o); |
| 160 | +int streamsize(Stream *s); | |
| 143 | 161 | void streamclose(Stream *s); |
| 144 | 162 | |
| 145 | 163 | Filter *filteropen(char *name, Object *o); |
| @@ -149,6 +167,7 @@ void filterclose(Filter *f); · 3 unmodified lines | ||
| 149 | 167 | void bufinit(Buffer *b, uchar *d, int sz); |
| 150 | 168 | void buffree(Buffer *b); |
| 151 | 169 | int bufeof(Buffer *b); |
| 170 | +int bufleft(Buffer *b); | |
| 152 | 171 | uchar *bufdata(Buffer *b, int *sz); |
| 153 | 172 | int bufreadn(Buffer *b, Biobuf *bio, int sz); |
| 154 | 173 | int bufput(Buffer *b, uchar *d, int sz); |
| @@ -57,6 +57,8 @@ streamopen(Object *o) · 56 unmodified lines | ||
| 57 | 57 | buffree(&x); |
| 58 | 58 | goto err; |
| 59 | 59 | } |
| 60 | + if(!bufeof(&b)) | |
| 61 | + fprint(2, "buffer has %d bytes left\n", bufleft(&b)); | |
| 60 | 62 | buffree(&b); |
| 61 | 63 | b = x; |
| 62 | 64 | } |
| @@ -79,9 +81,18 @@ err: · 16 unmodified lines | ||
| 79 | 81 | return nil; |
| 80 | 82 | } |
| 81 | 83 | |
| 84 | +int | |
| 85 | +streamsize(Stream *s) | |
| 86 | +{ | |
| 87 | + return bufleft(&s->buf); | |
| 88 | +} | |
| 89 | + | |
| 82 | 90 | void |
| 83 | 91 | streamclose(Stream *s) |
| 84 | 92 | { |
| 93 | + if(s == nil) | |
| 94 | + return; | |
| 95 | + | |
| 85 | 96 | buffree(&s->buf); |
| 86 | 97 | Bterm(s->bio); |
| 87 | 98 | free(s); |