History

fix flate-encoded streams with PNG prediction; parse compressed xref streams

Sigrid Haflínudóttir committed 6 years ago

Commit b4e6b3b1 parent ecd40a87 files · +292 −28Browse files

Unified · Split

7 files
  1. buffer.c +7 −1
  2. f_flate.c +119 −2
  3. filter.c +3 −9
  4. misc.c +24 −0
  5. pdf.c +107 −14
  6. pdf.h +21 −2
  7. stream.c +11 −0
buffer.c+7−1
@@ -47,7 +47,13 @@ buffree(Buffer *b) · 46 unmodified lines
47int47int
48bufeof(Buffer *b)48bufeof(Buffer *b)
49{49{
50 return b->off == b->sz;50 return bufleft(b) == 0;
51}
52
53int
54bufleft(Buffer *b)
55{
56 return b->sz - b->off;
51}57}
52 58
53uchar *59uchar *
f_flate.c+119−2
@@ -4,6 +4,69 @@ · 3 unmodified lines
4#include <flate.h>4#include <flate.h>
5#include "pdf.h"5#include "pdf.h"
6 6
7typedef struct FlateParms FlateParms;
8
9struct FlateParms {
10 int predictor;
11 int columns;
12};
13
14static uchar
15paeth(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
29static int
30pngunpredict(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
7static int70static int
8bw(void *aux, void *d, int n)71bw(void *aux, void *d, int n)
9{72{
@@ -21,9 +84,11 @@ bget(void *aux) · 11 unmodified lines
21int84int
22fFlate(void *aux, Buffer *bi, Buffer *bo)85fFlate(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 do{93 do{
29 r = inflatezlib(bo, bw, bi, bget);94 r = inflatezlib(bo, bw, bi, bget);
@@ -34,5 +99,57 @@ fFlate(void *aux, Buffer *bi, Buffer *bo) · 4 unmodified lines
34 return -1;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
123int
124openFlate(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 return 0;148 return 0;
38}149}
150
151void
152closeFlate(Filter *f)
153{
154 free(f->aux);
155}
filter.c+3−9
@@ -5,15 +5,9 @@ · 4 unmodified lines
5 5
6/* 7.4 Filters */6/* 7.4 Filters */
7 7
8struct 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
16int fFlate(void *aux, Buffer *bi, Buffer *bo);8int fFlate(void *aux, Buffer *bi, Buffer *bo);
9int openFlate(Filter *f, Object *o);
10void closeFlate(Filter *f);
17 11
18static Filter filters[] = {12static Filter filters[] = {
19 {"ASCII85Decode", nil, nil, nil},13 {"ASCII85Decode", nil, nil, nil},
@@ -21,7 +15,7 @@ static Filter filters[] = { · 1 unmodified line
21 {"CCITTFaxDecode", nil, nil, nil},15 {"CCITTFaxDecode", nil, nil, nil},
22 {"CryptDecode", nil, nil, nil},16 {"CryptDecode", nil, nil, nil},
23 {"DCTDecode", nil, nil, nil},17 {"DCTDecode", nil, nil, nil},
24 {"FlateDecode", fFlate},18 {"FlateDecode", fFlate, openFlate, closeFlate},
25 {"JBIG2Decode", nil, nil, nil},19 {"JBIG2Decode", nil, nil, nil},
26 {"JPXDecode", nil, nil, nil},20 {"JPXDecode", nil, nil, nil},
27 {"LZWDecode", nil, nil, nil},21 {"LZWDecode", nil, nil, nil},
misc.c+24−0
@@ -15,6 +15,12 @@ static char *otypes[] = { · 14 unmodified lines
15 [Oindir] = "indir",15 [Oindir] = "indir",
16};16};
17 17
18static char *xtypes[] = {
19 [Xusual] = "usual",
20 [Xuncompressed] = "uncompressed",
21 [Xcompressed] = "compressed",
22};
23
18Object null = {24Object null = {
19 .type = Onull,25 .type = Onull,
20};26};
@@ -32,6 +38,24 @@ Tfmt(Fmt *f) · 11 unmodified lines
32 return fmtprint(f, "%s", otypes[o->type]);38 return fmtprint(f, "%s", otypes[o->type]);
33}39}
34 40
41int
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
35int59int
36isws(int c)60isws(int c)
37{61{
pdf.c+107−14
@@ -5,6 +5,7 @@ · 4 unmodified lines
5#include "pdf.h"5#include "pdf.h"
6 6
7int Tfmt(Fmt *f);7int Tfmt(Fmt *f);
8int ⊗fmt(Fmt *f);
8 9
9/*10/*
10 * pre-1.5 xref section reader11 * pre-1.5 xref section reader
@@ -41,6 +42,8 @@ xrefread(Pdf *pdf, int xref0, int nxref) · 30 unmodified lines
41 }42 }
42 xref.id = xref0 + i;43 xref.id = xref0 + i;
43 xref.off = strtoul(e, nil, 10);44 xref.off = strtoul(e, nil, 10);
45 /* FIXME xref.gen */
46 xref.type = Xusual;
44 47
45 /* search in already existing xrefs, update if found */48 /* search in already existing xrefs, update if found */
46 for(j = 0; j < pdf->nxref; j++){49 for(j = 0; j < pdf->nxref; j++){
@@ -97,6 +100,104 @@ err: · 50 unmodified lines
97 return -1;100 return -1;
98}101}
99 102
103static int
104getint(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 */
118static int
119xrefstreamread(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;
195err:
196 streamclose(s);
197 pdfobjfree(o);
198 return -1;
199}
200
100Pdf *201Pdf *
101pdfopen(Biobuf *b)202pdfopen(Biobuf *b)
102{203{
@@ -106,10 +207,10 @@ pdfopen(Biobuf *b) · 3 unmodified lines
106 int xref0; /* 7.5.4 xref subsection first object number */207 int xref0; /* 7.5.4 xref subsection first object number */
107 int nxref; /* 7.5.4 xref subsection number of objects */208 int nxref; /* 7.5.4 xref subsection number of objects */
108 int xreftb; /* 7.5.4 xref table offset from the beginning of the file */209 int xreftb; /* 7.5.4 xref table offset from the beginning of the file */
109 int i, n, off, w[3];210 int i, n, off;
110 Stream *stream;
111 211
112 fmtinstall('T', Tfmt);212 fmtinstall('T', Tfmt);
213 fmtinstall(L'⊗', ⊗fmt);
113 214
114 o = nil;215 o = nil;
115 if((pdf = calloc(1, sizeof(*pdf))) == nil)216 if((pdf = calloc(1, sizeof(*pdf))) == nil)
@@ -181,22 +282,14 @@ badxref: · 65 unmodified lines
181 goto err;282 goto err;
182 }283 }
183 }else if(isdigit(tmp[0])){ /* could be 7.5.8 xref stream (since PDF 1.5) */284 }else if(isdigit(tmp[0])){ /* could be 7.5.8 xref stream (since PDF 1.5) */
184 Bseek(b, xreftb, 0);285 if(Bseek(b, xreftb, 0) != xreftb)
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");
191 goto badxref;286 goto badxref;
192 }287 if(xrefstreamread(pdf) != 0)
193 streamclose(stream);288 goto err;
194 pdf->root = dictget(o, "Root");
195 pdf->info = dictget(o, "Info");
196 }289 }
197 290
198 /* root is required, info is optional */291 /* root is required, info is optional */
199 if(pdf->root == nil){292 if(pdf->root == &null){
200 werrstr("no root");293 werrstr("no root");
201 goto err;294 goto err;
202 }295 }
pdf.h+21−2
@@ -8,6 +8,10 @@ enum { · 7 unmodified lines
8 Ostream, /* 7.3.8 */8 Ostream, /* 7.3.8 */
9 Onull, /* 7.3.9 */9 Onull, /* 7.3.9 */
10 Oindir, /* 7.3.10 */10 Oindir, /* 7.3.10 */
11
12 Xusual = 0,
13 Xuncompressed,
14 Xcompressed,
11};15};
12 16
13typedef struct Buffer Buffer;17typedef struct Buffer Buffer;
@@ -19,7 +23,8 @@ typedef struct Stream Stream; · 5 unmodified lines
19typedef struct Xref Xref;23typedef struct Xref Xref;
20#pragma incomplete Filter24#pragma incomplete Filter
21 25
22#pragma varargck type "T" Object *26#pragma varargck type "T" Object*
27#pragma varargck type "⊗" Xref
23 28
24struct Buffer {29struct Buffer {
25 uchar *b;30 uchar *b;
@@ -30,6 +35,14 @@ struct Buffer { · 4 unmodified lines
30 int eof;35 int eof;
31};36};
32 37
38struct 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
33struct Object {46struct Object {
34 int type;47 int type;
35 int ref;48 int ref;
@@ -83,8 +96,12 @@ struct Pdf { · 47 unmodified lines
83 96
84struct Xref {97struct Xref {
85 u32int id;98 u32int id;
86 u32int off;99 union{
100 u32int off;
101 u32int objnum;
102 };
87 u16int gen;103 u16int gen;
104 u16int type;
88};105};
89 106
90struct Stream {107struct Stream {
@@ -140,6 +157,7 @@ Object *dictdict(Object *o, char *name); · 49 unmodified lines
140int dictints(Object *o, char *name, int *el, int nel);157int dictints(Object *o, char *name, int *el, int nel);
141 158
142Stream *streamopen(Object *o);159Stream *streamopen(Object *o);
160int streamsize(Stream *s);
143void streamclose(Stream *s);161void streamclose(Stream *s);
144 162
145Filter *filteropen(char *name, Object *o);163Filter *filteropen(char *name, Object *o);
@@ -149,6 +167,7 @@ void filterclose(Filter *f); · 3 unmodified lines
149void bufinit(Buffer *b, uchar *d, int sz);167void bufinit(Buffer *b, uchar *d, int sz);
150void buffree(Buffer *b);168void buffree(Buffer *b);
151int bufeof(Buffer *b);169int bufeof(Buffer *b);
170int bufleft(Buffer *b);
152uchar *bufdata(Buffer *b, int *sz);171uchar *bufdata(Buffer *b, int *sz);
153int bufreadn(Buffer *b, Biobuf *bio, int sz);172int bufreadn(Buffer *b, Biobuf *bio, int sz);
154int bufput(Buffer *b, uchar *d, int sz);173int bufput(Buffer *b, uchar *d, int sz);
stream.c+11−0
@@ -57,6 +57,8 @@ streamopen(Object *o) · 56 unmodified lines
57 buffree(&x);57 buffree(&x);
58 goto err;58 goto err;
59 }59 }
60 if(!bufeof(&b))
61 fprint(2, "buffer has %d bytes left\n", bufleft(&b));
60 buffree(&b);62 buffree(&b);
61 b = x;63 b = x;
62 }64 }
@@ -79,9 +81,18 @@ err: · 16 unmodified lines
79 return nil;81 return nil;
80}82}
81 83
84int
85streamsize(Stream *s)
86{
87 return bufleft(&s->buf);
88}
89
82void90void
83streamclose(Stream *s)91streamclose(Stream *s)
84{92{
93 if(s == nil)
94 return;
95
85 buffree(&s->buf);96 buffree(&s->buf);
86 Bterm(s->bio);97 Bterm(s->bio);
87 free(s);98 free(s);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t