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
6static int
7bufgrow(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
29void
30bufinit(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
40void
41buffree(Buffer *b)
42{
43 if(b->ro == 0)
44 free(b->b);
45}
46
47int
48bufeof(Buffer *b)
49{
50 return b->off == b->sz;
51}
52
53uchar *
54bufdata(Buffer *b, int *sz)
55{
56 *sz = b->sz;
57 return b->b;
58}
59
60int
61bufreadn(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
75int
76bufput(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
89int
90bufget(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
106void
107bufdump(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
69{69{
70 int i;70 int i;
71 71
72 if(o == nil || o->type != Odict || name == nil)72 if(o == nil || (o->type != Ostream && o->type != Odict) || name == nil)
73 return nil;73 return nil;
74 for(i = 0; i < o->dict.nkv && strcmp(name, o->dict.kv[i].key) != 0; i++);74 for(i = 0; i < o->dict.nkv && strcmp(name, o->dict.kv[i].key) != 0; i++);
75 75
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
7static int
8bw(void *aux, void *d, int n)
9{
10 return bufput(aux, d, n);
11}
12
13static int
14bget(void *aux)
15{
16 uchar c;
17
18 return bufget(aux, &c, 1) == 1 ? c : -1;
19}
20
21int
22fFlate(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
3#include <bio.h>3#include <bio.h>
4#include "pdf.h"4#include "pdf.h"
5 5
6/*6/* 7.4 Filters */
77.47
8 8struct Filter {
9ASCIIHex9 char *name;
10ASCII8510 int (*readall)(void *aux, Buffer *bi, Buffer *bo);
11LZW11 int (*open)(Filter *f, Object *o);
12Flate12 void (*close)(Filter *f);
13RunLength13 void *aux;
14CCITTFax14};
15JBIG215
16DCT16int fFlate(void *aux, Buffer *bi, Buffer *bo);
17JPX17
18Crypt18static Filter filters[] = {
19*/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
31Filter *
32filteropen(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
57int
58filterrun(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
68void
69filterclose(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
22 Object *v;22 Object *v;
23 23
24 quotefmtinstall();24 quotefmtinstall();
25 deflateinit();25 inflateinit();
26 26
27 ARGBEGIN{27 ARGBEGIN{
28 default:28 default:
mkfile+3−0
@@ -5,8 +5,10 @@ TARG=pdfs · 4 unmodified lines
5 5
6OFILES=\6OFILES=\
7 array.$O\7 array.$O\
8 buffer.$O\
8 dict.$O\9 dict.$O\
9 eval.$O\10 eval.$O\
11 f_flate.$O\
10 filter.$O\12 filter.$O\
11 main.$O\13 main.$O\
12 misc.$O\14 misc.$O\
@@ -14,6 +16,7 @@ OFILES=\ · 1 unmodified line
14 object.$O\16 object.$O\
15 pdf.$O\17 pdf.$O\
16 pdfs.$O\18 pdfs.$O\
19 stream.$O\
17 string.$O\20 string.$O\
18 21
19HFILES=\22HFILES=\
object.c+27−2
@@ -13,6 +13,31 @@ static Object null = { · 12 unmodified lines
13 .type = Onull,13 .type = Onull,
14};14};
15 15
16static 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
28int
29Tfmt(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
16/* General function to parse an object of any type. */41/* General function to parse an object of any type. */
17Object *42Object *
18pdfobj(Pdf *pdf, void *b)43pdfobj(Pdf *pdf, void *b)
@@ -49,8 +74,8 @@ pdfobj(Pdf *pdf, void *b) · 30 unmodified lines
49 goto err;74 goto err;
50 }75 }
51 o->type = Ostream;76 o->type = Ostream;
52 o->stream.length = m->num;77 o->stream.len = m->num;
53 o->stream.offset = Boffset(b);78 o->stream.off = Boffset(b);
54 return o;79 return o;
55 }80 }
56 Bseek(b, off, 0);81 Bseek(b, off, 0);
pdf.c+14−13
@@ -75,9 +75,7 @@ err: · 74 unmodified lines
75static int75static int
76trailerread(Pdf *pdf)76trailerread(Pdf *pdf)
77{77{
78 int i;
79 Object *o;78 Object *o;
80 KeyValue *kv;
81 79
82 if((o = pdfobj(pdf, pdf->bio)) == nil)80 if((o = pdfobj(pdf, pdf->bio)) == nil)
83 goto err;81 goto err;
@@ -87,12 +85,8 @@ trailerread(Pdf *pdf) · 3 unmodified lines
87 goto err;85 goto err;
88 }86 }
89 87
90 for(i = 0, kv = o->dict.kv; i < o->dict.nkv; i++, kv++){88 pdf->root = pdfdictget(o, "Root");
91 if(strcmp(kv->key, "Root") == 0)89 pdf->info = pdfdictget(o, "Info");
92 pdf->root = kv->value;
93 else if(strcmp(kv->key, "Info") == 0)
94 pdf->info = kv->value;
95 }
96 pdfobjfree(o);90 pdfobjfree(o);
97 o = nil;91 o = nil;
98 92
@@ -101,8 +95,6 @@ trailerread(Pdf *pdf) · 2 unmodified lines
101 werrstr("no root");95 werrstr("no root");
102 goto err;96 goto err;
103 }97 }
104 if(pdfeval(pdf, pdf->root) != 0 || pdfeval(pdf, pdf->info) != 0)
105 goto err;
106 98
107 return 0;99 return 0;
108err:100err:
@@ -121,6 +113,9 @@ pdfopen(int fd) · 12 unmodified lines
121 int nxref; /* 7.5.4 xref subsection number of objects */113 int nxref; /* 7.5.4 xref subsection number of objects */
122 int xreftb; /* 7.5.4 xref table offset from the beginning of the file */114 int xreftb; /* 7.5.4 xref table offset from the beginning of the file */
123 int i, n, off;115 int i, n, off;
116 Stream *stream;
117
118 fmtinstall('T', Tfmt);
124 119
125 b = nil;120 b = nil;
126 o = nil;121 o = nil;
@@ -196,10 +191,16 @@ badxref: · 69 unmodified lines
196 }191 }
197 }else if(isdigit(tmp[0])){ /* could be 7.5.8 xref stream (since PDF 1.5) */192 }else if(isdigit(tmp[0])){ /* could be 7.5.8 xref stream (since PDF 1.5) */
198 Bseek(b, xreftb, 0);193 Bseek(b, xreftb, 0);
199 if((o = pdfobj(pdf, b)) == nil || pdfeval(pdf, o) != 0)194 if((o = pdfobj(pdf, b)) == nil || (stream = streamopen(pdf, o)) == nil)
200 goto err;195 goto badxref;
201 196 streamclose(stream);
197 pdf->root = pdfdictget(o, "Root");
198 pdf->info = pdfdictget(o, "Info");
202 }199 }
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);
203 204
204 return pdf;205 return pdf;
205err:206err:
pdf.h+33−6
@@ -10,11 +10,23 @@ enum { · 9 unmodified lines
10 Oindir, /* 7.3.10 */10 Oindir, /* 7.3.10 */
11};11};
12 12
13typedef struct Buffer Buffer;
14typedef struct Filter Filter;
13typedef struct KeyValue KeyValue;15typedef struct KeyValue KeyValue;
14typedef struct Object Object;16typedef struct Object Object;
15typedef struct Pdf Pdf;17typedef struct Pdf Pdf;
16typedef struct Xref Xref;
17typedef struct Stream Stream;18typedef struct Stream Stream;
19typedef struct Xref Xref;
20#pragma incomplete Filter
21
22struct Buffer {
23 uchar *b;
24 int ro;
25 int maxsz;
26 int sz;
27 int off;
28 int eof;
29};
18 30
19struct Object {31struct Object {
20 int type;32 int type;
@@ -45,8 +57,8 @@ struct Object { · 24 unmodified lines
45 struct {57 struct {
46 KeyValue *kv;58 KeyValue *kv;
47 int nkv;59 int nkv;
48 u32int length; /* packed */60 u32int len; /* packed */
49 u32int offset;61 u32int off;
50 }stream;62 }stream;
51 };63 };
52};64};
@@ -72,9 +84,8 @@ struct Xref { · 19 unmodified lines
72};84};
73 85
74struct Stream {86struct Stream {
75 Biobuf;87 Buffer buf;
76 Object *o;88 void *bio;
77 u32int offset;
78};89};
79 90
80Pdf *pdfopen(int fd);91Pdf *pdfopen(int fd);
@@ -96,3 +107,19 @@ Object *pdfdictget(Object *o, char *name); · 15 unmodified lines
96 107
97Stream *streamopen(Pdf *pdf, Object *o);108Stream *streamopen(Pdf *pdf, Object *o);
98void streamclose(Stream *s);109void streamclose(Stream *s);
110
111Filter *filteropen(char *name, Object *o);
112int filterrun(Filter *f, Buffer *bi, Buffer *bo);
113void filterclose(Filter *f);
114
115void bufinit(Buffer *b, uchar *d, int sz);
116void buffree(Buffer *b);
117int bufeof(Buffer *b);
118uchar *bufdata(Buffer *b, int *sz);
119int bufreadn(Buffer *b, void *bio, int sz);
120int bufput(Buffer *b, uchar *d, int sz);
121int bufget(Buffer *b, uchar *d, int sz);
122void bufdump(Buffer *b);
123
124#pragma varargck type "T" Object *
125int 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
6static int
7bufiof(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
16Stream *
17streamopen(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;
80err:
81 werrstr("stream: %r");
82 buffree(&b);
83 free(s);
84 return nil;
85}
86
87void
88streamclose(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