static fz_error * writeobject(fz_stream *out, pdf_xref *xref, pdf_crypt *encrypt, int oid, int gen) { pdf_xrefentry *x = xref->table + oid; fz_error *error; error = pdf_cacheobject(xref, oid, gen); if (error) return error; if (encrypt) pdf_cryptobj(encrypt, x->obj, oid, gen); fz_print(out, "%d %d obj\n", oid, gen); fz_printobj(out, x->obj, TIGHT); fz_print(out, "\n"); if (encrypt) pdf_cryptobj(encrypt, x->obj, oid, gen); if (pdf_isstream(xref, oid, gen)) { error = writestream(out, xref, encrypt, oid, gen); if (error) return error; } fz_print(out, "endobj\n\n"); return nil; }
fz_error pdf_cacheobject(pdf_xref *xref, int num, int gen) { fz_error error; pdf_xrefentry *x; int rnum, rgen; if (num < 0 || num >= xref->len) return fz_throw("object out of range (%d %d R); xref size %d", num, gen, xref->len); x = &xref->table[num]; if (x->obj) return fz_okay; if (x->type == 'f') { x->obj = fz_newnull(); return fz_okay; } else if (x->type == 'n') { fz_seek(xref->file, x->ofs, 0); error = pdf_parseindobj(&x->obj, xref, xref->file, xref->scratch, sizeof xref->scratch, &rnum, &rgen, &x->stmofs); if (error) return fz_rethrow(error, "cannot parse object (%d %d R)", num, gen); if (rnum != num) return fz_throw("found object (%d %d R) instead of (%d %d R)", rnum, rgen, num, gen); if (xref->crypt) pdf_cryptobj(xref->crypt, x->obj, num, gen); } else if (x->type == 'o') { if (!x->obj) { error = pdf_loadobjstm(xref, x->ofs, 0, xref->scratch, sizeof xref->scratch); if (error) return fz_rethrow(error, "cannot load object stream containing object (%d %d R)", num, gen); if (!x->obj) return fz_throw("object (%d %d R) was not found in its object stream", num, gen); } } else { return fz_throw("assert: corrupt xref struct"); } return fz_okay; }
fz_error * pdf_savexref(pdf_xref *xref, char *path, pdf_crypt *encrypt) { fz_error *error; fz_stream *out; int oid; int startxref; int *ofsbuf; fz_obj *obj; int eoid, egen; pdf_logxref("savexref '%s' %p\n", path, xref); /* need to add encryption object for acrobat < 6 */ if (encrypt) { pdf_logxref("make encryption dict\n"); error = pdf_allocobject(xref, &eoid, &egen); if (error) return error; pdf_cryptobj(encrypt, encrypt->encrypt, eoid, egen); error = pdf_updateobject(xref, eoid, egen, encrypt->encrypt); if (error) return error; } ofsbuf = fz_malloc(sizeof(int) * xref->len); if (!ofsbuf) return fz_outofmem; error = fz_openwfile(&out, path); if (error) { fz_free(ofsbuf); return error; } fz_print(out, "%%PDF-%1.1f\n", xref->version); fz_print(out, "%%\342\343\317\323\n\n"); for (oid = 0; oid < xref->len; oid++) { pdf_xrefentry *x = xref->table + oid; if (x->type == 'n' || x->type == 'o' || x->type == 'a') { ofsbuf[oid] = fz_tell(out); error = writeobject(out, xref, encrypt, oid, x->type == 'o' ? 0 : x->gen); if (error) goto cleanup; } else { ofsbuf[oid] = x->ofs; } } startxref = fz_tell(out); fz_print(out, "xref\n"); fz_print(out, "0 %d\n", xref->len); for (oid = 0; oid < xref->len; oid++) { int gen = xref->table[oid].gen; int type = xref->table[oid].type; if (type == 'o') gen = 0; if (type == 'a' || type == 'o') type = 'n'; if (type == 'd') type = 'f'; fz_print(out, "%010d %05d %c \n", ofsbuf[oid], gen, type); } fz_print(out, "\n"); fz_print(out, "trailer\n<<\n /Size %d", xref->len); obj = fz_dictgets(xref->trailer, "Root"); fz_print(out, "\n /Root %d %d R", fz_tonum(obj), fz_togen(obj)); obj = fz_dictgets(xref->trailer, "Info"); if (obj) fz_print(out, "\n /Info %d %d R", fz_tonum(obj), fz_togen(obj)); if (encrypt) { fz_print(out, "\n /Encrypt %d %d R", eoid, egen); fz_print(out, "\n /ID ["); fz_printobj(out, encrypt->id, 1); fz_printobj(out, encrypt->id, 1); fz_print(out, "]"); pdf_cryptobj(encrypt, encrypt->encrypt, eoid, egen); } fz_print(out, "\n>>\n\n"); fz_print(out, "startxref\n"); fz_print(out, "%d\n", startxref); fz_print(out, "%%%%EOF\n"); xref->startxref = startxref; if(ofsbuf) fz_free(ofsbuf); fz_dropstream(out); return nil; cleanup: if(ofsbuf) fz_free(ofsbuf); fz_dropstream(out); return error; }