summaryrefslogtreecommitdiff
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
parentb33b3b41100f2bb0b63dbf270bdd4401451c081a (diff)
downloadmupdf-ac84904af638b243284e24d5f401c3f1a21cb0ef.tar.xz
Update pdf_write_document to support incremental update
-rw-r--r--include/mupdf/fitz/write-document.h1
-rw-r--r--include/mupdf/pdf/xref.h1
-rw-r--r--platform/android/jni/mupdf.c31
-rw-r--r--platform/x11/jstest_main.c4
-rw-r--r--platform/x11/pdfapp.c7
-rw-r--r--platform/x11/pdfapp.h1
-rw-r--r--platform/x11/win_main.c22
-rw-r--r--platform/x11/x11_main.c11
-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
12 files changed, 220 insertions, 60 deletions
diff --git a/include/mupdf/fitz/write-document.h b/include/mupdf/fitz/write-document.h
index f345cc56..9fe27f5f 100644
--- a/include/mupdf/fitz/write-document.h
+++ b/include/mupdf/fitz/write-document.h
@@ -12,6 +12,7 @@
*/
struct fz_write_options_s
{
+ int do_incremental; /* Write just the changed objects */
int do_ascii; /* If non-zero then attempt (where possible) to make
the output ascii. */
int do_expand; /* Bitflags; each non zero bit indicates an aspect
diff --git a/include/mupdf/pdf/xref.h b/include/mupdf/pdf/xref.h
index c0544717..5d4ecde9 100644
--- a/include/mupdf/pdf/xref.h
+++ b/include/mupdf/pdf/xref.h
@@ -76,6 +76,7 @@ pdf_xref_entry *pdf_get_populating_xref_entry(pdf_document *doc, int i);
pdf_xref_entry *pdf_get_xref_entry(pdf_document *doc, int i);
void pdf_replace_xref(pdf_document *doc, pdf_xref_entry *entries, int n);
void pdf_xref_ensure_incremental_object(pdf_document *doc, int num);
+int pdf_xref_is_incremental(pdf_document *doc, int num);
void pdf_repair_xref(pdf_document *doc, pdf_lexbuf *buf);
void pdf_repair_obj_stms(pdf_document *doc);
diff --git a/platform/android/jni/mupdf.c b/platform/android/jni/mupdf.c
index bb827778..889abe07 100644
--- a/platform/android/jni/mupdf.c
+++ b/platform/android/jni/mupdf.c
@@ -2342,21 +2342,42 @@ JNI_FN(MuPDFCore_saveInternal)(JNIEnv * env, jobject thiz)
{
char *tmp;
fz_write_options opts;
- opts.do_ascii = 1;
+ opts.do_incremental = 1;
+ opts.do_ascii = 0;
opts.do_expand = 0;
- opts.do_garbage = 1;
+ opts.do_garbage = 0;
opts.do_linear = 0;
tmp = tmp_path(glo->current_path);
if (tmp)
{
- int written;
+ int written = 0;
fz_var(written);
fz_try(ctx)
{
- fz_write_document(glo->doc, tmp, &opts);
- written = 1;
+ FILE *fin = fopen(glo->current_path, "rb");
+ FILE *fout = fopen(tmp, "wb");
+ char buf[256];
+ int n, err = 1;
+
+ if (fin && fout)
+ {
+ while ((n = fread(buf, 1, sizeof(buf), fin)) > 0)
+ fwrite(buf, 1, n, fout);
+ err = (ferror(fin) || ferror(fout));
+ }
+
+ if (fin)
+ fclose(fin);
+ if (fout)
+ fclose(fout);
+
+ if (!err)
+ {
+ fz_write_document(glo->doc, tmp, &opts);
+ written = 1;
+ }
}
fz_catch(ctx)
{
diff --git a/platform/x11/jstest_main.c b/platform/x11/jstest_main.c
index 2003ad55..a07385bc 100644
--- a/platform/x11/jstest_main.c
+++ b/platform/x11/jstest_main.c
@@ -108,6 +108,10 @@ void winreplacefile(char *source, char *target)
{
}
+void wincopyfile(char *source, char *target)
+{
+}
+
void wincursor(pdfapp_t *app, int curs)
{
}
diff --git a/platform/x11/pdfapp.c b/platform/x11/pdfapp.c
index e76c6c7c..71561f14 100644
--- a/platform/x11/pdfapp.c
+++ b/platform/x11/pdfapp.c
@@ -299,13 +299,15 @@ static int pdfapp_save(pdfapp_t *app)
{
fz_write_options opts;
- opts.do_ascii = 1;
+ opts.do_incremental = 1;
+ opts.do_ascii = 0;
opts.do_expand = 0;
- opts.do_garbage = 1;
+ opts.do_garbage = 0;
opts.do_linear = 0;
if (strcmp(buf, app->docpath) != 0)
{
+ wincopyfile(app->docpath, buf);
fz_write_document(app->doc, buf, &opts);
return 1;
}
@@ -316,6 +318,7 @@ static int pdfapp_save(pdfapp_t *app)
fz_try(app->ctx)
{
+ wincopyfile(app->docpath, buf);
fz_write_document(app->doc, buf, &opts);
written = 1;
}
diff --git a/platform/x11/pdfapp.h b/platform/x11/pdfapp.h
index 3e40e0c4..0b89923e 100644
--- a/platform/x11/pdfapp.h
+++ b/platform/x11/pdfapp.h
@@ -42,6 +42,7 @@ extern void winalert(pdfapp_t *, pdf_alert_event *alert);
extern void winprint(pdfapp_t *);
extern void winadvancetimer(pdfapp_t *, float duration);
extern void winreplacefile(char *source, char *target);
+extern void wincopyfile(char *source, char *target);
struct pdfapp_s
{
diff --git a/platform/x11/win_main.c b/platform/x11/win_main.c
index cc01d539..a22e7fc0 100644
--- a/platform/x11/win_main.c
+++ b/platform/x11/win_main.c
@@ -248,6 +248,28 @@ void winreplacefile(char *source, char *target)
#endif
}
+void wincopyfile(char *source, char *target)
+{
+ wchar_t wsource[PATH_MAX];
+ wchar_t wtarget[PATH_MAX];
+
+ int sz = MultiByteToWideChar(CP_UTF8, 0, source, -1, wsource, PATH_MAX);
+ if (sz == 0)
+ {
+ winerror(&gapp, "cannot convert filename to Unicode");
+ return;
+ }
+
+ sz = MultiByteToWideChar(CP_UTF8, 0, target, -1, wtarget, PATH_MAX);
+ if (sz == 0)
+ {
+ winerror(&gapp, "cannot convert filename to Unicode");
+ return;
+ }
+
+ CopyFile(wsource, wtarget, FALSE);
+}
+
static char pd_filename[256] = "The file is encrypted.";
static char pd_password[256] = "";
static wchar_t pd_passwordw[256] = {0};
diff --git a/platform/x11/x11_main.c b/platform/x11/x11_main.c
index 481adce1..0bcb98f4 100644
--- a/platform/x11/x11_main.c
+++ b/platform/x11/x11_main.c
@@ -281,6 +281,17 @@ void winreplacefile(char *source, char *target)
rename(source, target);
}
+void wincopyfile(char *source, char *target)
+{
+ char *buf = malloc(strlen(source)+strlen(target)+4);
+ if (buf)
+ {
+ sprintf(buf, "cp %s %s", source, target);
+ system(buf);
+ free(buf);
+ }
+}
+
void cleanup(pdfapp_t *app)
{
fz_context *ctx = app->ctx;
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;