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);
}