fz_link_dest pdf_parse_action(pdf_document *xref, pdf_obj *action) { fz_link_dest ld; pdf_obj *obj, *dest; fz_context *ctx = xref->ctx; UNUSED(ctx); ld.kind = FZ_LINK_NONE; if (!action) return ld; obj = pdf_dict_gets(action, "S"); if (!strcmp(pdf_to_name(obj), "GoTo")) { dest = pdf_dict_gets(action, "D"); ld = pdf_parse_link_dest(xref, dest); } else if (!strcmp(pdf_to_name(obj), "URI")) { ld.kind = FZ_LINK_URI; ld.ld.uri.is_map = pdf_to_bool(pdf_dict_gets(action, "IsMap")); ld.ld.uri.uri = pdf_to_utf8(xref, pdf_dict_gets(action, "URI")); } else if (!strcmp(pdf_to_name(obj), "Launch")) { dest = pdf_dict_gets(action, "F"); ld.kind = FZ_LINK_LAUNCH; if (pdf_is_dict(dest)) dest = pdf_dict_gets(dest, "F"); ld.ld.launch.file_spec = pdf_to_utf8(xref, dest); ld.ld.launch.new_window = pdf_to_int(pdf_dict_gets(action, "NewWindow")); } else if (!strcmp(pdf_to_name(obj), "Named")) { ld.kind = FZ_LINK_NAMED; ld.ld.named.named = pdf_to_utf8(xref, pdf_dict_gets(action, "N")); } else if (!strcmp(pdf_to_name(obj), "GoToR")) { dest = pdf_dict_gets(action, "D"); ld = pdf_parse_link_dest(xref, dest); ld.kind = FZ_LINK_GOTOR; ld.ld.gotor.file_spec = pdf_to_utf8(xref, pdf_dict_gets(action, "F")); ld.ld.gotor.new_window = pdf_to_int(pdf_dict_gets(action, "NewWindow")); } return ld; }
static fz_outline * pdf_load_outline_imp(pdf_document *xref, pdf_obj *dict) { fz_context *ctx = xref->ctx; fz_outline *node, **prev, *first; pdf_obj *obj; pdf_obj *odict = dict; fz_var(dict); fz_try(ctx) { first = NULL; prev = &first; while (dict && pdf_is_dict(dict)) { if (pdf_obj_mark(dict)) break; node = fz_malloc_struct(ctx, fz_outline); node->title = NULL; node->dest.kind = FZ_LINK_NONE; node->down = NULL; node->next = NULL; *prev = node; prev = &node->next; obj = pdf_dict_gets(dict, "Title"); if (obj) node->title = pdf_to_utf8(xref, obj); /* SumatraPDF: support expansion states */ node->is_open = pdf_to_int(pdf_dict_gets(dict, "Count")) >= 0; if ((obj = pdf_dict_gets(dict, "Dest"))) node->dest = pdf_parse_link_dest(xref, obj); else if ((obj = pdf_dict_gets(dict, "A"))) node->dest = pdf_parse_action(xref, obj); obj = pdf_dict_gets(dict, "First"); if (obj) node->down = pdf_load_outline_imp(xref, obj); dict = pdf_dict_gets(dict, "Next"); } } fz_always(ctx) { for (dict = odict; dict && pdf_obj_marked(dict); dict = pdf_dict_gets(dict, "Next")) pdf_obj_unmark(dict); } fz_catch(ctx) { /* SumatraPDF: fix memory leak */ fz_free_outline(ctx, first); fz_rethrow(ctx); } return first; }
static fz_outline * pdf_load_outline_imp(pdf_document *xref, fz_obj *dict) { fz_context *ctx = xref->ctx; fz_outline *node, **prev, *first; fz_obj *obj; fz_obj *odict = dict; fz_var(dict); fz_try(ctx) { first = NULL; prev = &first; while (dict && fz_is_dict(dict)) { if (fz_dict_mark(dict)) break; node = fz_malloc_struct(ctx, fz_outline); node->title = NULL; node->dest.kind = FZ_LINK_NONE; node->down = NULL; node->next = NULL; *prev = node; prev = &node->next; obj = fz_dict_gets(dict, "Title"); if (obj) node->title = pdf_to_utf8(ctx, obj); if ((obj = fz_dict_gets(dict, "Dest"))) node->dest = pdf_parse_link_dest(xref, obj); else if ((obj = fz_dict_gets(dict, "A"))) node->dest = pdf_parse_action(xref, obj); obj = fz_dict_gets(dict, "First"); if (obj) node->down = pdf_load_outline_imp(xref, obj); dict = fz_dict_gets(dict, "Next"); } } fz_catch(ctx) { for (dict = odict; dict && fz_dict_marked(dict); dict = fz_dict_gets(dict, "Next")) fz_dict_unmark(dict); fz_rethrow(ctx); } for (dict = odict; dict && fz_dict_marked(dict); dict = fz_dict_gets(dict, "Next")) fz_dict_unmark(dict); return first; }
static fz_link * pdf_load_link(fz_context *ctx, pdf_document *doc, pdf_obj *dict, int pagenum, const fz_matrix *page_ctm) { pdf_obj *action; pdf_obj *obj; fz_rect bbox; char *uri; fz_link *link = NULL; obj = pdf_dict_get(ctx, dict, PDF_NAME_Subtype); if (!pdf_name_eq(ctx, obj, PDF_NAME_Link)) return NULL; obj = pdf_dict_get(ctx, dict, PDF_NAME_Rect); if (!obj) return NULL; pdf_to_rect(ctx, obj, &bbox); fz_transform_rect(&bbox, page_ctm); obj = pdf_dict_get(ctx, dict, PDF_NAME_Dest); if (obj) uri = pdf_parse_link_dest(ctx, doc, obj); else { action = pdf_dict_get(ctx, dict, PDF_NAME_A); /* fall back to additional action button's down/up action */ if (!action) action = pdf_dict_geta(ctx, pdf_dict_get(ctx, dict, PDF_NAME_AA), PDF_NAME_U, PDF_NAME_D); uri = pdf_parse_link_action(ctx, doc, action, pagenum); } if (!uri) return NULL; fz_try(ctx) link = fz_new_link(ctx, &bbox, doc, uri); fz_always(ctx) fz_free(ctx, uri); fz_catch(ctx) fz_rethrow(ctx); return link; }
static fz_link * pdf_load_link(pdf_document *xref, pdf_obj *dict, fz_matrix page_ctm) { pdf_obj *dest = NULL; pdf_obj *action; pdf_obj *obj; fz_rect bbox; fz_context *ctx = xref->ctx; fz_link_dest ld; dest = NULL; obj = pdf_dict_gets(dict, "Rect"); if (obj) bbox = pdf_to_rect(ctx, obj); else bbox = fz_empty_rect; bbox = fz_transform_rect(page_ctm, bbox); obj = pdf_dict_gets(dict, "Dest"); if (obj) { dest = resolve_dest(xref, obj); ld = pdf_parse_link_dest(xref, dest); } else { action = pdf_dict_gets(dict, "A"); /* fall back to additional action button's down/up action */ if (!action) action = pdf_dict_getsa(pdf_dict_gets(dict, "AA"), "U", "D"); ld = pdf_parse_action(xref, action); } if (ld.kind == FZ_LINK_NONE) return NULL; return fz_new_link(ctx, bbox, ld); }
char * pdf_parse_link_action(fz_context *ctx, pdf_document *doc, pdf_obj *action, int pagenum) { pdf_obj *obj, *dest, *file_spec; if (!action) return NULL; obj = pdf_dict_get(ctx, action, PDF_NAME_S); if (pdf_name_eq(ctx, PDF_NAME_GoTo, obj)) { dest = pdf_dict_get(ctx, action, PDF_NAME_D); return pdf_parse_link_dest(ctx, doc, dest); } else if (pdf_name_eq(ctx, PDF_NAME_URI, obj)) { /* URI entries are ASCII strings */ const char *uri = pdf_to_str_buf(ctx, pdf_dict_get(ctx, action, PDF_NAME_URI)); if (!fz_is_external_link(ctx, uri)) { pdf_obj *uri_base_obj = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/URI/Base"); const char *uri_base = uri_base_obj ? pdf_to_str_buf(ctx, uri_base_obj) : "file://"; char *new_uri = fz_malloc(ctx, strlen(uri_base) + strlen(uri) + 1); strcpy(new_uri, uri_base); strcat(new_uri, uri); return new_uri; } return fz_strdup(ctx, uri); } else if (pdf_name_eq(ctx, PDF_NAME_Launch, obj)) { file_spec = pdf_dict_get(ctx, action, PDF_NAME_F); return pdf_parse_file_spec(ctx, doc, file_spec, NULL); } else if (pdf_name_eq(ctx, PDF_NAME_GoToR, obj)) { dest = pdf_dict_get(ctx, action, PDF_NAME_D); file_spec = pdf_dict_get(ctx, action, PDF_NAME_F); return pdf_parse_file_spec(ctx, doc, file_spec, dest); } else if (pdf_name_eq(ctx, PDF_NAME_Named, obj)) { dest = pdf_dict_get(ctx, action, PDF_NAME_N); if (pdf_name_eq(ctx, PDF_NAME_FirstPage, dest)) pagenum = 0; else if (pdf_name_eq(ctx, PDF_NAME_LastPage, dest)) pagenum = pdf_count_pages(ctx, doc) - 1; else if (pdf_name_eq(ctx, PDF_NAME_PrevPage, dest) && pagenum >= 0) { if (pagenum > 0) pagenum--; } else if (pdf_name_eq(ctx, PDF_NAME_NextPage, dest) && pagenum >= 0) { if (pagenum < pdf_count_pages(ctx, doc) - 1) pagenum++; } else return NULL; return fz_asprintf(ctx, "#%d", pagenum + 1); } return NULL; }
static fz_outline * pdf_load_outline_imp(fz_context *ctx, pdf_document *doc, pdf_obj *dict) { fz_outline *node, **prev, *first; pdf_obj *obj; pdf_obj *odict = dict; fz_var(dict); fz_var(first); fz_try(ctx) { first = NULL; prev = &first; while (dict && pdf_is_dict(ctx, dict)) { if (pdf_mark_obj(ctx, dict)) break; node = fz_new_outline(ctx); *prev = node; prev = &node->next; obj = pdf_dict_get(ctx, dict, PDF_NAME_Title); if (obj) node->title = pdf_to_utf8(ctx, obj); if ((obj = pdf_dict_get(ctx, dict, PDF_NAME_Dest)) != NULL) node->uri = pdf_parse_link_dest(ctx, doc, obj); else if ((obj = pdf_dict_get(ctx, dict, PDF_NAME_A)) != NULL) node->uri = pdf_parse_link_action(ctx, doc, obj); else node->uri = NULL; if (node->uri) node->page = pdf_resolve_link(ctx, doc, node->uri, NULL, NULL); else node->page = -1; obj = pdf_dict_get(ctx, dict, PDF_NAME_First); if (obj) { node->down = pdf_load_outline_imp(ctx, doc, obj); obj = pdf_dict_get(ctx, dict, PDF_NAME_Count); if (pdf_to_int(ctx, obj) > 0) node->is_open = 1; } dict = pdf_dict_get(ctx, dict, PDF_NAME_Next); } } fz_always(ctx) { for (dict = odict; dict && pdf_obj_marked(ctx, dict); dict = pdf_dict_get(ctx, dict, PDF_NAME_Next)) pdf_unmark_obj(ctx, dict); } fz_catch(ctx) { fz_drop_outline(ctx, first); fz_rethrow(ctx); } return first; }