diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/pdf/pdf-annot.c | 17 | ||||
-rw-r--r-- | source/pdf/pdf-object.c | 63 | ||||
-rw-r--r-- | source/pdf/pdf-repair.c | 2 | ||||
-rw-r--r-- | source/pdf/pdf-write.c | 2 | ||||
-rw-r--r-- | source/pdf/pdf-xref.c | 74 |
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); |