summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorPaul Gardiner <paulg.artifex@glidos.net>2013-08-22 11:17:07 +0100
committerRobin Watts <robin.watts@artifex.com>2013-08-22 11:20:30 +0100
commit0dc6ea4e4dd36ff69b54fa49ae397d2b98fe84b2 (patch)
tree5505b571b93c6a19a14a2595199c42ed9886e60d /source
parent768a56a43c8104a0292f4a35e85cde12fbb40a5c (diff)
downloadmupdf-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.c139
-rw-r--r--source/pdf/pdf-xref.c2
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. */