ref: a080ae88c6c65503575da220cb131ddada107bf6
dir: /object.c/
#include <u.h> #include <libc.h> #include <ctype.h> #include <bio.h> #include "pdf.h" Object *pdfstring(Biobuf *b); Object *pdfname(Biobuf *b); Object *pdfarray(Biobuf *b); Object *pdfdict(Biobuf *b); static Object null = { .type = Onull, }; /* General function to parse an object of any type. */ Object * pdfobject(void *b) { Object *o, *o2; vlong off; int c, tf; o = o2 = nil; do; while(isws(c = Bgetc(b))); if(c < 0) goto err; switch(c){ case '<': /* dictionary or a string */ c = Bgetc(b); if(c == '<'){ Bseek(b, -2, 1); return pdfdict(b); } Bungetc(b); /* fall through */ case '(': Bungetc(b); return pdfstring(b); case '/': Bungetc(b); return pdfname(b); case '[': Bungetc(b); return pdfarray(b); case 'n': off = Boffset(b); if(Bgetc(b) == 'u' && Bgetc(b) == 'l' && Bgetc(b) == 'l' && (isws(c = Bgetc(b)) || isdelim(c))){ Bungetc(b); return &null; } Bseek(b, off, 0); c = 'f'; goto unexpected; case 't': off = Boffset(b); tf = 1; if(Bgetc(b) == 'r' && Bgetc(b) == 'u' && Bgetc(b) == 'e' && (isws(c = Bgetc(b)) || isdelim(c))) goto bool; Bseek(b, off, 0); c = 't'; goto unexpected; case 'f': off = Boffset(b); tf = 0; if(Bgetc(b) == 'a' && Bgetc(b) == 'l' && Bgetc(b) == 's' && Bgetc(b) == 'e' && (isws(c = Bgetc(b)) || isdelim(c))) goto bool; Bseek(b, off, 0); c = 'f'; goto unexpected; bool: Bungetc(b); if((o = malloc(sizeof(*o))) == nil) goto err; o->type = Obool; o->bool = tf; return o; default: if((o = malloc(sizeof(*o))) == nil) goto err; if(!isdigit(c)){ unexpected: Bungetc(b); werrstr("unexpected char '%c'", c); goto err; } /* it could be a number or an indirect object */ Bungetc(b); Bgetd(b, &o->num); /* get the first number */ off = Boffset(b); /* seek here if not an indirect object later */ if((o2 = pdfobject(b)) != nil && o2->type == Onum){ /* second object is number too */ do; while(isws(c = Bgetc(b))); if(c < 0) goto err; if(c == 'R'){ /* indirect object */ o->type = Oindir; o->indir.id = o->num; o->indir.gen = o2->num; freeobject(o2); return o; } if(c == 'o' && Bgetc(b) == 'b' && Bgetc(b) == 'j'){ /* object */ freeobject(o2); /* FIXME put into a map */ return pdfobject(b); } } /* just a number, go back and return it */ o->type = Onum; if(Bseek(b, off, 0) != off){ werrstr("seek failed"); goto err; } return o; } err: werrstr("object: %r"); freeobject(o); freeobject(o2); return nil; } void freeobject(Object *o) { int i; if(o == nil) return; switch(o->type){ case Onull: return; case Obool: case Onum: case Ostr: case Oname: break; case Oarray: for(i = 0; i < o->array.ne; i++) freeobject(o->array.e[i]); free(o->array.e); break; case Odict: case Ostream: case Oindir: break; } free(o); }