static void renumberobj(fz_obj *obj) { int i; if (fz_isdict(obj)) { for (i = 0; i < fz_dictlen(obj); i++) { fz_obj *key = fz_dictgetkey(obj, i); fz_obj *val = fz_dictgetval(obj, i); if (fz_isindirect(val)) { val = fz_newindirect(renumbermap[fz_tonum(val)], 0, xref); fz_dictput(obj, key, val); fz_dropobj(val); } else { renumberobj(val); } } } else if (fz_isarray(obj)) { for (i = 0; i < fz_arraylen(obj); i++) { fz_obj *val = fz_arrayget(obj, i); if (fz_isindirect(val)) { val = fz_newindirect(renumbermap[fz_tonum(val)], 0, xref); fz_arrayput(obj, i, val); fz_dropobj(val); } else { renumberobj(val); } } } }
fz_error pdf_parsedict(fz_obj **op, pdf_xref *xref, fz_stream *file, char *buf, int cap) { fz_error error = fz_okay; fz_obj *dict = nil; fz_obj *key = nil; fz_obj *val = nil; pdf_token_e tok; int len; int a, b; dict = fz_newdict(8); while (1) { error = pdf_lex(&tok, file, buf, cap, &len); if (error) { fz_dropobj(dict); return fz_rethrow(error, "cannot parse dict"); } skip: if (tok == PDF_TCDICT) { *op = dict; return fz_okay; } /* for BI .. ID .. EI in content streams */ if (tok == PDF_TKEYWORD && !strcmp(buf, "ID")) { *op = dict; return fz_okay; } if (tok != PDF_TNAME) { fz_dropobj(dict); return fz_throw("invalid key in dict");; } key = fz_newname(buf); error = pdf_lex(&tok, file, buf, cap, &len); if (error) { fz_dropobj(dict); return fz_rethrow(error, "cannot parse dict"); } switch (tok) { case PDF_TOARRAY: error = pdf_parsearray(&val, xref, file, buf, cap); if (error) { fz_dropobj(key); fz_dropobj(dict); return fz_rethrow(error, "cannot parse dict"); } break; case PDF_TODICT: error = pdf_parsedict(&val, xref, file, buf, cap); if (error) { fz_dropobj(key); fz_dropobj(dict); return fz_rethrow(error, "cannot parse dict"); } break; case PDF_TNAME: val = fz_newname(buf); break; case PDF_TREAL: val = fz_newreal(atof(buf)); break; case PDF_TSTRING: val = fz_newstring(buf, len); break; case PDF_TTRUE: val = fz_newbool(1); break; case PDF_TFALSE: val = fz_newbool(0); break; case PDF_TNULL: val = fz_newnull(); break; case PDF_TINT: /* 64-bit to allow for numbers > INT_MAX and overflow */ a = (int) strtoll(buf, 0, 10); error = pdf_lex(&tok, file, buf, cap, &len); if (error) { fz_dropobj(key); fz_dropobj(dict); return fz_rethrow(error, "cannot parse dict"); } if (tok == PDF_TCDICT || tok == PDF_TNAME || (tok == PDF_TKEYWORD && !strcmp(buf, "ID"))) { val = fz_newint(a); fz_dictput(dict, key, val); fz_dropobj(val); fz_dropobj(key); goto skip; } if (tok == PDF_TINT) { b = atoi(buf); error = pdf_lex(&tok, file, buf, cap, &len); if (error) { fz_dropobj(key); fz_dropobj(dict); return fz_rethrow(error, "cannot parse dict"); } if (tok == PDF_TR) { val = fz_newindirect(a, b, xref); break; } } fz_dropobj(key); fz_dropobj(dict); return fz_throw("invalid indirect reference in dict"); default: return fz_throw("unknown token in dict"); } fz_dictput(dict, key, val); fz_dropobj(val); fz_dropobj(key); } }
static fz_error * loadnametreenode(fz_obj *tree, pdf_xref *xref, fz_obj *node) { fz_error *error; fz_obj *names; fz_obj *kids; fz_obj *key; fz_obj *val; int i, len; error = pdf_resolve(&node, xref); if (error) return error; names = fz_dictgets(node, "Names"); if (names) { error = pdf_resolve(&names, xref); if (error) goto cleanup; len = fz_arraylen(names) / 2; for (i = 0; i < len; ++i) { key = fz_arrayget(names, i * 2 + 0); val = fz_arrayget(names, i * 2 + 1); error = fz_dictput(tree, key, val); if (error) { fz_dropobj(names); goto cleanup; } } fz_dropobj(names); } kids = fz_dictgets(node, "Kids"); if (kids) { error = pdf_resolve(&kids, xref); if (error) goto cleanup; len = fz_arraylen(kids); for (i = 0; i < len; ++i) { error = loadnametreenode(tree, xref, fz_arrayget(kids, i)); if (error) { fz_dropobj(kids); goto cleanup; } } fz_dropobj(kids); } fz_dropobj(node); return nil; cleanup: fz_dropobj(node); return error; }
static fz_error parsedict(fz_obj **obj, pdf_xref *xref, char **sp, struct vap *v) { fz_error error = fz_okay; fz_obj *dict = nil; fz_obj *key = nil; fz_obj *val = nil; char *s = *sp; error = fz_newdict(&dict, 8); if (error) return fz_rethrow(error, "cannot create dict"); s += 2; /* skip "<<" */ while (*s) { skipwhite(&s); /* end-of-dict marker >> */ if (*s == '>') { s ++; if (*s == '>') { s ++; break; } error = fz_throw("malformed >> marker"); goto cleanup; } /* non-name as key, bail */ if (*s != '/') { error = fz_throw("key is not a name"); goto cleanup; } error = parsename(&key, &s); if (error) { error = fz_rethrow(error, "cannot parse key"); goto cleanup; } skipwhite(&s); error = parseobj(&val, xref, &s, v); if (error) { error = fz_rethrow(error, "cannot parse value"); goto cleanup; } error = fz_dictput(dict, key, val); if (error) { error = fz_rethrow(error, "cannot insert dict entry"); goto cleanup; } fz_dropobj(val); val = nil; fz_dropobj(key); key = nil; } *obj = dict; *sp = s; return fz_okay; cleanup: if (val) fz_dropobj(val); if (key) fz_dropobj(key); if (dict) fz_dropobj(dict); *obj = nil; *sp = s; return error; /* already rethrown */ }
fz_error * pdf_parsedict(fz_obj **op, fz_stream *file, char *buf, int cap) { fz_error *error = nil; fz_obj *dict = nil; fz_obj *key = nil; fz_obj *val = nil; int tok, len; int a, b; error = fz_newdict(op, 8); if (error) return error; dict = *op; while (1) { tok = pdf_lex(file, buf, cap, &len); skip: if (tok == PDF_TCDICT) return nil; /* for BI .. ID .. EI in content streams */ if (tok == PDF_TKEYWORD && !strcmp(buf, "ID")) return nil; if (tok != PDF_TNAME) goto cleanup; error = fz_newname(&key, buf); if (error) goto cleanup; tok = pdf_lex(file, buf, cap, &len); switch (tok) { case PDF_TOARRAY: error = pdf_parsearray(&val, file, buf, cap); break; case PDF_TODICT: error = pdf_parsedict(&val, file, buf, cap); break; case PDF_TNAME: error = fz_newname(&val, buf); break; case PDF_TREAL: error = fz_newreal(&val, atof(buf)); break; case PDF_TSTRING: error = fz_newstring(&val, buf, len); break; case PDF_TTRUE: error = fz_newbool(&val, 1); break; case PDF_TFALSE: error = fz_newbool(&val, 0); break; case PDF_TNULL: error = fz_newnull(&val); break; case PDF_TINT: a = atoi(buf); tok = pdf_lex(file, buf, cap, &len); if (tok == PDF_TCDICT || tok == PDF_TNAME || (tok == PDF_TKEYWORD && !strcmp(buf, "ID"))) { error = fz_newint(&val, a); if (error) goto cleanup; error = fz_dictput(dict, key, val); if (error) goto cleanup; fz_dropobj(val); fz_dropobj(key); key = val = nil; goto skip; } if (tok == PDF_TINT) { b = atoi(buf); tok = pdf_lex(file, buf, cap, &len); if (tok == PDF_TR) { error = fz_newindirect(&val, a, b); break; } } goto cleanup; default: goto cleanup; } if (error) goto cleanup; error = fz_dictput(dict, key, val); if (error) goto cleanup; fz_dropobj(val); fz_dropobj(key); key = val = nil; } cleanup: if (key) fz_dropobj(key); if (val) fz_dropobj(val); if (dict) fz_dropobj(dict); if (error) return error; return fz_throw("syntaxerror: corrupt dictionary"); }