diff options
author | Paul Gardiner <paulg.artifex@glidos.net> | 2013-08-22 11:17:07 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2013-08-22 11:20:30 +0100 |
commit | 0dc6ea4e4dd36ff69b54fa49ae397d2b98fe84b2 (patch) | |
tree | 5505b571b93c6a19a14a2595199c42ed9886e60d /source | |
parent | 768a56a43c8104a0292f4a35e85cde12fbb40a5c (diff) | |
download | mupdf-0dc6ea4e4dd36ff69b54fa49ae397d2b98fe84b2.tar.xz |
Add support for writing of xref streams
Use of the feature is currently enabled only in the case that a file
that already contains xref streams is being updated incrementally. To
do so in that case is necessary because an old-style xref is then not
permitted.
This fixes bug #694527
Diffstat (limited to 'source')
-rw-r--r-- | source/pdf/pdf-write.c | 139 | ||||
-rw-r--r-- | source/pdf/pdf-xref.c | 2 |
2 files changed, 137 insertions, 4 deletions
diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c index fd126aac..de2dc810 100644 --- a/source/pdf/pdf-write.c +++ b/source/pdf/pdf-write.c @@ -1637,7 +1637,7 @@ static int filter_implies_image(pdf_document *doc, pdf_obj *o) return 0; } -static void writeobject(pdf_document *doc, pdf_write_options *opts, int num, int gen) +static void writeobject(pdf_document *doc, pdf_write_options *opts, int num, int gen, int skip_xrefs) { pdf_xref_entry *entry; pdf_obj *obj; @@ -1673,7 +1673,7 @@ static void writeobject(pdf_document *doc, pdf_write_options *opts, int num, int pdf_drop_obj(obj); return; } - if (pdf_is_name(type) && !strcmp(pdf_to_name(type), "XRef")) + if (skip_xrefs && pdf_is_name(type) && !strcmp(pdf_to_name(type), "XRef")) { opts->use_list[num] = 0; pdf_drop_obj(obj); @@ -1862,6 +1862,134 @@ static void writexref(pdf_document *doc, pdf_write_options *opts, int from, int pdf_drop_obj(trailer); fprintf(opts->out, "startxref\n%d\n%%%%EOF\n", startxref); + + doc->has_xref_streams = 0; +} + +static void writexrefstreamsubsect(pdf_document *doc, pdf_write_options *opts, pdf_obj *index, fz_buffer *fzbuf, int from, int to) +{ + int num; + + pdf_array_push_drop(index, pdf_new_int(doc, from)); + pdf_array_push_drop(index, pdf_new_int(doc, to - from)); + for (num = from; num < to; num++) + { + fz_write_buffer_byte(doc->ctx, fzbuf, opts->use_list[num] ? 1 : 0); + fz_write_buffer_byte(doc->ctx, fzbuf, opts->ofs_list[num]>>24); + fz_write_buffer_byte(doc->ctx, fzbuf, opts->ofs_list[num]>>16); + fz_write_buffer_byte(doc->ctx, fzbuf, opts->ofs_list[num]>>8); + fz_write_buffer_byte(doc->ctx, fzbuf, opts->ofs_list[num]); + fz_write_buffer_byte(doc->ctx, fzbuf, opts->gen_list[num]); + } +} + +static void writexrefstream(pdf_document *doc, pdf_write_options *opts, int from, int to, int first, int main_xref_offset, int startxref) +{ + fz_context *ctx = doc->ctx; + int num; + pdf_obj *dict = NULL; + pdf_obj *obj; + pdf_obj *w = NULL; + pdf_obj *index; + fz_buffer *fzbuf = NULL; + + fz_var(dict); + fz_var(w); + fz_var(fzbuf); + fz_try(ctx) + { + num = pdf_create_object(doc); + dict = pdf_new_dict(doc, 6); + pdf_update_object(doc, num, dict); + + opts->first_xref_entry_offset = ftell(opts->out); + + to++; + + if (first) + { + obj = pdf_dict_gets(pdf_trailer(doc), "Info"); + if (obj) + pdf_dict_puts(dict, "Info", obj); + + obj = pdf_dict_gets(pdf_trailer(doc), "Root"); + if (obj) + pdf_dict_puts(dict, "Root", obj); + + obj = pdf_dict_gets(pdf_trailer(doc), "ID"); + if (obj) + pdf_dict_puts(dict, "ID", obj); + } + + pdf_dict_puts_drop(dict, "Size", pdf_new_int(doc, to)); + + if (opts->do_incremental) + { + pdf_dict_puts_drop(dict, "Prev", pdf_new_int(doc, doc->startxref)); + doc->startxref = startxref; + } + else + { + if (main_xref_offset != 0) + pdf_dict_puts_drop(dict, "Prev", pdf_new_int(doc, main_xref_offset)); + } + + pdf_dict_puts_drop(dict, "Type", pdf_new_name(doc, "XRef")); + + w = pdf_new_array(doc, 3); + pdf_dict_puts(dict, "W", w); + pdf_array_push_drop(w, pdf_new_int(doc, 1)); + pdf_array_push_drop(w, pdf_new_int(doc, 4)); + pdf_array_push_drop(w, pdf_new_int(doc, 1)); + + index = pdf_new_array(doc, 2); + pdf_dict_puts_drop(dict, "Index", index); + + opts->ofs_list[num] = opts->first_xref_entry_offset; + + fzbuf = fz_new_buffer(ctx, 4*(to-from)); + + 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) + writexrefstreamsubsect(doc, opts, index, fzbuf, subfrom, subto); + + subfrom = subto; + } + } + else + { + writexrefstreamsubsect(doc, opts, index, fzbuf, from, to); + } + + pdf_update_stream(doc, num, fzbuf); + pdf_dict_puts_drop(dict, "Length", pdf_new_int(doc, fz_buffer_storage(ctx, fzbuf, NULL))); + + writeobject(doc, opts, num, 0, 0); + fprintf(opts->out, "startxref\n%d\n%%%%EOF\n", startxref); + } + fz_always(ctx) + { + pdf_drop_obj(dict); + pdf_drop_obj(w); + fz_drop_buffer(ctx, fzbuf); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } } static void @@ -1905,7 +2033,7 @@ dowriteobject(pdf_document *doc, pdf_write_options *opts, int num, int pass) padto(opts->out, opts->ofs_list[num]); opts->ofs_list[num] = ftell(opts->out); if (!opts->do_incremental || pdf_xref_is_incremental(doc, num)) - writeobject(doc, opts, num, opts->gen_list[num]); + writeobject(doc, opts, num, opts->gen_list[num], 1); } else opts->use_list[num] = 0; @@ -2524,7 +2652,10 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_ else { opts.first_xref_offset = ftell(opts.out); - writexref(doc, &opts, 0, xref_len, 1, 0, opts.first_xref_offset); + if (opts.do_incremental && doc->has_xref_streams) + writexrefstream(doc, &opts, 0, xref_len, 1, 0, opts.first_xref_offset); + else + writexref(doc, &opts, 0, xref_len, 1, 0, opts.first_xref_offset); } fclose(opts.out); diff --git a/source/pdf/pdf-xref.c b/source/pdf/pdf-xref.c index eaf250cf..a8aace68 100644 --- a/source/pdf/pdf-xref.c +++ b/source/pdf/pdf-xref.c @@ -533,6 +533,8 @@ pdf_read_new_xref_section(pdf_document *doc, fz_stream *stm, int i0, int i1, int entry->gen = w2 ? c : 0; } } + + doc->has_xref_streams = 1; } /* Entered with file locked, remains locked throughout. */ |