static void load_portfolio(fz_context *ctx, pdf_document *doc) { pdf_obj *obj; int i, n; pdf_portfolio **pp; obj = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root, PDF_NAME_Collection, PDF_NAME_Schema, NULL); n = pdf_dict_len(ctx, obj); for (i = 0; i < n; i++) { pdf_obj *k = pdf_dict_get_key(ctx, obj, i); pdf_obj *v = pdf_dict_get_val(ctx, obj, i); int sort = pdf_to_int(ctx, pdf_dict_get(ctx, v, PDF_NAME_O)); pdf_obj *eo = pdf_dict_get(ctx, v, PDF_NAME_E); int editable = eo ? pdf_to_bool(ctx, eo) : 0; pdf_obj *vo = pdf_dict_get(ctx, v, PDF_NAME_V); int visible = vo ? pdf_to_bool(ctx, vo) : 1; char *subtype = pdf_to_name(ctx, pdf_dict_get(ctx, v, PDF_NAME_Subtype)); pdf_obj *name = pdf_dict_get(ctx, v, PDF_NAME_N); pdf_portfolio *p = fz_malloc_struct(ctx, pdf_portfolio); p->key = pdf_keep_obj(ctx, k); p->val = pdf_keep_obj(ctx, v); p->sort = sort; p->entry.visible = visible; p->entry.editable = editable; p->entry.name = pdf_keep_obj(ctx, name); if (!strcmp(subtype, "S")) p->entry.type = PDF_SCHEMA_TEXT; else if (!strcmp(subtype, "D")) p->entry.type = PDF_SCHEMA_DATE; else if (!strcmp(subtype, "N")) p->entry.type = PDF_SCHEMA_NUMBER; else if (!strcmp(subtype, "F")) p->entry.type = PDF_SCHEMA_FILENAME; else if (!strcmp(subtype, "Desc")) p->entry.type = PDF_SCHEMA_DESC; else if (!strcmp(subtype, "ModDate")) p->entry.type = PDF_SCHEMA_MODDATE; else if (!strcmp(subtype, "CreationDate")) p->entry.type = PDF_SCHEMA_CREATIONDATE; else if (!strcmp(subtype, "Size")) p->entry.type = PDF_SCHEMA_SIZE; else p->entry.type = PDF_SCHEMA_UNKNOWN; /* Now insert p */ pp = &doc->portfolio; while (*pp && (*pp)->sort <= p->sort) pp = &(*pp)->next; p->next = *pp; *pp = p; } }
pdf_pattern * pdf_load_pattern(pdf_document *xref, pdf_obj *dict) { pdf_pattern *pat; pdf_obj *obj; fz_context *ctx = xref->ctx; if ((pat = pdf_find_item(ctx, pdf_free_pattern_imp, dict))) { return pat; } pat = fz_malloc_struct(ctx, pdf_pattern); FZ_INIT_STORABLE(pat, 1, pdf_free_pattern_imp); pat->resources = NULL; pat->contents = NULL; /* Store pattern now, to avoid possible recursion if objects refer back to this one */ pdf_store_item(ctx, dict, pat, pdf_pattern_size(pat)); pat->ismask = pdf_to_int(pdf_dict_gets(dict, "PaintType")) == 2; pat->xstep = pdf_to_real(pdf_dict_gets(dict, "XStep")); pat->ystep = pdf_to_real(pdf_dict_gets(dict, "YStep")); obj = pdf_dict_gets(dict, "BBox"); pdf_to_rect(ctx, obj, &pat->bbox); obj = pdf_dict_gets(dict, "Matrix"); if (obj) pdf_to_matrix(ctx, obj, &pat->matrix); else pat->matrix = fz_identity; pat->resources = pdf_dict_gets(dict, "Resources"); if (pat->resources) pdf_keep_obj(pat->resources); fz_try(ctx) { pat->contents = pdf_keep_obj(dict); } fz_catch(ctx) { pdf_remove_item(ctx, pdf_free_pattern_imp, dict); pdf_drop_pattern(ctx, pat); fz_throw(ctx, "cannot load pattern stream (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } return pat; }
pdf_pattern * pdf_load_pattern(fz_context *ctx, pdf_document *doc, pdf_obj *dict) { pdf_pattern *pat; pdf_obj *obj; if ((pat = pdf_find_item(ctx, pdf_drop_pattern_imp, dict)) != NULL) { return pat; } pat = fz_malloc_struct(ctx, pdf_pattern); FZ_INIT_STORABLE(pat, 1, pdf_drop_pattern_imp); pat->document = doc; pat->resources = NULL; pat->contents = NULL; fz_try(ctx) { /* Store pattern now, to avoid possible recursion if objects refer back to this one */ pdf_store_item(ctx, dict, pat, pdf_pattern_size(pat)); pat->ismask = pdf_to_int(ctx, pdf_dict_get(ctx, dict, PDF_NAME_PaintType)) == 2; pat->xstep = pdf_to_real(ctx, pdf_dict_get(ctx, dict, PDF_NAME_XStep)); pat->ystep = pdf_to_real(ctx, pdf_dict_get(ctx, dict, PDF_NAME_YStep)); obj = pdf_dict_gets(ctx, dict, "BBox"); pdf_to_rect(ctx, obj, &pat->bbox); obj = pdf_dict_gets(ctx, dict, "Matrix"); if (obj) pdf_to_matrix(ctx, obj, &pat->matrix); else pat->matrix = fz_identity; pat->resources = pdf_dict_get(ctx, dict, PDF_NAME_Resources); if (pat->resources) pdf_keep_obj(ctx, pat->resources); pat->contents = pdf_keep_obj(ctx, dict); } fz_catch(ctx) { pdf_remove_item(ctx, pdf_drop_pattern_imp, dict); pdf_drop_pattern(ctx, pat); fz_rethrow_message(ctx, "cannot load pattern (%d %d R)", pdf_to_num(ctx, dict), pdf_to_gen(ctx, dict)); } return pat; }
void pdf_set_populating_xref_trailer(pdf_document *doc, pdf_obj *trailer) { /* Update the trailer of the xref section being populated */ pdf_xref *xref = &doc->xref_sections[doc->num_xref_sections - 1]; pdf_drop_obj(xref->trailer); xref->trailer = pdf_keep_obj(trailer); }
/* SumatraPDF: allow to synthesize XObjects (cf. pdf_create_annot) */ pdf_xobject * pdf_create_xobject(fz_context *ctx, pdf_obj *dict) { pdf_xobject *form = fz_malloc_struct(ctx, pdf_xobject); FZ_INIT_STORABLE(form, 1, pdf_free_xobject_imp); form->matrix = fz_identity; form->me = pdf_keep_obj(dict); return form; }
static void add_root(fz_context *ctx, pdf_obj *obj, pdf_obj ***roots, int *num_roots, int *max_roots) { if (*num_roots == *max_roots) { int new_max_roots = *max_roots * 2; if (new_max_roots == 0) new_max_roots = 4; *roots = fz_resize_array(ctx, *roots, new_max_roots, sizeof(**roots)); *max_roots = new_max_roots; } (*roots)[(*num_roots)++] = pdf_keep_obj(ctx, obj); }
void pdf_array_push(fz_context *ctx, pdf_obj *obj, pdf_obj *item) { RESOLVE(obj); if (!OBJ_IS_ARRAY(obj)) fz_throw(ctx, FZ_ERROR_GENERIC, "not an array (%s)", pdf_objkindstr(obj)); prepare_object_for_alteration(ctx, obj, item); if (ARRAY(obj)->len + 1 > ARRAY(obj)->cap) pdf_array_grow(ctx, ARRAY(obj)); ARRAY(obj)->items[ARRAY(obj)->len] = pdf_keep_obj(ctx, item); ARRAY(obj)->len++; }
void pdf_array_insert(fz_context *ctx, pdf_obj *obj, pdf_obj *item, int i) { RESOLVE(obj); if (!OBJ_IS_ARRAY(obj)) fz_throw(ctx, FZ_ERROR_GENERIC, "not an array (%s)", pdf_objkindstr(obj)); if (i < 0 || i > ARRAY(obj)->len) fz_throw(ctx, FZ_ERROR_GENERIC, "index out of bounds"); prepare_object_for_alteration(ctx, obj, item); if (ARRAY(obj)->len + 1 > ARRAY(obj)->cap) pdf_array_grow(ctx, ARRAY(obj)); memmove(ARRAY(obj)->items + i + 1, ARRAY(obj)->items + i, (ARRAY(obj)->len - i) * sizeof(pdf_obj*)); ARRAY(obj)->items[i] = pdf_keep_obj(ctx, item); ARRAY(obj)->len++; }
void pdf_array_push(pdf_obj *obj, pdf_obj *item) { RESOLVE(obj); if (!obj) return; /* Can't warn :( */ if (obj->kind != PDF_ARRAY) fz_warn(obj->ctx, "assert: not an array (%s)", pdf_objkindstr(obj)); else { if (obj->u.a.len + 1 > obj->u.a.cap) pdf_array_grow(obj); obj->u.a.items[obj->u.a.len] = pdf_keep_obj(item); obj->u.a.len++; } }
void pdf_array_put(fz_context *ctx, pdf_obj *obj, int i, pdf_obj *item) { RESOLVE(obj); if (!OBJ_IS_ARRAY(obj)) fz_throw(ctx, FZ_ERROR_GENERIC, "not an array (%s)", pdf_objkindstr(obj)); if (i == ARRAY(obj)->len) { pdf_array_push(ctx, obj, item); return; } if (i < 0 || i > ARRAY(obj)->len) fz_throw(ctx, FZ_ERROR_GENERIC, "index out of bounds"); prepare_object_for_alteration(ctx, obj, item); pdf_drop_obj(ctx, ARRAY(obj)->items[i]); ARRAY(obj)->items[i] = pdf_keep_obj(ctx, item); }
static pdf_obj * res_image_search(fz_context *ctx, pdf_document *doc, pdf_res_table *table, void *item, unsigned char *digest) { fz_image *image = item; fz_hash_table *hash = table->hash; pdf_obj *res; if (hash == NULL) res_image_init(ctx, doc, doc->resources->image); hash = doc->resources->image->hash; /* Create md5 and see if we have the item in our table */ res_image_get_md5(ctx, image, digest); res = fz_hash_find(ctx, hash, digest); if (res) pdf_keep_obj(ctx, res); return res; }
static pdf_obj * res_font_search(fz_context *ctx, pdf_document *doc, pdf_res_table *table, void *item, unsigned char digest[16]) { fz_buffer *buffer = item; fz_hash_table *hash = table->hash; pdf_obj *res; if (hash == NULL) res_font_init(ctx, doc, doc->resources->font); hash = doc->resources->font->hash; /* Create md5 and see if we have the item in our table */ res_font_get_md5(ctx, buffer, digest); res = fz_hash_find(ctx, hash, digest); if (res) pdf_keep_obj(ctx, res); return res; }
void pdf_array_put(pdf_obj *obj, int i, pdf_obj *item) { RESOLVE(obj); if (!obj) return; /* Can't warn :( */ if (obj->kind != PDF_ARRAY) fz_warn(obj->ctx, "assert: not an array (%s)", pdf_objkindstr(obj)); else if (i < 0) fz_warn(obj->ctx, "assert: index %d < 0", i); else if (i >= obj->u.a.len) fz_warn(obj->ctx, "assert: index %d > length %d", i, obj->u.a.len); else { pdf_drop_obj(obj->u.a.items[i]); obj->u.a.items[i] = pdf_keep_obj(item); } }
pdf_obj * pdf_insert_resource(fz_context *ctx, pdf_res_table *table, void *key, pdf_obj *obj) { pdf_obj *res; fz_try(ctx) { res = fz_hash_insert(ctx, table->hash, key, obj); if (res != NULL) fz_warn(ctx, "warning: resource already present"); else res = pdf_keep_obj(ctx, obj); } fz_catch(ctx) { fz_rethrow(ctx); } return res; }
void pdf_array_push(fz_context *ctx, pdf_obj *obj, pdf_obj *item) { RESOLVE(obj); if (obj >= PDF_OBJ__LIMIT) { prepare_object_for_alteration(ctx, obj, item); if (obj->kind != PDF_ARRAY) fz_warn(ctx, "assert: not an array (%s)", pdf_objkindstr(obj)); else { if (ARRAY(obj)->len + 1 > ARRAY(obj)->cap) pdf_array_grow(ctx, ARRAY(obj)); ARRAY(obj)->items[ARRAY(obj)->len] = pdf_keep_obj(ctx, item); ARRAY(obj)->len++; } } return; /* Can't warn :( */ }
void pdf_array_push(fz_context *ctx, pdf_obj *obj, pdf_obj *item) { RESOLVE(obj); if (obj) { if (obj->kind != PDF_ARRAY) fz_warn(ctx, "assert: not an array (%s)", pdf_objkindstr(obj)); else { if (obj->u.a.len + 1 > obj->u.a.cap) pdf_array_grow(ctx, obj); obj->u.a.items[obj->u.a.len] = pdf_keep_obj(ctx, item); obj->u.a.len++; } object_altered(ctx, obj, item); } return; /* Can't warn :( */ }
void pdf_array_put(fz_context *ctx, pdf_obj *obj, int i, pdf_obj *item) { RESOLVE(obj); if (obj) { if (obj->kind != PDF_ARRAY) fz_warn(ctx, "assert: not an array (%s)", pdf_objkindstr(obj)); else if (i < 0) fz_warn(ctx, "assert: index %d < 0", i); else if (i >= obj->u.a.len) fz_warn(ctx, "assert: index %d > length %d", i, obj->u.a.len); else { pdf_drop_obj(ctx, obj->u.a.items[i]); obj->u.a.items[i] = pdf_keep_obj(ctx, item); } object_altered(ctx, obj, item); } return; /* Can't warn :( */ }
void pdf_array_put(fz_context *ctx, pdf_obj *obj, int i, pdf_obj *item) { RESOLVE(obj); if (obj >= PDF_OBJ__LIMIT) { prepare_object_for_alteration(ctx, obj, item); if (obj->kind != PDF_ARRAY) fz_warn(ctx, "assert: not an array (%s)", pdf_objkindstr(obj)); else if (i < 0) fz_warn(ctx, "assert: index %d < 0", i); else if (i >= ARRAY(obj)->len) fz_warn(ctx, "assert: index %d > length %d", i, ARRAY(obj)->len); else { pdf_drop_obj(ctx, ARRAY(obj)->items[i]); ARRAY(obj)->items[i] = pdf_keep_obj(ctx, item); } } return; /* Can't warn :( */ }
void pdf_array_insert(fz_context *ctx, pdf_obj *obj, pdf_obj *item, int i) { RESOLVE(obj); if (obj >= PDF_OBJ__LIMIT) { prepare_object_for_alteration(ctx, obj, item); if (obj->kind != PDF_ARRAY) fz_warn(ctx, "assert: not an array (%s)", pdf_objkindstr(obj)); else { if (i < 0 || i > ARRAY(obj)->len) fz_throw(ctx, FZ_ERROR_GENERIC, "attempt to insert object %d in array of length %d", i, ARRAY(obj)->len); if (ARRAY(obj)->len + 1 > ARRAY(obj)->cap) pdf_array_grow(ctx, ARRAY(obj)); memmove(ARRAY(obj)->items + i + 1, ARRAY(obj)->items + i, (ARRAY(obj)->len - i) * sizeof(pdf_obj*)); ARRAY(obj)->items[i] = pdf_keep_obj(ctx, item); ARRAY(obj)->len++; } } return; /* Can't warn :( */ }
void pdf_array_insert(fz_context *ctx, pdf_obj *obj, pdf_obj *item, int i) { RESOLVE(obj); if (obj) { if (obj->kind != PDF_ARRAY) fz_warn(ctx, "assert: not an array (%s)", pdf_objkindstr(obj)); else { if (i < 0 || i > obj->u.a.len) fz_throw(ctx, FZ_ERROR_GENERIC, "attempt to insert object %d in array of length %d", i, obj->u.a.len); if (obj->u.a.len + 1 > obj->u.a.cap) pdf_array_grow(ctx, obj); memmove(obj->u.a.items + i + 1, obj->u.a.items + i, (obj->u.a.len - i) * sizeof(pdf_obj*)); obj->u.a.items[i] = pdf_keep_obj(ctx, item); obj->u.a.len++; } object_altered(ctx, obj, item); } return; /* Can't warn :( */ }
pdf_annot * pdf_create_annot(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_annot_type type) { pdf_annot *annot = NULL; pdf_obj *annot_obj = pdf_new_dict(ctx, doc, 0); pdf_obj *ind_obj = NULL; fz_var(annot); fz_var(ind_obj); fz_try(ctx) { int ind_obj_num; fz_rect rect = {0.0, 0.0, 0.0, 0.0}; const char *type_str = annot_type_str(type); pdf_obj *annot_arr = pdf_dict_get(ctx, page->me, PDF_NAME_Annots); if (annot_arr == NULL) { annot_arr = pdf_new_array(ctx, doc, 0); pdf_dict_put_drop(ctx, page->me, PDF_NAME_Annots, annot_arr); } pdf_dict_put_drop(ctx, annot_obj, PDF_NAME_Type, PDF_NAME_Annot); pdf_dict_put_drop(ctx, annot_obj, PDF_NAME_Subtype, pdf_new_name(ctx, doc, type_str)); pdf_dict_put_drop(ctx, annot_obj, PDF_NAME_Rect, pdf_new_rect(ctx, doc, &rect)); /* Make printable as default */ pdf_dict_put_drop(ctx, annot_obj, PDF_NAME_F, pdf_new_int(ctx, doc, F_Print)); annot = fz_malloc_struct(ctx, pdf_annot); annot->page = page; annot->rect = rect; annot->pagerect = rect; annot->ap = NULL; annot->widget_type = PDF_WIDGET_TYPE_NOT_WIDGET; annot->annot_type = type; /* Both annotation object and annotation structure are now created. Insert the object in the hierarchy and the structure in the page's array. */ ind_obj_num = pdf_create_object(ctx, doc); pdf_update_object(ctx, doc, ind_obj_num, annot_obj); ind_obj = pdf_new_indirect(ctx, doc, ind_obj_num, 0); pdf_array_push(ctx, annot_arr, ind_obj); annot->obj = pdf_keep_obj(ctx, ind_obj); /* Linking must be done after any call that might throw because pdf_drop_annot below actually frees a list. Put the new annot at the end of the list, so that it will be drawn last. */ *page->annot_tailp = annot; page->annot_tailp = &annot->next; doc->dirty = 1; } fz_always(ctx) { pdf_drop_obj(ctx, annot_obj); pdf_drop_obj(ctx, ind_obj); } fz_catch(ctx) { pdf_drop_annot(ctx, annot); fz_rethrow(ctx); } return annot; }
pdf_page * pdf_load_page_by_obj(pdf_document *doc, int number, pdf_obj *pageref) { fz_context *ctx = doc->ctx; pdf_page *page; pdf_annot *annot; pdf_obj *pageobj, *obj; fz_rect mediabox, cropbox, realbox; float userunit; fz_matrix mat; /* SumatraPDF: allow replacing potentially slow pdf_lookup_page_obj */ pageobj = pdf_resolve_indirect(pageref); page = fz_malloc_struct(ctx, pdf_page); page->resources = NULL; page->contents = NULL; page->transparency = 0; page->links = NULL; page->annots = NULL; page->annot_tailp = &page->annots; page->deleted_annots = NULL; page->tmp_annots = NULL; page->me = pdf_keep_obj(pageobj); page->incomplete = 0; obj = pdf_dict_gets(pageobj, "UserUnit"); if (pdf_is_real(obj)) userunit = pdf_to_real(obj); else userunit = 1; pdf_to_rect(ctx, pdf_lookup_inherited_page_item(doc, pageobj, "MediaBox"), &mediabox); if (fz_is_empty_rect(&mediabox)) { fz_warn(ctx, "cannot find page size for page %d", number + 1); mediabox.x0 = 0; mediabox.y0 = 0; mediabox.x1 = 612; mediabox.y1 = 792; } pdf_to_rect(ctx, pdf_lookup_inherited_page_item(doc, pageobj, "CropBox"), &cropbox); if (!fz_is_empty_rect(&cropbox)) fz_intersect_rect(&mediabox, &cropbox); page->mediabox.x0 = fz_min(mediabox.x0, mediabox.x1) * userunit; page->mediabox.y0 = fz_min(mediabox.y0, mediabox.y1) * userunit; page->mediabox.x1 = fz_max(mediabox.x0, mediabox.x1) * userunit; page->mediabox.y1 = fz_max(mediabox.y0, mediabox.y1) * userunit; if (page->mediabox.x1 - page->mediabox.x0 < 1 || page->mediabox.y1 - page->mediabox.y0 < 1) { fz_warn(ctx, "invalid page size in page %d", number + 1); page->mediabox = fz_unit_rect; } page->rotate = pdf_to_int(pdf_lookup_inherited_page_item(doc, pageobj, "Rotate")); /* Snap page->rotate to 0, 90, 180 or 270 */ if (page->rotate < 0) page->rotate = 360 - ((-page->rotate) % 360); if (page->rotate >= 360) page->rotate = page->rotate % 360; page->rotate = 90*((page->rotate + 45)/90); if (page->rotate > 360) page->rotate = 0; fz_pre_rotate(fz_scale(&page->ctm, 1, -1), -page->rotate); realbox = page->mediabox; fz_transform_rect(&realbox, &page->ctm); fz_pre_scale(fz_translate(&mat, -realbox.x0, -realbox.y0), userunit, userunit); fz_concat(&page->ctm, &page->ctm, &mat); fz_try(ctx) { obj = pdf_dict_gets(pageobj, "Annots"); if (obj) { page->links = pdf_load_link_annots(doc, obj, &page->ctm); pdf_load_annots(doc, page, obj); } } fz_catch(ctx) { if (fz_caught(ctx) != FZ_ERROR_TRYLATER) /* SumatraPDF: ignore annotations in case of unexpected errors */ fz_warn(ctx, "unexpectedly failed to load page annotations"); page->incomplete |= PDF_PAGE_INCOMPLETE_ANNOTS; } page->duration = pdf_to_real(pdf_dict_gets(pageobj, "Dur")); obj = pdf_dict_gets(pageobj, "Trans"); page->transition_present = (obj != NULL); if (obj) { pdf_load_transition(doc, page, obj); } // TODO: inherit page->resources = pdf_lookup_inherited_page_item(doc, pageobj, "Resources"); if (page->resources) pdf_keep_obj(page->resources); obj = pdf_dict_gets(pageobj, "Contents"); fz_try(ctx) { page->contents = pdf_keep_obj(obj); if (pdf_resources_use_blending(doc, page->resources)) page->transparency = 1; /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=2107 */ else if (!strcmp(pdf_to_name(pdf_dict_getp(pageobj, "Group/S")), "Transparency")) page->transparency = 1; for (annot = page->annots; annot && !page->transparency; annot = annot->next) if (annot->ap && pdf_resources_use_blending(doc, annot->ap->resources)) page->transparency = 1; } fz_catch(ctx) { if (fz_caught(ctx) != FZ_ERROR_TRYLATER) { pdf_free_page(doc, page); fz_rethrow_message(ctx, "cannot load page %d contents (%d 0 R)", number + 1, pdf_to_num(pageref)); } page->incomplete |= PDF_PAGE_INCOMPLETE_CONTENTS; } return page; }
pdf_font_desc * pdf_load_type3_font(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict) { char buf[256]; char *estrings[256]; pdf_font_desc *fontdesc = NULL; pdf_obj *encoding; pdf_obj *widths; pdf_obj *charprocs; pdf_obj *obj; int first, last; int i, k, n; fz_rect bbox; fz_matrix matrix; fz_font *font; fz_var(fontdesc); /* Make a new type3 font entry in the document */ if (doc->num_type3_fonts == doc->max_type3_fonts) { int new_max = doc->max_type3_fonts * 2; if (new_max == 0) new_max = 4; doc->type3_fonts = fz_resize_array(ctx, doc->type3_fonts, new_max, sizeof(*doc->type3_fonts)); doc->max_type3_fonts = new_max; } fz_try(ctx) { obj = pdf_dict_get(ctx, dict, PDF_NAME_Name); if (pdf_is_name(ctx, obj)) fz_strlcpy(buf, pdf_to_name(ctx, obj), sizeof buf); else fz_strlcpy(buf, "Unnamed-T3", sizeof buf); fontdesc = pdf_new_font_desc(ctx); obj = pdf_dict_get(ctx, dict, PDF_NAME_FontMatrix); pdf_to_matrix(ctx, obj, &matrix); obj = pdf_dict_get(ctx, dict, PDF_NAME_FontBBox); fz_transform_rect(pdf_to_rect(ctx, obj, &bbox), &matrix); font = fz_new_type3_font(ctx, buf, &matrix); fontdesc->font = font; fontdesc->size += sizeof(fz_font) + 256 * (sizeof(fz_buffer*) + sizeof(float)); fz_set_font_bbox(ctx, font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* Encoding */ for (i = 0; i < 256; i++) estrings[i] = NULL; encoding = pdf_dict_get(ctx, dict, PDF_NAME_Encoding); if (!encoding) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing Encoding"); } if (pdf_is_name(ctx, encoding)) pdf_load_encoding(estrings, pdf_to_name(ctx, encoding)); if (pdf_is_dict(ctx, encoding)) { pdf_obj *base, *diff, *item; base = pdf_dict_get(ctx, encoding, PDF_NAME_BaseEncoding); if (pdf_is_name(ctx, base)) pdf_load_encoding(estrings, pdf_to_name(ctx, base)); diff = pdf_dict_get(ctx, encoding, PDF_NAME_Differences); if (pdf_is_array(ctx, diff)) { n = pdf_array_len(ctx, diff); k = 0; for (i = 0; i < n; i++) { item = pdf_array_get(ctx, diff, i); if (pdf_is_int(ctx, item)) k = pdf_to_int(ctx, item); if (pdf_is_name(ctx, item) && k >= 0 && k < nelem(estrings)) estrings[k++] = pdf_to_name(ctx, item); } } } fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); pdf_load_to_unicode(ctx, doc, fontdesc, estrings, NULL, pdf_dict_get(ctx, dict, PDF_NAME_ToUnicode)); /* Widths */ pdf_set_default_hmtx(ctx, fontdesc, 0); first = pdf_to_int(ctx, pdf_dict_get(ctx, dict, PDF_NAME_FirstChar)); last = pdf_to_int(ctx, pdf_dict_get(ctx, dict, PDF_NAME_LastChar)); if (first < 0 || last > 255 || first > last) first = last = 0; widths = pdf_dict_get(ctx, dict, PDF_NAME_Widths); if (!widths) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing Widths"); } for (i = first; i <= last; i++) { float w = pdf_to_real(ctx, pdf_array_get(ctx, widths, i - first)); w = font->t3matrix.a * w * 1000; font->t3widths[i] = w * 0.001f; pdf_add_hmtx(ctx, fontdesc, i, i, w); } pdf_end_hmtx(ctx, fontdesc); /* Resources -- inherit page resources if the font doesn't have its own */ font->t3freeres = pdf_t3_free_resources; font->t3resources = pdf_dict_get(ctx, dict, PDF_NAME_Resources); if (!font->t3resources) font->t3resources = rdb; if (font->t3resources) pdf_keep_obj(ctx, font->t3resources); if (!font->t3resources) fz_warn(ctx, "no resource dictionary for type 3 font!"); font->t3doc = doc; font->t3run = pdf_run_glyph_func; /* CharProcs */ charprocs = pdf_dict_get(ctx, dict, PDF_NAME_CharProcs); if (!charprocs) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing CharProcs"); } for (i = 0; i < 256; i++) { if (estrings[i]) { obj = pdf_dict_gets(ctx, charprocs, estrings[i]); if (pdf_is_stream(ctx, obj)) { font->t3procs[i] = pdf_load_stream(ctx, obj); fz_trim_buffer(ctx, font->t3procs[i]); fontdesc->size += fz_buffer_storage(ctx, font->t3procs[i], NULL); fontdesc->size += 0; // TODO: display list size calculation } } } } fz_catch(ctx) { pdf_drop_font(ctx, fontdesc); fz_rethrow(ctx); } doc->type3_fonts[doc->num_type3_fonts++] = fz_keep_font(ctx, font); return fontdesc; }
pdf_annot * pdf_load_annots(pdf_document *xref, pdf_obj *annots, fz_matrix page_ctm) { pdf_annot *annot, *head, *tail; pdf_obj *obj, *ap, *as, *n, *d, *c, *rect; int i, len; int mouse_states; int has_states = 0; fz_context *ctx = xref->ctx; head = tail = NULL; annot = NULL; len = pdf_array_len(annots); for (i = 0; i < len; i++) { obj = pdf_array_get(annots, i); pdf_update_appearance(xref, obj); rect = pdf_dict_gets(obj, "Rect"); ap = pdf_dict_gets(obj, "AP"); as = pdf_dict_gets(obj, "AS"); if (pdf_is_dict(ap)) { pdf_hotspot *hp = &xref->hotspot; n = pdf_dict_gets(ap, "N"); /* normal state */ d = pdf_dict_gets(ap, "D"); /* down state */ if (n && d) { if (hp->num == pdf_to_num(obj) && hp->gen == pdf_to_gen(obj) && (hp->state & HOTSPOT_POINTER_DOWN)) { /* Use the down appearance, but as we also have * a normal appearance, it is suitable only for mouse * down */ c = d; mouse_states = MOUSE_DOWN_APPEARANCE; } else { /* Use the normal appearance, but as we also have * a down appearance, it is suitable only for mouse * up */ c = n; mouse_states = MOUSE_UP_APPEARANCE; } } else { /* Use whichever appearance we have for both states */ c = n?n:d; mouse_states = MOUSE_UP_APPEARANCE|MOUSE_DOWN_APPEARANCE; } /* lookup current state in sub-dictionary */ if (!pdf_is_stream(xref, pdf_to_num(c), pdf_to_gen(c))) { has_states = 1; c = pdf_dict_get(c, as); } annot = fz_malloc_struct(ctx, pdf_annot); annot->obj = pdf_keep_obj(obj); annot->rect = pdf_to_rect(ctx, rect); annot->pagerect = fz_transform_rect(page_ctm, annot->rect); annot->ap = NULL; annot->type = pdf_field_type(xref, obj); annot->mouse_states = mouse_states; annot->has_states = has_states; if (pdf_is_stream(xref, pdf_to_num(c), pdf_to_gen(c))) { fz_try(ctx) { annot->ap = pdf_load_xobject(xref, c); pdf_transform_annot(annot); } fz_catch(ctx) { fz_warn(ctx, "ignoring broken annotation"); } } annot->next = NULL; if (obj == xref->focus_obj) xref->focus = annot; if (!head) head = tail = annot; else { tail->next = annot; tail = annot; } } } return head; }
pdf_annot * pdf_create_annot(fz_context *ctx, pdf_page *page, fz_annot_type type) { pdf_annot *annot = NULL; pdf_document *doc = page->doc; pdf_obj *annot_obj = pdf_new_dict(ctx, doc, 0); pdf_obj *ind_obj = NULL; fz_var(annot); fz_var(ind_obj); fz_try(ctx) { int ind_obj_num; fz_rect rect = {0.0f, 0.0f, 0.0f, 0.0f}; const char *type_str; pdf_obj *annot_arr; type_str = pdf_string_from_annot_type(ctx, type); if (type == PDF_ANNOT_UNKNOWN) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot create unknown annotation"); annot_arr = pdf_dict_get(ctx, page->obj, PDF_NAME_Annots); if (annot_arr == NULL) { annot_arr = pdf_new_array(ctx, doc, 0); pdf_dict_put_drop(ctx, page->obj, PDF_NAME_Annots, annot_arr); } pdf_dict_put_drop(ctx, annot_obj, PDF_NAME_Type, PDF_NAME_Annot); pdf_dict_put_drop(ctx, annot_obj, PDF_NAME_Subtype, pdf_new_name(ctx, doc, type_str)); pdf_dict_put_drop(ctx, annot_obj, PDF_NAME_Rect, pdf_new_rect(ctx, doc, &rect)); /* Make printable as default */ pdf_dict_put_drop(ctx, annot_obj, PDF_NAME_F, pdf_new_int(ctx, doc, PDF_ANNOT_IS_PRINT)); annot = pdf_new_annot(ctx, page); annot->ap = NULL; /* Both annotation object and annotation structure are now created. Insert the object in the hierarchy and the structure in the page's array. */ ind_obj_num = pdf_create_object(ctx, doc); pdf_update_object(ctx, doc, ind_obj_num, annot_obj); ind_obj = pdf_new_indirect(ctx, doc, ind_obj_num, 0); pdf_array_push(ctx, annot_arr, ind_obj); annot->obj = pdf_keep_obj(ctx, ind_obj); /* Linking must be done after any call that might throw because pdf_drop_annots below actually frees a list. Put the new annot at the end of the list, so that it will be drawn last. */ *page->annot_tailp = annot; page->annot_tailp = &annot->next; doc->dirty = 1; } fz_always(ctx) { pdf_drop_obj(ctx, annot_obj); pdf_drop_obj(ctx, ind_obj); } fz_catch(ctx) { pdf_drop_annots(ctx, annot); fz_rethrow(ctx); } return annot; }
int pdf_repair_obj(fz_context *ctx, pdf_document *doc, pdf_lexbuf *buf, fz_off_t *stmofsp, int *stmlenp, pdf_obj **encrypt, pdf_obj **id, pdf_obj **page, fz_off_t *tmpofs, pdf_obj **root) { fz_stream *file = doc->file; pdf_token tok; int stm_len; *stmofsp = 0; if (stmlenp) *stmlenp = -1; stm_len = 0; /* On entry to this function, we know that we've just seen * '<int> <int> obj'. We expect the next thing we see to be a * pdf object. Regardless of the type of thing we meet next * we only need to fully parse it if it is a dictionary. */ tok = pdf_lex(ctx, file, buf); if (tok == PDF_TOK_OPEN_DICT) { pdf_obj *dict, *obj; fz_try(ctx) { dict = pdf_parse_dict(ctx, doc, file, buf); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); /* Don't let a broken object at EOF overwrite a good one */ if (file->eof) fz_rethrow(ctx); /* Silently swallow the error */ dict = pdf_new_dict(ctx, NULL, 2); } /* We must be careful not to try to resolve any indirections * here. We have just read dict, so we know it to be a non * indirected dictionary. Before we look at any values that * we get back from looking up in it, we need to check they * aren't indirected. */ if (encrypt || id || root) { obj = pdf_dict_get(ctx, dict, PDF_NAME_Type); if (!pdf_is_indirect(ctx, obj) && pdf_name_eq(ctx, obj, PDF_NAME_XRef)) { if (encrypt) { obj = pdf_dict_get(ctx, dict, PDF_NAME_Encrypt); if (obj) { pdf_drop_obj(ctx, *encrypt); *encrypt = pdf_keep_obj(ctx, obj); } } if (id) { obj = pdf_dict_get(ctx, dict, PDF_NAME_ID); if (obj) { pdf_drop_obj(ctx, *id); *id = pdf_keep_obj(ctx, obj); } } if (root) *root = pdf_keep_obj(ctx, pdf_dict_get(ctx, dict, PDF_NAME_Root)); } } obj = pdf_dict_get(ctx, dict, PDF_NAME_Length); if (!pdf_is_indirect(ctx, obj) && pdf_is_int(ctx, obj)) stm_len = pdf_to_int(ctx, obj); if (doc->file_reading_linearly && page) { obj = pdf_dict_get(ctx, dict, PDF_NAME_Type); if (!pdf_is_indirect(ctx, obj) && pdf_name_eq(ctx, obj, PDF_NAME_Page)) { pdf_drop_obj(ctx, *page); *page = pdf_keep_obj(ctx, dict); } } pdf_drop_obj(ctx, dict); }
static void reset_field(pdf_document *doc, pdf_obj *field) { fz_context *ctx = doc->ctx; /* Set V to DV whereever DV is present, and delete V where DV is not. * FIXME: we assume for now that V has not been set unequal * to DV higher in the hierarchy than "field". * * At the bottom of the hierarchy we may find widget annotations * that aren't also fields, but DV and V will not be present in their * dictionaries, and attempts to remove V will be harmless. */ pdf_obj *dv = pdf_dict_gets(field, "DV"); pdf_obj *kids = pdf_dict_gets(field, "Kids"); if (dv) pdf_dict_puts(field, "V", dv); else pdf_dict_dels(field, "V"); if (kids == NULL) { /* The leaves of the tree are widget annotations * In some cases we need to update the appearance state; * in others we need to mark the field as dirty so that * the appearance stream will be regenerated. */ switch (pdf_field_type(doc, field)) { case PDF_WIDGET_TYPE_RADIOBUTTON: case PDF_WIDGET_TYPE_CHECKBOX: { pdf_obj *leafv = pdf_get_inheritable(doc, field, "V"); if (leafv) pdf_keep_obj(leafv); else leafv = pdf_new_name(doc, "Off"); fz_try(ctx) { pdf_dict_puts(field, "AS", leafv); } fz_always(ctx) { pdf_drop_obj(leafv); } fz_catch(ctx) { fz_rethrow(ctx); } } break; case PDF_WIDGET_TYPE_PUSHBUTTON: break; default: pdf_field_mark_dirty(doc, field); break; } } doc->dirty = 1; }
pdf_font_desc * pdf_load_type3_font(pdf_document *doc, pdf_obj *rdb, pdf_obj *dict) { char buf[256]; char *estrings[256]; pdf_font_desc *fontdesc = NULL; pdf_obj *encoding; pdf_obj *widths; pdf_obj *charprocs; pdf_obj *obj; int first, last; int i, k, n; fz_rect bbox; fz_matrix matrix; fz_context *ctx = doc->ctx; fz_var(fontdesc); /* Make a new type3 font entry in the document */ if (doc->num_type3_fonts == doc->max_type3_fonts) { int new_max = doc->max_type3_fonts * 2; if (new_max == 0) new_max = 4; doc->type3_fonts = fz_resize_array(doc->ctx, doc->type3_fonts, new_max, sizeof(*doc->type3_fonts)); doc->max_type3_fonts = new_max; } fz_try(ctx) { obj = pdf_dict_gets(dict, "Name"); if (pdf_is_name(obj)) fz_strlcpy(buf, pdf_to_name(obj), sizeof buf); else sprintf(buf, "Unnamed-T3"); fontdesc = pdf_new_font_desc(ctx); obj = pdf_dict_gets(dict, "FontMatrix"); pdf_to_matrix(ctx, obj, &matrix); obj = pdf_dict_gets(dict, "FontBBox"); fz_transform_rect(pdf_to_rect(ctx, obj, &bbox), &matrix); fontdesc->font = fz_new_type3_font(ctx, buf, &matrix); fontdesc->size += sizeof(fz_font) + 256 * (sizeof(fz_buffer*) + sizeof(float)); fz_set_font_bbox(ctx, fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* SumatraPDF: expose Type3 FontDescriptor flags */ fontdesc->flags = pdf_to_int(pdf_dict_gets(pdf_dict_gets(dict, "FontDescriptor"), "Flags")); /* Encoding */ for (i = 0; i < 256; i++) estrings[i] = NULL; encoding = pdf_dict_gets(dict, "Encoding"); if (!encoding) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing Encoding"); } if (pdf_is_name(encoding)) pdf_load_encoding(estrings, pdf_to_name(encoding)); if (pdf_is_dict(encoding)) { pdf_obj *base, *diff, *item; base = pdf_dict_gets(encoding, "BaseEncoding"); if (pdf_is_name(base)) pdf_load_encoding(estrings, pdf_to_name(base)); diff = pdf_dict_gets(encoding, "Differences"); if (pdf_is_array(diff)) { n = pdf_array_len(diff); k = 0; for (i = 0; i < n; i++) { item = pdf_array_get(diff, i); if (pdf_is_int(item)) k = pdf_to_int(item); if (pdf_is_name(item) && k >= 0 && k < nelem(estrings)) estrings[k++] = pdf_to_name(item); } } } fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); pdf_load_to_unicode(doc, fontdesc, estrings, NULL, pdf_dict_gets(dict, "ToUnicode")); /* SumatraPDF: trying to match Adobe Reader's behavior */ if (!(fontdesc->flags & PDF_FD_SYMBOLIC) && fontdesc->cid_to_ucs_len >= 128) for (i = 32; i < 128; i++) if (fontdesc->cid_to_ucs[i] == '?' || fontdesc->cid_to_ucs[i] == '\0') fontdesc->cid_to_ucs[i] = i; /* Widths */ pdf_set_default_hmtx(ctx, fontdesc, 0); first = pdf_to_int(pdf_dict_gets(dict, "FirstChar")); last = pdf_to_int(pdf_dict_gets(dict, "LastChar")); /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1966 */ if (first >= 256 && last - first < 256) { fz_warn(ctx, "ignoring out-of-bound values for FirstChar/LastChar: %d/%d", first, last); last -= first; first = 0; } if (first < 0 || last > 255 || first > last) first = last = 0; widths = pdf_dict_gets(dict, "Widths"); if (!widths) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing Widths"); } for (i = first; i <= last; i++) { float w = pdf_to_real(pdf_array_get(widths, i - first)); w = fontdesc->font->t3matrix.a * w * 1000; fontdesc->font->t3widths[i] = w * 0.001f; pdf_add_hmtx(ctx, fontdesc, i, i, w); } pdf_end_hmtx(ctx, fontdesc); /* Resources -- inherit page resources if the font doesn't have its own */ fontdesc->font->t3freeres = pdf_t3_free_resources; fontdesc->font->t3resources = pdf_dict_gets(dict, "Resources"); if (!fontdesc->font->t3resources) fontdesc->font->t3resources = rdb; if (fontdesc->font->t3resources) pdf_keep_obj(fontdesc->font->t3resources); if (!fontdesc->font->t3resources) fz_warn(ctx, "no resource dictionary for type 3 font!"); fontdesc->font->t3doc = doc; fontdesc->font->t3run = pdf_run_glyph_func; /* CharProcs */ charprocs = pdf_dict_gets(dict, "CharProcs"); if (!charprocs) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing CharProcs"); } for (i = 0; i < 256; i++) { if (estrings[i]) { /* SumatraPDF: don't reject fonts with few broken glyphs */ fz_try(ctx) { obj = pdf_dict_gets(charprocs, estrings[i]); if (pdf_is_stream(doc, pdf_to_num(obj), pdf_to_gen(obj))) { fontdesc->font->t3procs[i] = pdf_load_stream(doc, pdf_to_num(obj), pdf_to_gen(obj)); fontdesc->size += fontdesc->font->t3procs[i]->cap; fontdesc->size += 0; // TODO: display list size calculation } } fz_catch(ctx) { fz_warn(ctx, "failed to get data for type 3 glyph '%s'", estrings[i]); } } } } fz_catch(ctx) { if (fontdesc) pdf_drop_font(ctx, fontdesc); fz_rethrow_message(ctx, "cannot load type3 font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } doc->type3_fonts[doc->num_type3_fonts++] = fz_keep_font(ctx, fontdesc->font); return fontdesc; }
/* Performs the same task as pdf_clean_page_contents, but with an optional text filter function. text_filter: Function to assess whether a given character should be kept (return 0) or removed (return 1). after_text: Function called after each text object is closed to allow other output to be sent. arg: Opaque value to be passed to callback functions. */ void pdf_filter_page_contents(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_cookie *cookie, pdf_page_contents_process_fn *proc_fn, pdf_text_filter_fn *text_filter, pdf_after_text_object_fn *after_text, void *proc_arg, int sanitize, int ascii) { pdf_processor *proc_buffer = NULL; pdf_processor *proc_filter = NULL; pdf_obj *new_obj = NULL; pdf_obj *new_ref = NULL; pdf_obj *res = NULL; pdf_obj *obj; pdf_obj *contents; pdf_obj *resources; fz_buffer *buffer; fz_var(new_obj); fz_var(new_ref); fz_var(res); fz_var(proc_buffer); fz_var(proc_filter); buffer = fz_new_buffer(ctx, 1024); fz_try(ctx) { contents = pdf_page_contents(ctx, page); resources = pdf_page_resources(ctx, page); proc_buffer = pdf_new_buffer_processor(ctx, buffer, ascii); if (sanitize) { res = pdf_new_dict(ctx, doc, 1); proc_filter = pdf_new_filter_processor_with_text_filter(ctx, doc, proc_buffer, resources, res, text_filter, after_text, proc_arg); pdf_process_contents(ctx, proc_filter, doc, resources, contents, cookie); pdf_close_processor(ctx, proc_filter); } else { res = pdf_keep_obj(ctx, resources); pdf_process_contents(ctx, proc_buffer, doc, resources, contents, cookie); } pdf_close_processor(ctx, proc_buffer); /* Deal with page content stream. */ if (pdf_is_array(ctx, contents)) { /* create a new object to replace the array */ new_obj = pdf_new_dict(ctx, doc, 1); new_ref = pdf_add_object(ctx, doc, new_obj); contents = new_ref; pdf_dict_put(ctx, page->obj, PDF_NAME(Contents), contents); } else { pdf_dict_del(ctx, contents, PDF_NAME(Filter)); pdf_dict_del(ctx, contents, PDF_NAME(DecodeParms)); } pdf_update_stream(ctx, doc, contents, buffer, 0); /* Now deal with resources. The spec allows for Type3 fonts and form * XObjects to omit a resource dictionary and look in the parent. * Avoid that by flattening here as part of the cleaning. This could * conceivably cause changes in rendering, but we don't care. */ /* ExtGState */ obj = pdf_dict_get(ctx, res, PDF_NAME(ExtGState)); if (obj) { int i, l; l = pdf_dict_len(ctx, obj); for (i = 0; i < l; i++) { pdf_obj *o = pdf_dict_get(ctx, pdf_dict_get_val(ctx, obj, i), PDF_NAME(SMask)); if (!o) continue; o = pdf_dict_get(ctx, o, PDF_NAME(G)); if (!o) continue; /* Transparency group XObject */ pdf_clean_stream_object(ctx, doc, o, resources, cookie, 1, text_filter, after_text, proc_arg, sanitize, ascii); } } /* Pattern */ obj = pdf_dict_get(ctx, res, PDF_NAME(Pattern)); if (obj) { int i, l; l = pdf_dict_len(ctx, obj); for (i = 0; i < l; i++) { pdf_obj *pat_res; pdf_obj *pat = pdf_dict_get_val(ctx, obj, i); if (!pat) continue; pat_res = pdf_dict_get(ctx, pat, PDF_NAME(Resources)); if (pat_res == NULL) pat_res = resources; if (pdf_dict_get_int(ctx, pat, PDF_NAME(PatternType)) == 1) pdf_clean_stream_object(ctx, doc, pat, pat_res, cookie, 0, text_filter, after_text, proc_arg, sanitize, ascii); } } /* XObject */ obj = pdf_dict_get(ctx, res, PDF_NAME(XObject)); if (obj) { int i, l; l = pdf_dict_len(ctx, obj); for (i = 0; i < l; i++) { pdf_obj *xobj_res; pdf_obj *xobj = pdf_dict_get_val(ctx, obj, i); if (!xobj) continue; xobj_res = pdf_dict_get(ctx, xobj, PDF_NAME(Resources)); if (xobj_res == NULL) xobj_res = resources; if (pdf_name_eq(ctx, PDF_NAME(Form), pdf_dict_get(ctx, xobj, PDF_NAME(Subtype)))) pdf_clean_stream_object(ctx, doc, xobj, xobj_res, cookie, 1, text_filter, after_text, proc_arg, sanitize, ascii); } } /* Font */ obj = pdf_dict_get(ctx, res, PDF_NAME(Font)); if (obj) { int i, l; l = pdf_dict_len(ctx, obj); for (i = 0; i < l; i++) { pdf_obj *o = pdf_dict_get_val(ctx, obj, i); if (!o) continue; if (pdf_name_eq(ctx, PDF_NAME(Type3), pdf_dict_get(ctx, o, PDF_NAME(Subtype)))) pdf_clean_type3(ctx, doc, o, resources, cookie, sanitize, ascii); } } /* ProcSet - no cleaning possible. Inherit this from the old dict. */ obj = pdf_dict_get(ctx, resources, PDF_NAME(ProcSet)); if (obj) pdf_dict_put(ctx, res, PDF_NAME(ProcSet), obj); /* ColorSpace - no cleaning possible. */ /* Properties - no cleaning possible. */ if (proc_fn) (*proc_fn)(ctx, buffer, res, proc_arg); /* Update resource dictionary */ if (sanitize) { pdf_dict_put(ctx, page->obj, PDF_NAME(Resources), res); } } fz_always(ctx) { pdf_drop_processor(ctx, proc_filter); pdf_drop_processor(ctx, proc_buffer); fz_drop_buffer(ctx, buffer); pdf_drop_obj(ctx, new_obj); pdf_drop_obj(ctx, new_ref); pdf_drop_obj(ctx, res); } fz_catch(ctx) { fz_rethrow(ctx); } }
void pdf_add_portfolio_schema(fz_context *ctx, pdf_document *doc, int entry, const pdf_portfolio_schema *info) { pdf_portfolio **pp; pdf_portfolio *p; pdf_obj *s; pdf_obj *sc; int num; char str_name[32]; pdf_obj *num_name = NULL; if (!doc) fz_throw(ctx, FZ_ERROR_GENERIC, "Bad pdf_add_portfolio_schema call"); if (doc->portfolio == NULL) load_portfolio(ctx, doc); fz_var(num_name); pp = &doc->portfolio; while (*pp && entry > 0) pp = &(*pp)->next, entry--; fz_try(ctx) { /* Find a name for the new schema entry */ num = 0; do { pdf_drop_obj(ctx, num_name); num_name = NULL; num++; sprintf(str_name, "%d", num); num_name = pdf_new_name(ctx, doc, str_name); p = doc->portfolio; for (p = doc->portfolio; p; p = p->next) if (pdf_name_eq(ctx, num_name, p->key)) break; } while (p); sc = pdf_new_dict(ctx, doc, 4); pdf_dict_put_drop(ctx, sc, PDF_NAME_E, pdf_new_bool(ctx, doc, !!info->editable)); pdf_dict_put_drop(ctx, sc, PDF_NAME_V, pdf_new_bool(ctx, doc, !!info->visible)); pdf_dict_put_drop(ctx, sc, PDF_NAME_N, info->name); pdf_dict_put(ctx, sc, PDF_NAME_Subtype, PDF_NAME_S); /* Add to our linked list (in the correct sorted place) */ p = fz_malloc_struct(ctx, pdf_portfolio); p->entry = *info; p->sort = 0; /* Will be rewritten in a mo */ p->key = pdf_keep_obj(ctx, num_name); p->val = pdf_keep_obj(ctx, sc); p->next = *pp; *pp = p; /* Add the key to the schema */ s = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME_Root, PDF_NAME_Collection, PDF_NAME_Schema, NULL); pdf_dict_put(ctx, s, num_name, sc); /* Renumber the schema entries */ for (num = 0, p = doc->portfolio; p; num++, p = p->next) { pdf_dict_put_drop(ctx, p->val, PDF_NAME_O, pdf_new_int(ctx, doc, num)); p->sort = num; } } fz_always(ctx) pdf_drop_obj(ctx, num_name); fz_catch(ctx) fz_rethrow(ctx); }