History

rewrite the API, support more object types and actual evaluation

Sigrid Haflínudóttir committed 6 years ago

Commit a080ae81 parent 34238e011 files · +494 −376Browse files

Unified · Split

11 files
  1. array.c +21 −24
  2. dict.c +41 −34
  3. eval.c +18 −7
  4. filter.c +1 −0
  5. main.c +9 −1
  6. misc.c +3 −2
  7. name.c +93 −65
  8. object.c +128 −68
  9. pdf.c +5 −9
  10. pdf.h +12 −38
  11. string.c +163 −128
array.c+21−24
@@ -1,40 +1,34 @@
11 #include <u.h>
22 #include <libc.h>
3−#include <ctype.h>
3+#include <bio.h>
44 #include "pdf.h"
55
6+/* 7.3.6 Array Objects */
7+
68 Object *
7−pdfarray(char *p, char **e, int len)
9+pdfarray(Biobuf *b)
810 {
911 Object *o, *m;
1012 Object **a;
11−
12− o = nil;
13− if(len < 3 || p[0] != '['){
14− werrstr("invalid array");
15− goto err;
16− }
17− p++;
18− len--;
13+ int c, noel;
1914
2015 o = calloc(1, sizeof(*o));
2116 o->type = Oarray;
22− for(; len >= 1;){
23− for(; len > 0 && isws(*p); p++, len--);
24− if(len < 1){
25− werrstr("too short");
26− goto err;
27− }
17+ Bgetc(b); /* throw away '[' */
2818
29− if(p[0] == ']'){
30− p++;
19+ for(noel = 0;;){
20+ if((c = Bgetc(b)) < 0 || c == ']')
3121 break;
22+ if(noel){
23+ werrstr("no ']'");
24+ goto err;
3225 }
3326
34− if((m = pdfobject(p, e, len)) == nil)
35− goto err;
36− len -= *e - p;
37− p = *e;
27+ Bungetc(b);
28+ if((m = pdfobject(b)) == nil){
29+ noel = 1;
30+ continue;
31+ }
3832
3933 if((a = realloc(o->array.e, (o->array.ne+1)*sizeof(Object*))) == nil){
4034 freeobject(m);
@@ -45,11 +39,14 @@ pdfarray(char *p, char **e, int len) · 4 unmodified lines
4539 a[o->array.ne++] = m;
4640 }
4741
48− *e = p;
42+ if(c != ']'){
43+ werrstr("no ']'");
44+ goto err;
45+ }
4946
5047 return o;
5148 err:
49+ werrstr("array: %r");
5250 freeobject(o);
53−
5451 return nil;
5552 }
dict.c+41−34
@@ -1,70 +1,77 @@
11 #include <u.h>
22 #include <libc.h>
3−#include <ctype.h>
3+#include <bio.h>
44 #include "pdf.h"
55
6+/* 7.3.7 Dictionary Objects */
7+
68 Object *
7−pdfdict(char *p, char **e, int len)
9+pdfdict(Biobuf *b)
810 {
911 Object *o, *k, *v;
1012 KeyValue *kv;
13+ int c, nokey;
1114
12− o = nil;
13− if(len < 4 || p[0] != '<' || p[1] != '<'){
14− werrstr("invalid dict");
15− goto err;
16− }
17− p += 2;
18− len -= 2;
15+ /* skip '<<' */
16+ Bseek(b, 2, 1);
1917
18+ k = v = nil;
2019 o = calloc(1, sizeof(*o));
2120 o->type = Odict;
22− for(; len >= 2;){
23− for(; len > 2 && isws(*p); p++, len--);
24− if(len < 1){
25− werrstr("too short");
21+ for(nokey = 0;;){
22+ if((c = Bgetc(b)) < 0)
23+ goto err;
24+ if(c == '>'){
25+ if(Bgetc(b) == '>')
26+ break;
27+ werrstr("no '>>'");
2628 goto err;
2729 }
28−
29− if(p[0] == '>' && p[1] == '>'){
30− p += 2;
31− break;
30+ if(nokey){
31+ werrstr("no '>>'");
32+ goto err;
3233 }
3334
34− if((k = pdfobject(p, e, len)) == nil)
35+ Bungetc(b);
36+ if((k = pdfobject(b)) == nil){
37+ nokey = 1;
38+ continue;
39+ }
40+ if((v = pdfobject(b)) == nil)
3541 goto err;
3642 if(k->type != Oname){
37− freeobject(k);
3843 werrstr("expected name as a key");
3944 goto err;
4045 }
41− len -= *e - p;
42− p = *e;
4346
44− if((v = pdfobject(p, e, len)) == nil){
45− freeobject(k);
47+ if((kv = realloc(o->dict.kv, (o->dict.nkv+1)*sizeof(KeyValue))) == nil)
4648 goto err;
47− }
48− len -= *e - p;
49− p = *e;
50−
51− if((kv = realloc(o->dict.kv, (o->dict.nkv+1)*sizeof(KeyValue))) == nil){
52− freeobject(k);
53− freeobject(v);
54− goto err;
55− }
5649
5750 o->dict.kv = kv;
5851 kv[o->dict.nkv].key = strdup(k->name);
5952 freeobject(k);
6053 kv[o->dict.nkv++].value = v;
54+ k = v = nil;
6155 }
6256
63− *e = p;
64−
6557 return o;
6658 err:
6759 freeobject(o);
60+ freeobject(k);
61+ freeobject(v);
62+ werrstr("dict: %r");
6863
6964 return nil;
7065 }
66+
67+Object *
68+pdfdictget(Object *o, char *name)
69+{
70+ int i;
71+
72+ if(o == nil || o->type != Odict || name == nil)
73+ return nil;
74+ for(i = 0; i < o->dict.nkv && strcmp(name, o->dict.kv[i].key) != 0; i++);
75+
76+ return i < o->dict.nkv ? o->dict.kv[i].value : nil;
77+}
eval.c+18−7
@@ -1,23 +1,34 @@
11 #include <u.h>
22 #include <libc.h>
3+#include <bio.h>
34 #include "pdf.h"
45
56 int
67 pdfeval(Pdf *pdf, Object *o)
78 {
9+ Object *d;
810 Xref *x;
911 int i;
1012
11− if(o->type != Oindir)
13+ if(o == nil || o->type != Oindir)
1214 return 0;
1315
14− for(i = 0; i < pdf->nxref; i++){
15− x = &pdf->xref[i];
16− if(x->id == o->indir.id)
17− return 0;
16+ for(i = 0; i < pdf->nxref && pdf->xref[i].id != o->indir.id; i++);
17+ if(i >= pdf->nxref){
18+ werrstr("no object id %d in xref", o->indir.id);
19+ return -1;
1820 }
21+ x = &pdf->xref[i];
1922
20− werrstr("no object id %d in xref", o->indir.id);
23+ if(Bseek(pdf->bio, x->off, 0) != x->off){
24+ werrstr("xref seek failed");
25+ return -1;
26+ }
27+ if((d = pdfobject(pdf->bio)) == nil)
28+ return -1;
29+ *o = *d;
30+ memset(d, 0, sizeof(*d));
31+ freeobject(d);
2132
22− return -1;
33+ return 0;
2334 }
filter.c+1−0
@@ -1,5 +1,6 @@
11 #include <u.h>
22 #include <libc.h>
3+#include <bio.h>
34 #include "pdf.h"
45
56 /*
main.c+9−1
@@ -1,8 +1,11 @@
11 #include <u.h>
22 #include <libc.h>
33 #include <thread.h>
4+#include <bio.h>
45 #include "pdf.h"
56
7+int mainstacksize = 32768;
8+
69 static void
710 usage(void)
811 {
@@ -15,6 +18,7 @@ threadmain(int argc, char **argv) · 6 unmodified lines
1518 {
1619 int fd;
1720 Pdf *pdf;
21+ Object *v;
1822
1923 quotefmtinstall();
2024
@@ -40,7 +44,11 @@ threadmain(int argc, char **argv) · 19 unmodified lines
4044 if((fd = open(argv[0], OREAD)) < 0)
4145 sysfatal("%r");
4246 if((pdf = pdfopen(fd)) == nil)
43− sysfatal("pdfopen: %r");
47+ sysfatal("%r");
48+ if((v = pdfdictget(pdf->info, "Creator")) != nil)
49+ fprint(2, "creator: %s\n", v->str);
50+ if((v = pdfdictget(pdf->info, "Producer")) != nil)
51+ fprint(2, "producer: %s\n", v->str);
4452 pdfclose(pdf);
4553
4654 threadexitsall(nil);
misc.c+3−2
@@ -1,10 +1,11 @@
11 #include <u.h>
22 #include <libc.h>
3+#include <bio.h>
34 #include "pdf.h"
45
56 /* 7.2.2 whitespace */
67 int
7−isws(char c)
8+isws(int c)
89 {
910 return /* \0 is missing on purpose */
1011 c == '\t' || c == '\n' || c == '\f' || c == '\r' ||
@@ -13,7 +14,7 @@ isws(char c) · 2 unmodified lines
1314
1415 /* 7.2.2 delimeters */
1516 int
16−isdelim(char c)
17+isdelim(int c)
1718 {
1819 return
1920 c == '(' || c == ')' || c == '<' || c == '>' ||
name.c+93−65
@@ -1,104 +1,132 @@
11 #include <u.h>
22 #include <libc.h>
3+#include <bio.h>
34 #include "pdf.h"
45
5−int
6−pdfname(char *p, char **e, int len)
6+/* 7.3.5 Name Objects */
7+
8+Object *
9+pdfname(Biobuf *b)
710 {
8− int i, o;
11+ Object *o;
12+ char *s, *r, hex[3];
13+ int c, sz, maxsz;
914
10− if(len < 2){
11− werrstr("too short");
12− goto err;
13− }
15+ Bgetc(b); /* skip '/' */
1416
15− if(p[0] != '/'){
16− werrstr("invalid first char");
17+ maxsz = 32;
18+ if((s = malloc(maxsz)) == nil)
1719 goto err;
18− }
1920
20− for(i = 1, o = 0; i < len; i++){
21− if(p[i] < '!' || p[i] > '~'){
22− if(isws(p[i]) || isdelim(p[i]))
21+ for(sz = 0;;){
22+ if((c = Bgetc(b)) < 0){
23+ if(c == Beof)
2324 break;
24− werrstr("invalid char %02x", p[i]);
2525 goto err;
2626 }
27− if(p[i] == '#'){
28− i++;
29− if(i+2 > len){
30− werrstr("hex too short");
27+
28+ if(isws(c) || isdelim(c)){
29+ Bungetc(b);
30+ break;
31+ }
32+ if(c < '!' || c > '~'){
33+ werrstr("invalid char %02x", c);
34+ goto err;
35+ }
36+ if(c == '#'){
37+ if((c = Bgetc(b)) < 0)
3138 goto err;
32− }
33− if(dec16((uchar*)p+o, 1, p+i, 2) != 1){
39+ hex[0] = c;
40+ if((c = Bgetc(b)) < 0)
41+ goto err;
42+ hex[1] = c;
43+ if(dec16((uchar*)hex, 1, hex, 2) != 1){
3444 werrstr("invalid hex");
3545 goto err;
3646 }
37− o++;
38− i++;
39− }else{
40− p[o++] = p[i];
47+ c = hex[0];
4148 }
49+ if(sz+1 >= maxsz){
50+ maxsz *= 2;
51+ if((r = realloc(s, maxsz)) == nil)
52+ goto err;
53+ s = r;
54+ }
55+ s[sz++] = c;
4256 }
4357
44− p[o] = 0;
45− *e = p + i;
58+ if((o = malloc(sizeof(*o) + sz + 1)) != nil){
59+ memmove(o->name, s, sz);
60+ o->name[sz] = 0;
61+ o->type = Oname;
62+ free(s);
63+ return o;
64+ }
4665
47− return o;
4866 err:
4967 werrstr("name: %r");
50− return -1;
68+ free(s);
69+ return nil;
5170 }
5271
5372 #ifdef TEST
5473 static struct {
55− char *i;
56− int len;
57− char *o;
58− int r;
59− int e;
74+ char *in;
75+ char *out;
6076 }t[] = {
61− {"/SimpleName", 11, "SimpleName", 10},
62− {"WrongName", 9, nil, -1},
63− {"/.$()", 5, ".$()", 4},
64− {"/#30", 4, "0", 1},
65− {"/#3", 3, nil, -1},
66− {"/#G0", 4, nil, -1},
67− {"/#", 2, nil, -1},
68− {"/Wrong Char", 11, nil, -1},
69− {"/\xff", 2, nil, -1},
77+ {"/SimpleName", "SimpleName"},
78+ {"/.$()", ".$"},
79+ {"/#30", "0"},
80+ {"/#3", nil},
81+ {"/#G0", nil},
82+ {"/#", nil},
83+ {"/Space Between", "Space"},
84+ {"/Two/Names", "Two"},
85+ {"/\xff", nil,},
7086 };
7187
88+static char *s;
89+static int off, n;
90+
91+static int
92+rd(Biobufhdr *, void *data, long sz)
93+{
94+ if(sz > n-off)
95+ sz = n-off;
96+ memmove(data, s+off, sz);
97+ off += sz;
98+ return sz;
99+}
100+
72101 void
73102 test_pdfname(void)
74103 {
75− char *e;
76− int i, r;
104+ Object *o;
105+ Biobuf b;
106+ int i;
77107
78108 fprint(2, "pdfname\n");
79109 for(i = 0; i < nelem(t); i++){
110+ s = t[i].in;
111+ n = strlen(s);
112+ off = 0;
113+ Binit(&b, -1, OREAD);
114+ Biofn(&b, rd);
115+
80116 fprint(2, "\t%d: ", i);
81− r = pdfname(t[i].i, &e, t[i].len);
82− if(r != t[i].r){
83− fprint(2, "expected r=%d, got %d", t[i].r, r);
84− if(r < 0)
85− fprint(2, " (%r)\n");
86− else
87− fprint(2, "\n");
88− continue;
89− }else if(r >= 0){
90− if(t[i].i+t[i].len != e){
91− fprint(2, "expected e=%p, got %p\n", t[i].i+t[i].len, e);
92− continue;
93− }else if(strcmp(t[i].o, t[i].i) != 0){
94− fprint(2, "expected %q, got %q\n", t[i].o, t[i].i);
95− continue;
96− }
97− }
98− fprint(2, "OK");
99− if(r < 0)
100− fprint(2, " (%r)");
101− fprint(2, "\n");
117+ o = pdfname(&b);
118+ if(o == nil && t[i].out != nil)
119+ fprint(2, "ERROR: expected %q, got error: %r\n", t[i].out);
120+ else if(o != nil && t[i].out == nil)
121+ fprint(2, "ERROR: expected error, got %q\n", o->name);
122+ else if(o == nil && t[i].out == nil)
123+ fprint(2, "OK (%r)\n");
124+ else if(strcmp(o->name, t[i].out) != 0)
125+ fprint(2, "ERROR: expected %q, got %q\n", t[i].out, o->name);
126+ else
127+ fprint(2, "OK\n");
128+ freeobject(o);
129+ Bterm(&b);
102130 }
103131 }
104132 #endif
object.c+128−68
@@ -1,105 +1,165 @@
11 #include <u.h>
22 #include <libc.h>
33 #include <ctype.h>
4+#include <bio.h>
45 #include "pdf.h"
56
7+Object *pdfstring(Biobuf *b);
8+Object *pdfname(Biobuf *b);
9+Object *pdfarray(Biobuf *b);
10+Object *pdfdict(Biobuf *b);
11+
12+static Object null = {
13+ .type = Onull,
14+};
15+
16+/* General function to parse an object of any type. */
617 Object *
7−pdfobject(char *p, char **e, int len)
18+pdfobject(void *b)
819 {
9− Object *o;
10− char *s, *p0;
11− int sz, gen;
12−
13− o = nil;
14− for(; len > 0 && isws(*p); p++, len--);
15− if(len < 1){
16− werrstr("too short");
17− goto err;
18− }
20+ Object *o, *o2;
21+ vlong off;
22+ int c, tf;
1923
20− if(*p < 1){
21− werrstr("unexpected non-ascii char");
24+ o = o2 = nil;
25+ do; while(isws(c = Bgetc(b)));
26+ if(c < 0)
2227 goto err;
23− }
2428
25− switch(*p){
29+ switch(c){
2630 case '<': /* dictionary or a string */
27− if(len < 2){
28− werrstr("too short");
29− goto err;
30− }
31− if(p[1] == '<'){ /* dictionary */
32− o = pdfdict(p, e, len);
33− break;
31+ c = Bgetc(b);
32+ if(c == '<'){
33+ Bseek(b, -2, 1);
34+ return pdfdict(b);
3435 }
36+ Bungetc(b);
3537 /* fall through */
3638
37− case '(': /* string */
38− if((sz = pdfstring(p, e, len)) < 0)
39− goto err;
40− if((o = malloc(sizeof(*o)+sz+1)) != nil){
41− o->type = Ostr;
42− o->str = (char*)(o+1);
43− strcpy(o->str, p);
44− }
45− break;
39+ case '(':
40+ Bungetc(b);
41+ return pdfstring(b);
4642
4743 case '/':
48− if((sz = pdfname(p, e, len)) < 0)
49− goto err;
50− if((o = malloc(sizeof(*o)+sz+1)) != nil){
51− o->type = Oname;
52− o->str = (char*)(o+1);
53− strcpy(o->str, p);
54− }
55− break;
44+ Bungetc(b);
45+ return pdfname(b);
5646
5747 case '[':
58− o = pdfarray(p, e, len);
59− break;
48+ Bungetc(b);
49+ return pdfarray(b);
50+
51+ case 'n':
52+ off = Boffset(b);
53+ if(Bgetc(b) == 'u' && Bgetc(b) == 'l' && Bgetc(b) == 'l' && (isws(c = Bgetc(b)) || isdelim(c))){
54+ Bungetc(b);
55+ return &null;
56+ }
57+ Bseek(b, off, 0);
58+ c = 'f';
59+ goto unexpected;
60+
61+ case 't':
62+ off = Boffset(b);
63+ tf = 1;
64+ if(Bgetc(b) == 'r' && Bgetc(b) == 'u' && Bgetc(b) == 'e' && (isws(c = Bgetc(b)) || isdelim(c)))
65+ goto bool;
66+ Bseek(b, off, 0);
67+ c = 't';
68+ goto unexpected;
69+
70+ case 'f':
71+ off = Boffset(b);
72+ tf = 0;
73+ if(Bgetc(b) == 'a' && Bgetc(b) == 'l' && Bgetc(b) == 's' && Bgetc(b) == 'e' && (isws(c = Bgetc(b)) || isdelim(c)))
74+ goto bool;
75+ Bseek(b, off, 0);
76+ c = 'f';
77+ goto unexpected;
78+bool:
79+ Bungetc(b);
80+ if((o = malloc(sizeof(*o))) == nil)
81+ goto err;
82+ o->type = Obool;
83+ o->bool = tf;
84+ return o;
6085
6186 default:
62− if(isdigit(*p)){
63− if((o = malloc(sizeof(*o))) != nil){
64− o->type = Onum;
65− o->num = strtod(p, e);
66− sz = len - (*e - p);
67− p0 = *e;
68− s = p0;
69− for(; sz > 0 && isws(*s); s++, sz--);
70− if(sz > 0 && isdigit(*s)){
71− gen = strtod(s, &p);
72− sz -= (p - s);
73− s = p;
74− for(; sz > 0 && isws(*s); s++, sz--);
75− if(sz > 0 && *s == 'R'){ /* indirect object */
76− s++;
77− o->type = Oindir;
78− o->indir.id = o->num;
79− o->indir.gen = gen;
80− p0 = s;
81− }
82− }
83− *e = p0;
87+ if((o = malloc(sizeof(*o))) == nil)
88+ goto err;
89+ if(!isdigit(c)){
90+unexpected:
91+ Bungetc(b);
92+ werrstr("unexpected char '%c'", c);
93+ goto err;
94+ }
95+ /* it could be a number or an indirect object */
96+ Bungetc(b);
97+ Bgetd(b, &o->num); /* get the first number */
98+ off = Boffset(b); /* seek here if not an indirect object later */
99+
100+ if((o2 = pdfobject(b)) != nil && o2->type == Onum){ /* second object is number too */
101+ do; while(isws(c = Bgetc(b)));
102+ if(c < 0)
103+ goto err;
104+ if(c == 'R'){ /* indirect object */
105+ o->type = Oindir;
106+ o->indir.id = o->num;
107+ o->indir.gen = o2->num;
108+ freeobject(o2);
109+ return o;
110+ }
111+ if(c == 'o' && Bgetc(b) == 'b' && Bgetc(b) == 'j'){ /* object */
112+ freeobject(o2);
113+ /* FIXME put into a map */
114+ return pdfobject(b);
84115 }
85− break;
86116 }
87− werrstr("unexpected char %c", *p);
88− goto err;
89− }
90117
91− if(o != nil)
118+ /* just a number, go back and return it */
119+ o->type = Onum;
120+ if(Bseek(b, off, 0) != off){
121+ werrstr("seek failed");
122+ goto err;
123+ }
92124 return o;
125+ }
126+
93127 err:
94128 werrstr("object: %r");
95129 freeobject(o);
130+ freeobject(o2);
96131 return nil;
97132 }
98133
99134 void
100135 freeobject(Object *o)
101136 {
137+ int i;
138+
102139 if(o == nil)
103140 return;
141+
142+ switch(o->type){
143+ case Onull:
144+ return;
145+
146+ case Obool:
147+ case Onum:
148+ case Ostr:
149+ case Oname:
150+ break;
151+
152+ case Oarray:
153+ for(i = 0; i < o->array.ne; i++)
154+ freeobject(o->array.e[i]);
155+ free(o->array.e);
156+ break;
157+
158+ case Odict:
159+ case Ostream:
160+ case Oindir:
161+ break;
162+ }
163+
104164 free(o);
105165 }
pdf.c+5−9
@@ -33,8 +33,8 @@ xrefread(Pdf *pdf, int xref0, int nxref) · 32 unmodified lines
3333 /* store non-free objects only */
3434 newnxref = pdf->nxref;
3535 for(e = s, i = 0; i < nxref; i++, e += 20){
36− if(e[10] != ' ' || e[18] != '\r' || e[19] != '\n'){
37− werrstr("invalid xref line");
36+ if(!isspace(e[10]) || !isspace(e[18]) || !isspace(e[19])){
37+ werrstr("invalid xref line (%d/%d)", i, nxref);
3838 goto err;
3939 }
4040 xref.id = xref0 + i;
@@ -76,15 +76,11 @@ static int · 35 unmodified lines
7676 trailerread(Pdf *pdf)
7777 {
7878 int i;
79− char *s, *e;
8079 Object *o;
8180 KeyValue *kv;
8281
83− o = nil;
84− if((s = Brdstr(pdf->bio, 0, 1)) == nil || (o = pdfobject(s, &e, Blinelen(pdf->bio))) == nil)
82+ if((o = pdfobject(pdf->bio)) == nil)
8583 goto err;
86− free(s);
87− s = nil;
8884
8985 if(o->type != Odict){
9086 werrstr("isn't a dictionary");
@@ -92,7 +88,6 @@ trailerread(Pdf *pdf) · 1 unmodified line
9288 }
9389
9490 for(i = 0, kv = o->dict.kv; i < o->dict.nkv; i++, kv++){
95− fprint(2, "# %s %p\n", kv->key, kv->value);
9691 if(strcmp(kv->key, "Root") == 0)
9792 pdf->root = kv->value;
9893 else if(strcmp(kv->key, "Info") == 0)
@@ -112,7 +107,6 @@ trailerread(Pdf *pdf) · 13 unmodified lines
112107 return 0;
113108 err:
114109 freeobject(o);
115− free(s);
116110 return -1;
117111 }
118112
@@ -127,6 +121,7 @@ pdfopen(int fd) · 8 unmodified lines
127121 int xreftb; /* 7.5.4 xref table offset from the beginning of the file */
128122 int i, n, off;
129123
124+ b = nil;
130125 if((pdf = calloc(1, sizeof(*pdf))) == nil || (b = Bfdopen(fd, OREAD)) == nil)
131126 goto err;
132127 pdf->bio = b;
@@ -204,6 +199,7 @@ badxref: · 71 unmodified lines
204199
205200 return pdf;
206201 err:
202+ werrstr("pdfopen: %r [at %p]", (void*)Boffset(b));
207203 pdfclose(pdf);
208204 return nil;
209205 }
pdf.h+12−38
@@ -20,8 +20,11 @@ struct Object { · 19 unmodified lines
2020 union {
2121 int bool;
2222 double num;
23− char *str;
24− char *name;
23+ struct {
24+ int len;
25+ char str[1];
26+ };
27+ char name[1];
2528
2629 struct {
2730 u32int id;
@@ -50,8 +53,8 @@ struct Pdf { · 22 unmodified lines
5053 Xref *xref;
5154 int nxref; /* 7.5.4 xref subsection number of objects */
5255
53− Object *root; /* 7.5.5 root object */
54− Object *info; /* 7.5.5 info dictionary */
56+ Object *root; /* 7.7.2 root object */
57+ Object *info; /* 14.3.3 info dictionary */
5558 };
5659
5760 struct Xref {
@@ -63,45 +66,16 @@ struct Xref { · 5 unmodified lines
6366 Pdf *pdfopen(int fd);
6467 void pdfclose(Pdf *pdf);
6568
66−/*
67− * General function to parse an object of any type.
68− */
69−Object *pdfobject(char *p, char **e, int len);
70−
69+Object *pdfobject(void *b);
7170 void freeobject(Object *o);
7271
73−/*
74− * 7.3.4 String Objects
75− *
76− * Rewrites the string in place with null termination and returns the
77− * length in bytes, without the null terminator.
78− * Returns < 0 if parsing failed.
79− * (*e) is advanced to the position after the string pointed by (p).
80− */
81−int pdfstring(char *p, char **e, int len);
82−
83−/*
84− * 7.3.5 Name Objects
85− *
86− * Works the same way as pdfstring, but for name objects.
87− */
88−int pdfname(char *p, char **e, int len);
89−
90−/*
91− * 7.3.6 Array Objects
92− */
93−Object *pdfarray(char *p, char **e, int len);
94−
95−/*
96− * 7.3.7 Dictionary Objects
97− */
98−Object *pdfdict(char *p, char **e, int len);
99−
10072 /*
10173 * If the object is indirect, resolve it. Operation is not recursive, ie
10274 * values of a dictionary won't be resolved automatically.
10375 */
10476 int pdfeval(Pdf *pdf, Object *o);
10577
106−int isws(char c);
107−int isdelim(char c);
78+int isws(int c);
79+int isdelim(int c);
80+
81+Object *pdfdictget(Object *o, char *name);
string.c+163−128
@@ -1,8 +1,11 @@
11 #include <u.h>
22 #include <libc.h>
3+#include <bio.h>
34 #include "pdf.h"
45
5−static int esc[] = {
6+/* 7.3.4 String Objects */
7+
8+static char esc[] = {
69 ['n'] = '\n',
710 ['r'] = '\r',
811 ['t'] = '\t',
@@ -14,175 +17,207 @@ static int esc[] = { · 5 unmodified lines
1417 ['\n'] = -1,
1518 };
1619
17−static int
18−pdfstringhex(char *p, char **e, int len)
20+static Object *
21+stringhex(Biobuf *b)
1922 {
20− int i;
23+ char *s;
24+ Object *o;
25+ int len, n;
2126
22− for(i = 1; i < len; i += 1){
23− if(p[i] == '>')
24− break;
27+ if((s = Brdstr(b, '>', 0)) == nil)
28+ return nil;
29+ len = Blinelen(b) - 1;
30+ if(s[len] != '>'){
31+ werrstr("no '>'");
32+ free(s);
33+ return nil;
2534 }
26− if(i >= len){
27− werrstr("hex not closed");
28− return -1;
29− }
30− p[i] = '0'; /* the final zero may be missing */
31− *e = p+i+1;
32− i = dec16((uchar*)p, i/2, p+1, i) == i/2 ? i/2 : -1;
33− if(i < 0)
35+ s[len] = '0'; /* the final zero may be missing */
36+ n = len/2;
37+ o = nil;
38+ if(dec16((uchar*)s, n, s+1, len) != n){
3439 werrstr("invalid hex");
35− p[i] = 0;
36− return i;
40+ }else if((o = malloc(sizeof(*o) + n + 1)) != nil){
41+ memmove(o->str, s, n);
42+ o->str[n] = 0;
43+ o->len = n;
44+ o->type = Ostr;
45+ }
46+
47+ free(s);
48+ return o;
3749 }
3850
39−int
40−pdfstring(char *p, char **e, int len)
51+Object *
52+pdfstring(Biobuf *b)
4153 {
42− Rune r;
43− int c, j, i, o, n, paren;
54+ Object *o;
55+ char *s, *r;
4456 char oct[4];
57+ int i, c, paren, sz, maxsz;
4558
46− if(len < 2){
47− werrstr("too short");
48− goto err;
49− }
59+ maxsz = 64;
60+ if((s = malloc(maxsz)) == nil)
61+ return nil;
5062
51− paren = 0;
52− for(i = o = 0; i < len;){
53− if((n = chartorune(&r, p+i)) == 1 && r == Runeerror){
54− werrstr("rune error at byte %d", n);
55− return -1;
56− }
63+ for(paren = sz = 0;;){
64+ if((c = Bgetc(b)) <= 0)
65+ break;
5766
58− if(i == 0){
59− if(r == '('){
60− paren = 1;
61− i++;
62− continue;
63− }
64− if(r == '<'){
65− len = pdfstringhex(p, e, len);
66− if(len < 0)
67− goto err;
68− return len;
67+ switch(c){
68+ case '<':
69+ if(sz == 0){
70+ Bungetc(b);
71+ return stringhex(b);
6972 }
70− werrstr("invalid first char");
71− goto err;
72− }
73+ break;
7374
74− if(r == '\\'){
75− if(++i >= len){
76− werrstr("escaped char out of string len");
77− goto err;
78− }
79− if((n = chartorune(&r, p+i)) == 1 && r == Runeerror){
80− werrstr("rune error at byte %d", i);
81− goto err;
82− }
83− if(r >= '0' && r <= '9'){ /* octal */
84− n = 0;
85− for(j = 0; j < 3 && i < len && p[i] >= '0' && p[i] <= '9'; j++, i++)
86− oct[j] = p[i];
87− oct[j] = 0;
88− c = strtol(oct, nil, 8);
89− }else if(r >= nelem(esc) || (c = esc[r]) == 0){
90− werrstr("unknown escape char at byte %d", i);
91− goto err;
92− }
93− r = c;
94− i += n;
95− if(c < 0)
96− continue;
97− }else if(r == '('){
75+ case '(':
9876 paren++;
99− i++;
10077 continue;
101− }else if(r == ')'){
78+
79+ case ')':
10280 paren--;
103− i++;
104− if(paren == 0)
81+ if(paren < 1){
82+ c = 0;
10583 break;
84+ }
10685 continue;
107− }else{
108− i += n;
86+
87+ case '\\':
88+ if((c = Bgetc(b)) <= 0)
89+ break;
90+ if(c >= '0' && c <= '7'){ /* octal */
91+ oct[0] = c;
92+ for(i = 1; i < 3 && (c = Bgetc(b)) >= '0' && c <= '7'; i++)
93+ oct[i] = c;
94+ if(c <= 0)
95+ break;
96+ if(c < '0' || c > '7')
97+ Bungetc(b);
98+ oct[i] = 0;
99+ c = strtol(oct, nil, 8);
100+ }else if(c >= nelem(esc) || (c = esc[c]) == 0){
101+ werrstr("unknown escape char %c", c);
102+ goto err;
103+ }else if(c < 0){
104+ continue;
105+ }
106+ break;
107+
108+ default:
109+ if(paren < 1){
110+ werrstr("unexpected char '%c'", c);
111+ goto err;
112+ }
113+ break;
109114 }
110115
111− o += runetochar(p+o, &r);
116+ if(c <= 0)
117+ break;
118+ if(sz+1 > maxsz){
119+ maxsz *= 2;
120+ if((r = realloc(s, maxsz)) == nil)
121+ goto err;
122+ s = r;
123+ }
124+ s[sz++] = c;
112125 }
113126
114− if(paren > 0){
115− werrstr("non-closed paren");
127+ if(paren != 0){
128+ werrstr("bad paren");
129+ goto err;
130+ }
131+ if(c < 0){
132+ werrstr("short");
116133 goto err;
117134 }
118135
119− p[o] = 0;
120− *e = p + i;
136+ if(c >= 0 && (o = malloc(sizeof(*o) + sz + 1)) != nil){
137+ memmove(o->str, s, sz);
138+ o->str[sz] = 0;
139+ o->len = sz;
140+ o->type = Ostr;
141+ free(s);
142+ return o;
143+ }
121144
122− return o;
123145 err:
146+ free(s);
124147 werrstr("string: %r");
125− return -1;
148+ return nil;
126149 }
127150
128151 #ifdef TEST
129152 static struct {
130− char *i;
131− int len;
132− char *o;
133− int r;
134− int e;
153+ char *in;
154+ char *out;
135155 }t[] = {
136− {"(simple string)", 15, "simple string", 13},
137− {"(non-closed paren", 17, nil, -1},
138− {"wrong first char", 16, nil, -1},
139− {"(parens((()((())))()))", 22, "parens", 6},
140− {"(\\0053)", 7, "\x053", 2},
141− {"(\\053)", 6, "+", 1},
142− {"(\\53)", 5, "+", 1},
143− {"()", 2, "", 0},
144− {")", 1, nil, -1},
145− {"(\\)\\()", 6, ")(", 2},
146− {"(\\\\)", 4, "\\", 1},
147− {"a", 1, nil, -1},
148− {"(1\\\n2)", 6, "12", 2},
149− {"<323130>", 8, "210", 3},
150− {"<32313>", 7, "210", 3},
151− {"<>", 2, "", 0},
152− {"<", 1, nil, -1},
153− {"<zz>", 4, nil, -1},
156+ {"", nil},
157+ {"(test, success)", "test, success"},
158+ {"(simple string)", "simple string"},
159+ {"(non-closed paren", nil},
160+ {"wrong first char", nil},
161+ {"(parens((()((())))()))", "parens"},
162+ {"(\\0053)", "\x053"},
163+ {"(\\053)", "+"},
164+ {"(\\53)", "+"},
165+ {"()", ""},
166+ {")", nil},
167+ {"(\\)\\()", ")("},
168+ {"(\\\\)", "\\"},
169+ {"a", nil},
170+ {"(1\\\n2)", "12"},
171+ {"<323130>", "210"},
172+ {"<32313>", "210"},
173+ {"<>", ""},
174+ {"<", nil},
175+ {"<zz>", nil},
176+ {">", nil},
154177 };
155178
179+static char *s;
180+static int off, n;
181+
182+static int
183+rd(Biobufhdr *, void *data, long sz)
184+{
185+ if(sz > n-off)
186+ sz = n-off;
187+ memmove(data, s+off, sz);
188+ off += sz;
189+ return sz;
190+}
191+
156192 void
157193 test_pdfstring(void)
158194 {
159− char *e;
160− int i, r;
195+ Object *o;
196+ Biobuf b;
197+ int i;
161198
162199 fprint(2, "pdfstring\n");
163200 for(i = 0; i < nelem(t); i++){
201+ s = t[i].in;
202+ n = strlen(s);
203+ off = 0;
204+ Binit(&b, -1, OREAD);
205+ Biofn(&b, rd);
206+
164207 fprint(2, "\t%d: ", i);
165− r = pdfstring(t[i].i, &e, t[i].len);
166− if(r != t[i].r){
167− fprint(2, "expected r=%d, got %d", t[i].r, r);
168− if(r < 0)
169− fprint(2, " (%r)\n");
170− else
171− fprint(2, "\n");
172− continue;
173− }else if(r >= 0){
174− if(t[i].i+t[i].len != e){
175− fprint(2, "expected e=%p, got %p\n", t[i].i+t[i].len, e);
176− continue;
177− }else if(strcmp(t[i].o, t[i].i) != 0){
178− fprint(2, "expected %q, got %q\n", t[i].o, t[i].i);
179− continue;
180− }
181− }
182− fprint(2, "OK");
183− if(r < 0)
184− fprint(2, " (%r)");
185− fprint(2, "\n");
208+ o = pdfstring(&b);
209+ if(o == nil && t[i].out != nil)
210+ fprint(2, "ERROR: expected %q, got error: %r\n", t[i].out);
211+ else if(o != nil && t[i].out == nil)
212+ fprint(2, "ERROR: expected error, got %q\n", o->str);
213+ else if(o == nil && t[i].out == nil)
214+ fprint(2, "OK (%r)\n");
215+ else if(strcmp(o->str, t[i].out) != 0)
216+ fprint(2, "ERROR: expected %q, got %q\n", t[i].out, o->str);
217+ else
218+ fprint(2, "OK\n");
219+ freeobject(o);
220+ Bterm(&b);
186221 }
187222 }
188223 #endif

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