History

add and use flate filter

Sigrid Haflínudóttir committed 6 years ago

Commit a9516691 parent ef6cdd010 files · +400 −37Browse files

Unified · Split

10 files
  1. buffer.c +121 −0
  2. dict.c +1 −1
  3. f_flate.c +38 −0
  4. filter.c +69 −14
  5. main.c +1 −1
  6. mkfile +3 −0
  7. object.c +27 −2
  8. pdf.c +14 −13
  9. pdf.h +33 −6
  10. stream.c +93 −0
buffer.c+121−0
@@ -0,0 +1,121 @@
1+#include <u.h>
2+#include <libc.h>
3+#include <bio.h>
4+#include "pdf.h"
5+
6+static int
7+bufgrow(Buffer *b, int sz)
8+{
9+ uchar *r;
10+ int maxsz;
11+
12+ if(b->maxsz < 1){
13+ if((b->b = mallocz(128, 1)) == nil)
14+ return -1;
15+ b->maxsz = 128;
16+ }
17+ for(maxsz = b->maxsz; b->sz+sz > maxsz; maxsz *= 2);
18+ if(maxsz != b->maxsz){
19+ if((r = realloc(b->b, maxsz)) == nil)
20+ return -1;
21+ memset(r+b->maxsz, 0, maxsz-b->maxsz);
22+ b->b = r;
23+ b->maxsz = maxsz;
24+ }
25+
26+ return 0;
27+}
28+
29+void
30+bufinit(Buffer *b, uchar *d, int sz)
31+{
32+ memset(b, 0, sizeof(*b));
33+ if(d != nil){
34+ b->b = d;
35+ b->sz = sz;
36+ b->ro = 1;
37+ }
38+}
39+
40+void
41+buffree(Buffer *b)
42+{
43+ if(b->ro == 0)
44+ free(b->b);
45+}
46+
47+int
48+bufeof(Buffer *b)
49+{
50+ return b->off == b->sz;
51+}
52+
53+uchar *
54+bufdata(Buffer *b, int *sz)
55+{
56+ *sz = b->sz;
57+ return b->b;
58+}
59+
60+int
61+bufreadn(Buffer *b, void *bio, int sz)
62+{
63+ int n, end;
64+
65+ if(bufgrow(b, sz) != 0)
66+ return -1;
67+ for(end = b->sz+sz; b->sz < end; b->sz += n){
68+ if((n = Bread(bio, b->b+b->sz, sz)) < 1)
69+ return -1;
70+ sz -= n;
71+ }
72+ return 0;
73+}
74+
75+int
76+bufput(Buffer *b, uchar *d, int sz)
77+{
78+ if(b->ro)
79+ sysfatal("bufferput on readonly buffer");
80+ if(bufgrow(b, sz) != 0)
81+ return -1;
82+
83+ memmove(b->b+b->sz, d, sz);
84+ b->sz += sz;
85+
86+ return sz;
87+}
88+
89+int
90+bufget(Buffer *b, uchar *d, int sz)
91+{
92+ if(sz == 0)
93+ return 0;
94+
95+ if(b->off > b->sz)
96+ sysfatal("buffer: off(%d) > sz(%d)", b->off, b->sz);
97+ if(sz > b->sz - b->off)
98+ sz = b->sz - b->off;
99+ memmove(d, b->b+b->off, sz);
100+ b->off += sz;
101+ b->eof = sz == 0;
102+
103+ return sz;
104+}
105+
106+void
107+bufdump(Buffer *b)
108+{
109+ Biobuf bio;
110+ int i, j;
111+
112+ Binit(&bio, 2, OWRITE);
113+ Bprint(&bio, "%d bytes:\n", b->sz);
114+ for(i = 0; i < b->sz;){
115+ Bprint(&bio, "%04x\t", i);
116+ for(j = 0; i < b->sz && j < 16; j++, i++)
117+ Bprint(&bio, "%02x%s", b->b[i], (j+1)&7 ? " " : " ");
118+ Bprint(&bio, "\n");
119+ }
120+ Bterm(&bio);
121+}
dict.c+1−1
@@ -69,7 +69,7 @@ pdfdictget(Object *o, char *name) · 68 unmodified lines
6969 {
7070 int i;
7171
72− if(o == nil || o->type != Odict || name == nil)
72+ if(o == nil || (o->type != Ostream && o->type != Odict) || name == nil)
7373 return nil;
7474 for(i = 0; i < o->dict.nkv && strcmp(name, o->dict.kv[i].key) != 0; i++);
7575
f_flate.c+38−0
@@ -0,0 +1,38 @@
1+#include <u.h>
2+#include <libc.h>
3+#include <bio.h>
4+#include <flate.h>
5+#include "pdf.h"
6+
7+static int
8+bw(void *aux, void *d, int n)
9+{
10+ return bufput(aux, d, n);
11+}
12+
13+static int
14+bget(void *aux)
15+{
16+ uchar c;
17+
18+ return bufget(aux, &c, 1) == 1 ? c : -1;
19+}
20+
21+int
22+fFlate(void *aux, Buffer *bi, Buffer *bo)
23+{
24+ int r;
25+
26+ USED(aux);
27+
28+ do{
29+ r = inflatezlib(bo, bw, bi, bget);
30+ }while(r == FlateOk && !bufeof(bi));
31+
32+ if(r != FlateOk){
33+ werrstr("%s", flateerr(r));
34+ return -1;
35+ }
36+
37+ return 0;
38+}
filter.c+69−14
@@ -3,17 +3,72 @@ · 2 unmodified lines
33 #include <bio.h>
44 #include "pdf.h"
55
6−/*
7−7.4
8−
9−ASCIIHex
10−ASCII85
11−LZW
12−Flate
13−RunLength
14−CCITTFax
15−JBIG2
16−DCT
17−JPX
18−Crypt
19−*/
6+/* 7.4 Filters */
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+int fFlate(void *aux, Buffer *bi, Buffer *bo);
17+
18+static Filter filters[] = {
19+ {"ASCII85Decode", nil, nil, nil},
20+ {"ASCIIHexDecode", nil, nil, nil},
21+ {"CCITTFaxDecode", nil, nil, nil},
22+ {"CryptDecode", nil, nil, nil},
23+ {"DCTDecode", nil, nil, nil},
24+ {"FlateDecode", fFlate},
25+ {"JBIG2Decode", nil, nil, nil},
26+ {"JPXDecode", nil, nil, nil},
27+ {"LZWDecode", nil, nil, nil},
28+ {"RunLengthDecode", nil, nil, nil},
29+};
30+
31+Filter *
32+filteropen(char *name, Object *o)
33+{
34+ int i;
35+ Filter *f;
36+
37+ for(i = 0; i < nelem(filters) && strcmp(filters[i].name, name) != 0; i++);
38+ if(i >= nelem(filters)){
39+ werrstr("no such filter %q", name);
40+ return nil;
41+ }
42+ if(filters[i].readall == nil){
43+ werrstr("filter %q not implemented", name);
44+ return nil;
45+ }
46+ if((f = malloc(sizeof(*f))) == nil)
47+ return nil;
48+ memmove(f, &filters[i], sizeof(*f));
49+ if(f->open != nil && f->open(f, o) != 0){
50+ free(f);
51+ return nil;
52+ }
53+
54+ return f;
55+}
56+
57+int
58+filterrun(Filter *f, Buffer *bi, Buffer *bo)
59+{
60+ if(f->readall(f->aux, bi, bo) != 0){
61+ werrstr("filter[%s]: %r", f->name);
62+ return -1;
63+ }
64+ fprint(2, "filter[%s]: %d → %d %d\n", f->name, bi->sz, bo->sz, bo->off);
65+ return 0;
66+}
67+
68+void
69+filterclose(Filter *f)
70+{
71+ if(f->close != nil)
72+ f->close(f);
73+ free(f);
74+}
main.c+1−1
@@ -22,7 +22,7 @@ threadmain(int argc, char **argv) · 21 unmodified lines
2222 Object *v;
2323
2424 quotefmtinstall();
25− deflateinit();
25+ inflateinit();
2626
2727 ARGBEGIN{
2828 default:
mkfile+3−0
@@ -5,8 +5,10 @@ TARG=pdfs · 4 unmodified lines
55
66 OFILES=\
77 array.$O\
8+ buffer.$O\
89 dict.$O\
910 eval.$O\
11+ f_flate.$O\
1012 filter.$O\
1113 main.$O\
1214 misc.$O\
@@ -14,6 +16,7 @@ OFILES=\ · 1 unmodified line
1416 object.$O\
1517 pdf.$O\
1618 pdfs.$O\
19+ stream.$O\
1720 string.$O\
1821
1922 HFILES=\
object.c+27−2
@@ -13,6 +13,31 @@ static Object null = { · 12 unmodified lines
1313 .type = Onull,
1414 };
1515
16+static char *otypes[] = {
17+ [Obool] = "bool",
18+ [Onum] = "num",
19+ [Ostr] = "str",
20+ [Oname] = "name",
21+ [Oarray] = "array",
22+ [Odict] = "dict",
23+ [Ostream] = "stream",
24+ [Onull] = "null",
25+ [Oindir] = "indir",
26+};
27+
28+int
29+Tfmt(Fmt *f)
30+{
31+ Object *o;
32+
33+ o = va_arg(f->args, Object*);
34+ if(o == nil || o == &null)
35+ return fmtprint(f, "null");
36+ if(o->type < 0 || o->type >= nelem(otypes))
37+ return fmtprint(f, "????");
38+ return fmtprint(f, "%s", otypes[o->type]);
39+}
40+
1641 /* General function to parse an object of any type. */
1742 Object *
1843 pdfobj(Pdf *pdf, void *b)
@@ -49,8 +74,8 @@ pdfobj(Pdf *pdf, void *b) · 30 unmodified lines
4974 goto err;
5075 }
5176 o->type = Ostream;
52− o->stream.length = m->num;
53− o->stream.offset = Boffset(b);
77+ o->stream.len = m->num;
78+ o->stream.off = Boffset(b);
5479 return o;
5580 }
5681 Bseek(b, off, 0);
pdf.c+14−13
@@ -75,9 +75,7 @@ err: · 74 unmodified lines
7575 static int
7676 trailerread(Pdf *pdf)
7777 {
78− int i;
7978 Object *o;
80− KeyValue *kv;
8179
8280 if((o = pdfobj(pdf, pdf->bio)) == nil)
8381 goto err;
@@ -87,12 +85,8 @@ trailerread(Pdf *pdf) · 3 unmodified lines
8785 goto err;
8886 }
8987
90− for(i = 0, kv = o->dict.kv; i < o->dict.nkv; i++, kv++){
91− if(strcmp(kv->key, "Root") == 0)
92− pdf->root = kv->value;
93− else if(strcmp(kv->key, "Info") == 0)
94− pdf->info = kv->value;
95− }
88+ pdf->root = pdfdictget(o, "Root");
89+ pdf->info = pdfdictget(o, "Info");
9690 pdfobjfree(o);
9791 o = nil;
9892
@@ -101,8 +95,6 @@ trailerread(Pdf *pdf) · 2 unmodified lines
10195 werrstr("no root");
10296 goto err;
10397 }
104− if(pdfeval(pdf, pdf->root) != 0 || pdfeval(pdf, pdf->info) != 0)
105− goto err;
10698
10799 return 0;
108100 err:
@@ -121,6 +113,9 @@ pdfopen(int fd) · 12 unmodified lines
121113 int nxref; /* 7.5.4 xref subsection number of objects */
122114 int xreftb; /* 7.5.4 xref table offset from the beginning of the file */
123115 int i, n, off;
116+ Stream *stream;
117+
118+ fmtinstall('T', Tfmt);
124119
125120 b = nil;
126121 o = nil;
@@ -196,10 +191,16 @@ badxref: · 69 unmodified lines
196191 }
197192 }else if(isdigit(tmp[0])){ /* could be 7.5.8 xref stream (since PDF 1.5) */
198193 Bseek(b, xreftb, 0);
199− if((o = pdfobj(pdf, b)) == nil || pdfeval(pdf, o) != 0)
200− goto err;
201−
194+ if((o = pdfobj(pdf, b)) == nil || (stream = streamopen(pdf, o)) == nil)
195+ goto badxref;
196+ streamclose(stream);
197+ pdf->root = pdfdictget(o, "Root");
198+ pdf->info = pdfdictget(o, "Info");
202199 }
200+ if(pdfeval(pdf, pdf->root) != 0 || pdfeval(pdf, pdf->info) != 0)
201+ goto err;
202+ fprint(2, "root %T\n", pdf->root);
203+ fprint(2, "info %T\n", pdf->info);
203204
204205 return pdf;
205206 err:
pdf.h+33−6
@@ -10,11 +10,23 @@ enum { · 9 unmodified lines
1010 Oindir, /* 7.3.10 */
1111 };
1212
13+typedef struct Buffer Buffer;
14+typedef struct Filter Filter;
1315 typedef struct KeyValue KeyValue;
1416 typedef struct Object Object;
1517 typedef struct Pdf Pdf;
16−typedef struct Xref Xref;
1718 typedef struct Stream Stream;
19+typedef struct Xref Xref;
20+#pragma incomplete Filter
21+
22+struct Buffer {
23+ uchar *b;
24+ int ro;
25+ int maxsz;
26+ int sz;
27+ int off;
28+ int eof;
29+};
1830
1931 struct Object {
2032 int type;
@@ -45,8 +57,8 @@ struct Object { · 24 unmodified lines
4557 struct {
4658 KeyValue *kv;
4759 int nkv;
48− u32int length; /* packed */
49− u32int offset;
60+ u32int len; /* packed */
61+ u32int off;
5062 }stream;
5163 };
5264 };
@@ -72,9 +84,8 @@ struct Xref { · 19 unmodified lines
7284 };
7385
7486 struct Stream {
75− Biobuf;
76− Object *o;
77− u32int offset;
87+ Buffer buf;
88+ void *bio;
7889 };
7990
8091 Pdf *pdfopen(int fd);
@@ -96,3 +107,19 @@ Object *pdfdictget(Object *o, char *name); · 15 unmodified lines
96107
97108 Stream *streamopen(Pdf *pdf, Object *o);
98109 void streamclose(Stream *s);
110+
111+Filter *filteropen(char *name, Object *o);
112+int filterrun(Filter *f, Buffer *bi, Buffer *bo);
113+void filterclose(Filter *f);
114+
115+void bufinit(Buffer *b, uchar *d, int sz);
116+void buffree(Buffer *b);
117+int bufeof(Buffer *b);
118+uchar *bufdata(Buffer *b, int *sz);
119+int bufreadn(Buffer *b, void *bio, int sz);
120+int bufput(Buffer *b, uchar *d, int sz);
121+int bufget(Buffer *b, uchar *d, int sz);
122+void bufdump(Buffer *b);
123+
124+#pragma varargck type "T" Object *
125+int Tfmt(Fmt *f);
stream.c+93−0
@@ -0,0 +1,93 @@
1+#include <u.h>
2+#include <libc.h>
3+#include <bio.h>
4+#include "pdf.h"
5+
6+static int
7+bufiof(Biobufhdr *b, void *data, long n)
8+{
9+ Stream *s;
10+
11+ s = (void*)((char*)b - sizeof(*s));
12+
13+ return bufget(&s->buf, data, n);
14+}
15+
16+Stream *
17+streamopen(Pdf *pdf, Object *o)
18+{
19+ Stream *s;
20+ Buffer b, x;
21+ Object *of, **flts;
22+ Filter *f;
23+ int i, nflts;
24+
25+ s = nil;
26+ if(pdfeval(pdf, o) != 0 || o == nil || o->type != Ostream) /* FIXME open a string object as a stream as well? */
27+ return nil;
28+
29+ bufinit(&b, nil, 0);
30+ if(Bseek(pdf->bio, o->stream.off, 0) != o->stream.off)
31+ return nil;
32+ if(bufreadn(&b, pdf->bio, o->stream.len) < 0)
33+ goto err;
34+ bufdump(&b);
35+
36+ /* see if there are any filters */
37+ if((of = pdfdictget(o, "Filter")) != nil){
38+ if(pdfeval(pdf, of) != 0)
39+ goto err;
40+ if(of->type == Oname){ /* one filter */
41+ flts = &of;
42+ nflts = 1;
43+ }else if(of->type == Oarray){ /* array of filters */
44+ flts = of->array.e;
45+ nflts = of->array.ne;
46+ }else{
47+ werrstr("filters type invalid (%T)", of);
48+ goto err;
49+ }
50+
51+ for(i = nflts-1; i >= 0; i--){
52+ if(flts[i]->type != Oname){
53+ werrstr("filter type invalid (%T)", flts[i]);
54+ goto err;
55+ }
56+ if((f = filteropen(flts[i]->name, o)) == nil)
57+ goto err;
58+ bufinit(&x, nil, 0);
59+ if(filterrun(f, &b, &x) != 0){
60+ buffree(&x);
61+ goto err;
62+ }
63+ buffree(&b);
64+ b = x;
65+ }
66+ }
67+
68+ if((s = calloc(1, sizeof(*s)+sizeof(Biobuf))) == nil){
69+ buffree(&b);
70+ return nil;
71+ }
72+ s->bio = (uchar*)(s+1);
73+ s->buf = b;
74+ Binit(s->bio, Bfildes(pdf->bio), OREAD);
75+ Biofn(s->bio, bufiof);
76+
77+ bufdump(&s->buf);
78+
79+ return s;
80+err:
81+ werrstr("stream: %r");
82+ buffree(&b);
83+ free(s);
84+ return nil;
85+}
86+
87+void
88+streamclose(Stream *s)
89+{
90+ buffree(&s->buf);
91+ Bterm(s->bio);
92+ free(s);
93+}

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