summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorPaul Gardiner <paulg.artifex@glidos.net>2013-07-04 12:11:20 +0100
committerPaul Gardiner <paulg.artifex@glidos.net>2013-07-04 12:11:20 +0100
commitac84904af638b243284e24d5f401c3f1a21cb0ef (patch)
tree32e9f6b3b0d0ad83cb8f2dd0c41bc5e60b53ed3e /source
parentb33b3b41100f2bb0b63dbf270bdd4401451c081a (diff)
downloadmupdf-ac84904af638b243284e24d5f401c3f1a21cb0ef.tar.xz
Update pdf_write_document to support incremental update
Diffstat (limited to 'source')
-rw-r--r--source/pdf/pdf-write.c156
-rw-r--r--source/pdf/pdf-xref.c44
-rw-r--r--source/tools/pdfclean.c1
-rw-r--r--source/tools/pdfposter.c1
4 files changed, 149 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)
{
diff --git a/source/tools/pdfclean.c b/source/tools/pdfclean.c
index aac3a888..f42269a8 100644
--- a/source/tools/pdfclean.c
+++ b/source/tools/pdfclean.c
@@ -163,6 +163,7 @@ int pdfclean_main(int argc, char **argv)
int write_failed = 0;
int errors = 0;
+ opts.do_incremental = 0;
opts.do_garbage = 0;
opts.do_expand = 0;
opts.do_ascii = 0;
diff --git a/source/tools/pdfposter.c b/source/tools/pdfposter.c
index 981bf0c0..4702c2aa 100644
--- a/source/tools/pdfposter.c
+++ b/source/tools/pdfposter.c
@@ -133,6 +133,7 @@ int pdfposter_main(int argc, char **argv)
pdf_document *doc;
fz_context *ctx;
+ opts.do_incremental = 0;
opts.do_garbage = 0;
opts.do_expand = 0;
opts.do_ascii = 0;