diff options
author | Paul Gardiner <paulg.artifex@glidos.net> | 2013-07-04 12:11:20 +0100 |
---|---|---|
committer | Paul Gardiner <paulg.artifex@glidos.net> | 2013-07-04 12:11:20 +0100 |
commit | ac84904af638b243284e24d5f401c3f1a21cb0ef (patch) | |
tree | 32e9f6b3b0d0ad83cb8f2dd0c41bc5e60b53ed3e /source/pdf | |
parent | b33b3b41100f2bb0b63dbf270bdd4401451c081a (diff) | |
download | mupdf-ac84904af638b243284e24d5f401c3f1a21cb0ef.tar.xz |
Update pdf_write_document to support incremental update
Diffstat (limited to 'source/pdf')
-rw-r--r-- | source/pdf/pdf-write.c | 156 | ||||
-rw-r--r-- | source/pdf/pdf-xref.c | 44 |
2 files changed, 147 insertions, 53 deletions
diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c index 4e6ddb21..63fab4f1 100644 --- a/source/pdf/pdf-write.c +++ b/source/pdf/pdf-write.c @@ -46,6 +46,7 @@ typedef struct { struct pdf_write_options_s { FILE *out; + int do_incremental; int do_ascii; int do_expand; int do_garbage; @@ -1750,16 +1751,11 @@ static void writeobject(pdf_document *doc, pdf_write_options *opts, int num, int pdf_drop_obj(obj); } -static void writexref(pdf_document *doc, pdf_write_options *opts, int from, int to, int first, int main_xref_offset, int startxref) +static void writexrefsubsect(pdf_write_options *opts, int from, int to) { - pdf_obj *trailer = NULL; - pdf_obj *obj; - pdf_obj *nobj = NULL; int num; - fz_context *ctx = doc->ctx; - fprintf(opts->out, "xref\n%d %d\n", from, to - from); - opts->first_xref_entry_offset = ftell(opts->out); + fprintf(opts->out, "%d %d\n", from, to - from); for (num = from; num < to; num++) { if (opts->use_list[num]) @@ -1767,6 +1763,43 @@ static void writexref(pdf_document *doc, pdf_write_options *opts, int from, int else fprintf(opts->out, "%010d %05d f \n", opts->ofs_list[num], opts->gen_list[num]); } +} + +static void writexref(pdf_document *doc, pdf_write_options *opts, int from, int to, int first, int main_xref_offset, int startxref) +{ + pdf_obj *trailer = NULL; + pdf_obj *obj; + pdf_obj *nobj = NULL; + fz_context *ctx = doc->ctx; + + fprintf(opts->out, "xref\n"); + opts->first_xref_entry_offset = ftell(opts->out); + + if (opts->do_incremental) + { + int subfrom = from; + int subto; + + while (subfrom < to) + { + while (subfrom < to && !pdf_xref_is_incremental(doc, subfrom)) + subfrom++; + + subto = subfrom; + while (subto < to && pdf_xref_is_incremental(doc, subto)) + subto++; + + if (subfrom < subto) + writexrefsubsect(opts, subfrom, subto); + + subfrom = subto; + } + } + else + { + writexrefsubsect(opts, from, to); + } + fprintf(opts->out, "\n"); fz_var(trailer); @@ -1774,33 +1807,43 @@ static void writexref(pdf_document *doc, pdf_write_options *opts, int from, int fz_try(ctx) { - trailer = pdf_new_dict(doc, 5); - - nobj = pdf_new_int(doc, to); - pdf_dict_puts(trailer, "Size", nobj); - pdf_drop_obj(nobj); - nobj = NULL; - - if (first) + if (opts->do_incremental) { - obj = pdf_dict_gets(pdf_trailer(doc), "Info"); - if (obj) - pdf_dict_puts(trailer, "Info", obj); - - obj = pdf_dict_gets(pdf_trailer(doc), "Root"); - if (obj) - pdf_dict_puts(trailer, "Root", obj); - - obj = pdf_dict_gets(pdf_trailer(doc), "ID"); - if (obj) - pdf_dict_puts(trailer, "ID", obj); + trailer = pdf_keep_obj(pdf_trailer(doc)); + pdf_dict_puts_drop(trailer, "Size", pdf_new_int(doc, pdf_xref_len(doc))); + pdf_dict_puts_drop(trailer, "Prev", pdf_new_int(doc, doc->startxref)); + doc->startxref = startxref; } - if (main_xref_offset != 0) + else { - nobj = pdf_new_int(doc, main_xref_offset); - pdf_dict_puts(trailer, "Prev", nobj); + trailer = pdf_new_dict(doc, 5); + + nobj = pdf_new_int(doc, to); + pdf_dict_puts(trailer, "Size", nobj); pdf_drop_obj(nobj); nobj = NULL; + + if (first) + { + obj = pdf_dict_gets(pdf_trailer(doc), "Info"); + if (obj) + pdf_dict_puts(trailer, "Info", obj); + + obj = pdf_dict_gets(pdf_trailer(doc), "Root"); + if (obj) + pdf_dict_puts(trailer, "Root", obj); + + obj = pdf_dict_gets(pdf_trailer(doc), "ID"); + if (obj) + pdf_dict_puts(trailer, "ID", obj); + } + if (main_xref_offset != 0) + { + nobj = pdf_new_int(doc, main_xref_offset); + pdf_dict_puts(trailer, "Prev", nobj); + pdf_drop_obj(nobj); + nobj = NULL; + } } } fz_always(ctx) @@ -1861,7 +1904,8 @@ dowriteobject(pdf_document *doc, pdf_write_options *opts, int num, int pass) if (pass > 0) padto(opts->out, opts->ofs_list[num]); opts->ofs_list[num] = ftell(opts->out); - writeobject(doc, opts, num, opts->gen_list[num]); + if (!opts->do_incremental || pdf_xref_is_incremental(doc, num)) + writeobject(doc, opts, num, opts->gen_list[num]); } else opts->use_list[num] = 0; @@ -1873,8 +1917,11 @@ writeobjects(pdf_document *doc, pdf_write_options *opts, int pass) int num; int xref_len = pdf_xref_len(doc); - fprintf(opts->out, "%%PDF-%d.%d\n", doc->version / 10, doc->version % 10); - fprintf(opts->out, "%%\316\274\341\277\246\n\n"); + if (!opts->do_incremental) + { + fprintf(opts->out, "%%PDF-%d.%d\n", doc->version / 10, doc->version % 10); + fprintf(opts->out, "%%\316\274\341\277\246\n\n"); + } dowriteobject(doc, opts, opts->start, pass); @@ -2241,12 +2288,23 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_ xref_len = pdf_xref_len(doc); - opts.out = fopen(filename, "wb"); + if (fz_opts->do_incremental) + { + opts.out = fopen(filename, "ab"); + if (opts.out) + fseek(opts.out, 0, SEEK_END); + } + else + { + opts.out = fopen(filename, "wb"); + } + if (!opts.out) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open output file '%s'", filename); fz_try(ctx) { + opts.do_incremental = fz_opts ? fz_opts->do_incremental : 0; opts.do_expand = fz_opts ? fz_opts->do_expand : 0; opts.do_garbage = fz_opts ? fz_opts->do_garbage : 0; opts.do_ascii = fz_opts ? fz_opts->do_ascii: 0; @@ -2275,7 +2333,8 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_ } /* Make sure any objects hidden in compressed streams have been loaded */ - preloadobjstms(doc); + if (!opts.do_incremental) + preloadobjstms(doc); /* Sweep & mark objects from the trailer */ if (opts.do_garbage >= 1) @@ -2307,15 +2366,30 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_ dump_object_details(doc, &opts); #endif - /* Construct linked list of free object slots */ - lastfree = 0; - for (num = 0; num < xref_len; num++) + if (opts.do_incremental) { - if (!opts.use_list[num]) + for (num = 0; num < xref_len; num++) { - opts.gen_list[num]++; - opts.ofs_list[lastfree] = num; - lastfree = num; + if (!opts.use_list[num] && pdf_xref_is_incremental(doc, num)) + { + /* Make unreusable. FIXME: would be better to link to existing free list */ + opts.gen_list[num] = 65535; + opts.ofs_list[num] = 0; + } + } + } + else + { + /* Construct linked list of free object slots */ + lastfree = 0; + for (num = 0; num < xref_len; num++) + { + if (!opts.use_list[num]) + { + opts.gen_list[num]++; + opts.ofs_list[lastfree] = num; + lastfree = num; + } } } diff --git a/source/pdf/pdf-xref.c b/source/pdf/pdf-xref.c index 0337bb16..71213fd7 100644 --- a/source/pdf/pdf-xref.c +++ b/source/pdf/pdf-xref.c @@ -154,21 +154,34 @@ pdf_xref_entry *pdf_get_xref_entry(pdf_document *doc, int i) static void ensure_incremental_xref(pdf_document *doc) { fz_context *ctx = doc->ctx; - pdf_xref *xref, *pxref; if (!doc->xref_altered) { - pdf_xref_entry *new_table; - doc->xref_sections = fz_resize_array(ctx, doc->xref_sections, doc->num_xref_sections + 1, sizeof(pdf_xref)); - xref = &doc->xref_sections[0]; - pxref = &doc->xref_sections[1]; - new_table = fz_calloc(ctx, xref->len, sizeof(pdf_xref_entry)); - memmove(pxref, xref, doc->num_xref_sections * sizeof(pdf_xref)); - doc->num_xref_sections++; - /* xref->len is already correct */ - xref->table = new_table; - xref->trailer = pdf_keep_obj(pxref->trailer); - doc->xref_altered = 1; + pdf_xref *xref = &doc->xref_sections[0]; + pdf_xref *pxref; + pdf_xref_entry *new_table = fz_calloc(ctx, xref->len, sizeof(pdf_xref_entry)); + pdf_obj *trailer = NULL; + + fz_var(trailer); + fz_try(ctx) + { + trailer = pdf_copy_dict(xref->trailer); + doc->xref_sections = fz_resize_array(ctx, doc->xref_sections, doc->num_xref_sections + 1, sizeof(pdf_xref)); + xref = &doc->xref_sections[0]; + pxref = &doc->xref_sections[1]; + memmove(pxref, xref, doc->num_xref_sections * sizeof(pdf_xref)); + /* xref->len is already correct */ + xref->table = new_table; + xref->trailer = trailer; + doc->num_xref_sections++; + doc->xref_altered = 1; + } + fz_catch(ctx) + { + fz_free(ctx, new_table); + pdf_drop_obj(trailer); + fz_rethrow(ctx); + } } } @@ -188,6 +201,13 @@ static pdf_xref_entry *pdf_get_incremental_xref_entry(pdf_document *doc, int i) return &xref->table[i]; } +int pdf_xref_is_incremental(pdf_document *doc, int num) +{ + pdf_xref *xref = &doc->xref_sections[0]; + + return doc->xref_altered && num < xref->len && xref->table[num].type; +} + /* Ensure that an object has been cloned into the incremental xref section */ void pdf_xref_ensure_incremental_object(pdf_document *doc, int num) { |