summaryrefslogtreecommitdiff
path: root/source/pdf
diff options
context:
space:
mode:
authorPaul Gardiner <paulg.artifex@glidos.net>2013-06-28 11:29:51 +0100
committerRobin Watts <robin.watts@artifex.com>2013-06-28 19:36:16 +0100
commit3b1d2b99bd2aa3f02e0e6aa26ec862f28722a011 (patch)
tree0fb16843d644e9749aeb91c0bf27cbae288747ff /source/pdf
parent063c7175976213010ce1c3c96c4d4b9703239eb0 (diff)
downloadmupdf-3b1d2b99bd2aa3f02e0e6aa26ec862f28722a011.tar.xz
Ensure altered objects are moved to the incremental xref section
Diffstat (limited to 'source/pdf')
-rw-r--r--source/pdf/pdf-annot.c17
-rw-r--r--source/pdf/pdf-object.c63
-rw-r--r--source/pdf/pdf-repair.c2
-rw-r--r--source/pdf/pdf-write.c2
-rw-r--r--source/pdf/pdf-xref.c74
5 files changed, 136 insertions, 22 deletions
diff --git a/source/pdf/pdf-annot.c b/source/pdf/pdf-annot.c
index 5e50f0a2..9c93ac93 100644
--- a/source/pdf/pdf-annot.c
+++ b/source/pdf/pdf-annot.c
@@ -705,7 +705,6 @@ pdf_create_annot(pdf_document *doc, pdf_page *page, fz_annot_type type)
annot = fz_malloc_struct(ctx, pdf_annot);
annot->page = page;
- annot->obj = pdf_keep_obj(annot_obj);
annot->rect = rect;
annot->pagerect = rect;
annot->ap = NULL;
@@ -721,6 +720,7 @@ pdf_create_annot(pdf_document *doc, pdf_page *page, fz_annot_type type)
pdf_update_object(doc, ind_obj_num, annot_obj);
ind_obj = pdf_new_indirect(doc, ind_obj_num, 0);
pdf_array_push(annot_arr, ind_obj);
+ annot->obj = pdf_keep_obj(ind_obj);
/*
Linking must be done after any call that might throw because
@@ -794,11 +794,13 @@ pdf_delete_annot(pdf_document *doc, pdf_page *page, pdf_annot *annot)
pdf_array_push(annot_arr, obj);
}
- /*
- Overwrite "Annots" in the page dictionary, which has the
- side-effect of releasing the last reference to old_annot_arr
- */
- pdf_dict_puts(page->me, "Annots", annot_arr);
+ if (pdf_is_indirect(old_annot_arr))
+ pdf_update_object(doc, pdf_to_num(old_annot_arr), annot_arr);
+ else
+ pdf_dict_puts(page->me, "Annots", annot_arr);
+
+ if (pdf_is_indirect(annot->obj))
+ pdf_delete_object(doc, pdf_to_num(annot->obj));
}
fz_always(ctx)
{
@@ -985,7 +987,7 @@ pdf_set_annot_appearance(pdf_document *doc, pdf_annot *annot, fz_rect *rect, fz_
/* See if there is a current normal appearance */
ap_obj = pdf_dict_getp(obj, "AP/N");
- if (!pdf_is_stream(doc, pdf_to_num(obj), pdf_to_gen(obj)))
+ if (!pdf_is_stream(doc, pdf_to_num(ap_obj), pdf_to_gen(ap_obj)))
ap_obj = NULL;
if (ap_obj == NULL)
@@ -995,6 +997,7 @@ pdf_set_annot_appearance(pdf_document *doc, pdf_annot *annot, fz_rect *rect, fz_
}
else
{
+ pdf_xref_ensure_incremental_object(doc, pdf_to_num(ap_obj));
pdf_dict_puts_drop(ap_obj, "Rect", pdf_new_rect(doc, &trect));
pdf_dict_puts_drop(ap_obj, "Matrix", pdf_new_matrix(doc, &mat));
}
diff --git a/source/pdf/pdf-object.c b/source/pdf/pdf-object.c
index 037f1e16..88af2639 100644
--- a/source/pdf/pdf-object.c
+++ b/source/pdf/pdf-object.c
@@ -34,6 +34,7 @@ struct pdf_obj_s
unsigned char kind;
unsigned char flags;
pdf_document *doc;
+ int parent_num;
union
{
int b;
@@ -71,6 +72,7 @@ pdf_new_null(pdf_document *doc)
obj->refs = 1;
obj->kind = PDF_NULL;
obj->flags = 0;
+ obj->parent_num = 0;
return obj;
}
@@ -84,6 +86,7 @@ pdf_new_bool(pdf_document *doc, int b)
obj->refs = 1;
obj->kind = PDF_BOOL;
obj->flags = 0;
+ obj->parent_num = 0;
obj->u.b = b;
return obj;
}
@@ -98,6 +101,7 @@ pdf_new_int(pdf_document *doc, int i)
obj->refs = 1;
obj->kind = PDF_INT;
obj->flags = 0;
+ obj->parent_num = 0;
obj->u.i = i;
return obj;
}
@@ -112,6 +116,7 @@ pdf_new_real(pdf_document *doc, float f)
obj->refs = 1;
obj->kind = PDF_REAL;
obj->flags = 0;
+ obj->parent_num = 0;
obj->u.f = f;
return obj;
}
@@ -126,6 +131,7 @@ pdf_new_string(pdf_document *doc, const char *str, int len)
obj->refs = 1;
obj->kind = PDF_STRING;
obj->flags = 0;
+ obj->parent_num = 0;
obj->u.s.len = len;
memcpy(obj->u.s.buf, str, len);
obj->u.s.buf[len] = '\0';
@@ -142,6 +148,7 @@ pdf_new_name(pdf_document *doc, const char *str)
obj->refs = 1;
obj->kind = PDF_NAME;
obj->flags = 0;
+ obj->parent_num = 0;
strcpy(obj->u.n, str);
return obj;
}
@@ -156,6 +163,7 @@ pdf_new_indirect(pdf_document *doc, int num, int gen)
obj->refs = 1;
obj->kind = PDF_INDIRECT;
obj->flags = 0;
+ obj->parent_num = 0;
obj->u.r.num = num;
obj->u.r.gen = gen;
return obj;
@@ -442,6 +450,7 @@ pdf_new_array(pdf_document *doc, int initialcap)
obj->refs = 1;
obj->kind = PDF_ARRAY;
obj->flags = 0;
+ obj->parent_num = 0;
obj->u.a.len = 0;
obj->u.a.cap = initialcap > 1 ? initialcap : 6;
@@ -519,6 +528,24 @@ pdf_array_get(pdf_obj *obj, int i)
return obj->u.a.items[i];
}
+static void object_altered(pdf_obj *obj, pdf_obj *val)
+{
+ /*
+ parent_num = 0 while an object is being parsed from the file.
+ No further action is necessary.
+ */
+ if (obj->parent_num == 0 || obj->doc->freeze_updates)
+ return;
+
+ /*
+ Otherwise we need to ensure that the containing hierarchy of objects
+ has been moved to the incremental xref section and the newly linked
+ object needs to record the parent_num
+ */
+ pdf_xref_ensure_incremental_object(obj->doc, obj->parent_num);
+ pdf_set_objects_parent_num(val, obj->parent_num);
+}
+
void
pdf_array_put(pdf_obj *obj, int i, pdf_obj *item)
{
@@ -537,6 +564,8 @@ pdf_array_put(pdf_obj *obj, int i, pdf_obj *item)
pdf_drop_obj(obj->u.a.items[i]);
obj->u.a.items[i] = pdf_keep_obj(item);
}
+
+ object_altered(obj, item);
}
void
@@ -555,6 +584,8 @@ pdf_array_push(pdf_obj *obj, pdf_obj *item)
obj->u.a.items[obj->u.a.len] = pdf_keep_obj(item);
obj->u.a.len++;
}
+
+ object_altered(obj, item);
}
void
@@ -593,6 +624,8 @@ pdf_array_insert(pdf_obj *obj, pdf_obj *item)
obj->u.a.items[0] = pdf_keep_obj(item);
obj->u.a.len++;
}
+
+ object_altered(obj, item);
}
int
@@ -723,6 +756,7 @@ pdf_new_dict(pdf_document *doc, int initialcap)
obj->refs = 1;
obj->kind = PDF_DICT;
obj->flags = 0;
+ obj->parent_num = 0;
obj->u.d.len = 0;
obj->u.d.cap = initialcap > 1 ? initialcap : 10;
@@ -987,6 +1021,8 @@ pdf_dict_put(pdf_obj *obj, pdf_obj *key, pdf_obj *val)
obj->u.d.items[i].v = pdf_keep_obj(val);
obj->u.d.len ++;
}
+
+ object_altered(obj, val);
}
void
@@ -1136,6 +1172,8 @@ pdf_dict_dels(pdf_obj *obj, const char *key)
obj->u.d.len --;
}
}
+
+ object_altered(obj, NULL);
}
void
@@ -1274,6 +1312,31 @@ pdf_drop_obj(pdf_obj *obj)
fz_free(obj->doc->ctx, obj);
}
+void
+pdf_set_objects_parent_num(pdf_obj *obj, int num)
+{
+ int n, i;
+
+ if (!obj)
+ return;
+
+ obj->parent_num = num;
+
+ switch(obj->kind)
+ {
+ case PDF_ARRAY:
+ n = pdf_array_len(obj);
+ for (i = 0; i < n; i++)
+ pdf_set_objects_parent_num(pdf_array_get(obj, i), num);
+ break;
+ case PDF_DICT:
+ n = pdf_dict_len(obj);
+ for (i = 0; i < n; i++)
+ pdf_set_objects_parent_num(pdf_dict_get_val(obj, i), num);
+ break;
+ }
+}
+
pdf_obj *pdf_new_obj_from_str(pdf_document *doc, const char *src)
{
pdf_obj *result;
diff --git a/source/pdf/pdf-repair.c b/source/pdf/pdf-repair.c
index bf4bcf89..3db32de0 100644
--- a/source/pdf/pdf-repair.c
+++ b/source/pdf/pdf-repair.c
@@ -256,6 +256,8 @@ pdf_repair_xref(pdf_document *doc, pdf_lexbuf *buf)
fz_var(obj);
doc->dirty = 1;
+ /* Can't support incremental update after repair */
+ doc->freeze_updates = 1;
fz_seek(doc->file, 0, 0);
diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c
index 79271499..9d768d0f 100644
--- a/source/pdf/pdf-write.c
+++ b/source/pdf/pdf-write.c
@@ -2225,6 +2225,7 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_
if (!doc)
return;
+ doc->freeze_updates = 1;
ctx = doc->ctx;
pdf_finish_edit(doc);
@@ -2356,6 +2357,7 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_
pdf_drop_obj(opts.hints_length);
page_objects_list_destroy(ctx, opts.page_object_lists);
fclose(opts.out);
+ doc->freeze_updates = 0;
}
fz_catch(ctx)
{
diff --git a/source/pdf/pdf-xref.c b/source/pdf/pdf-xref.c
index 91083468..a67f6bc7 100644
--- a/source/pdf/pdf-xref.c
+++ b/source/pdf/pdf-xref.c
@@ -147,26 +147,39 @@ pdf_xref_entry *pdf_get_xref_entry(pdf_document *doc, int i)
return &doc->xref_sections[0].table[i];
}
-/* Used when altering a document */
-static pdf_xref_entry *pdf_get_new_xref_entry(pdf_document *doc, int i)
+/*
+ Ensure we have an incremental xref section where we can store
+ updated versions of indirect objects
+*/
+static void ensure_incremental_xref(pdf_document *doc)
{
fz_context *ctx = doc->ctx;
- pdf_xref *xref;
+ pdf_xref *xref, *pxref;
- /* Make a new final xref section if we haven't already */
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));
- memmove(&doc->xref_sections[1], &doc->xref_sections[0], doc->num_xref_sections * sizeof(pdf_xref));
- doc->num_xref_sections++;
xref = &doc->xref_sections[0];
- xref->len = 0;
- xref->table = NULL;
- xref->trailer = pdf_keep_obj(doc->xref_sections[1].trailer);
- /* All new levels must be at least as big as the level before */
- pdf_resize_xref(ctx, xref, fz_maxi(i+1, doc->xref_sections[1].len));
+ 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;
}
+}
+
+/* Used when altering a document */
+static pdf_xref_entry *pdf_get_incremental_xref_entry(pdf_document *doc, int i)
+{
+ fz_context *ctx = doc->ctx;
+ pdf_xref *xref;
+
+ /* Make a new final xref section if we haven't already */
+ ensure_incremental_xref(doc);
xref = &doc->xref_sections[0];
if (i >= xref->len)
@@ -175,6 +188,36 @@ static pdf_xref_entry *pdf_get_new_xref_entry(pdf_document *doc, int i)
return &xref->table[i];
}
+/* Ensure that an object has been cloned into the incremental xref section */
+void pdf_xref_ensure_incremental_object(pdf_document *doc, int num)
+{
+ fz_context *ctx = doc->ctx;
+ pdf_xref_entry *new_entry, *old_entry;
+ int i;
+
+ /* Make sure we have created an xref section for incremental updates */
+ ensure_incremental_xref(doc);
+
+ /* Search for the section that contains this object */
+ for (i = 0; i < doc->num_xref_sections; i++)
+ {
+ pdf_xref *xref = &doc->xref_sections[i];
+ if (num >= 0 && num < xref->len && xref->table[num].type)
+ break;
+ }
+
+ /* If we don't find it, or it's already in the incremental section, return */
+ if (i == 0 || i == doc->num_xref_sections)
+ return;
+
+ /* Move the object to the incremental section */
+ old_entry = &doc->xref_sections[i].table[num];
+ new_entry = pdf_get_incremental_xref_entry(doc, num);
+ *new_entry = *old_entry;
+ old_entry->obj = NULL;
+ old_entry->stm_buf = NULL;
+}
+
void pdf_replace_xref(pdf_document *doc, pdf_xref_entry *entries, int n)
{
fz_context *ctx = doc->ctx;
@@ -1213,7 +1256,6 @@ pdf_cache_object(pdf_document *doc, int num, int gen)
if (x->type == 'f')
{
x->obj = pdf_new_null(doc);
- return;
}
else if (x->type == 'n')
{
@@ -1259,6 +1301,8 @@ pdf_cache_object(pdf_document *doc, int num, int gen)
{
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find object in xref (%d %d R)", num, gen);
}
+
+ pdf_set_objects_parent_num(x->obj, num);
}
pdf_obj *
@@ -1337,7 +1381,7 @@ pdf_create_object(pdf_document *doc)
/* TODO: reuse free object slots by properly linking free object chains in the ofs field */
pdf_xref_entry *entry;
int num = pdf_xref_len(doc);
- entry = pdf_get_new_xref_entry(doc, num);
+ entry = pdf_get_incremental_xref_entry(doc, num);
entry->type = 'f';
entry->ofs = -1;
entry->gen = 0;
@@ -1358,7 +1402,7 @@ pdf_delete_object(pdf_document *doc, int num)
return;
}
- x = pdf_get_new_xref_entry(doc, num);
+ x = pdf_get_incremental_xref_entry(doc, num);
fz_drop_buffer(doc->ctx, x->stm_buf);
pdf_drop_obj(x->obj);
@@ -1382,7 +1426,7 @@ pdf_update_object(pdf_document *doc, int num, pdf_obj *newobj)
return;
}
- x = pdf_get_new_xref_entry(doc, num);
+ x = pdf_get_incremental_xref_entry(doc, num);
pdf_drop_obj(x->obj);