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_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 = pdf_dict_gets(dict, "Title"); if (obj) node->title = pdf_to_utf8(ctx, 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_catch(ctx) { for (dict = odict; dict && pdf_dict_marked(dict); dict = pdf_dict_gets(dict, "Next")) pdf_dict_unmark(dict); fz_rethrow(ctx); } for (dict = odict; dict && pdf_dict_marked(dict); dict = pdf_dict_gets(dict, "Next")) pdf_dict_unmark(dict); return first; }
static void pdf_load_name_tree_imp(pdf_obj *dict, pdf_document *xref, pdf_obj *node) { fz_context *ctx = xref->ctx; pdf_obj *kids = pdf_dict_gets(node, "Kids"); pdf_obj *names = pdf_dict_gets(node, "Names"); int i; if (kids && !pdf_dict_mark(node)) { for (i = 0; i < pdf_array_len(kids); i++) pdf_load_name_tree_imp(dict, xref, pdf_array_get(kids, i)); pdf_dict_unmark(node); } if (names) { for (i = 0; i + 1 < pdf_array_len(names); i += 2) { pdf_obj *key = pdf_array_get(names, i); pdf_obj *val = pdf_array_get(names, i + 1); if (pdf_is_string(key)) { key = pdf_to_utf8_name(ctx, key); pdf_dict_put(dict, key, val); pdf_drop_obj(key); } else if (pdf_is_name(key)) { pdf_dict_put(dict, key, val); } } } }
static pdf_obj * pdf_lookup_name_imp(fz_context *ctx, pdf_obj *node, pdf_obj *needle) { pdf_obj *kids = pdf_dict_gets(node, "Kids"); pdf_obj *names = pdf_dict_gets(node, "Names"); if (pdf_is_array(kids)) { int l = 0; int r = pdf_array_len(kids) - 1; while (l <= r) { int m = (l + r) >> 1; pdf_obj *kid = pdf_array_get(kids, m); pdf_obj *limits = pdf_dict_gets(kid, "Limits"); pdf_obj *first = pdf_array_get(limits, 0); pdf_obj *last = pdf_array_get(limits, 1); if (pdf_objcmp(needle, first) < 0) r = m - 1; else if (pdf_objcmp(needle, last) > 0) l = m + 1; else { pdf_obj *obj; if (pdf_dict_mark(node)) break; obj = pdf_lookup_name_imp(ctx, kid, needle); pdf_dict_unmark(node); return obj; } } } if (pdf_is_array(names)) { int l = 0; int r = (pdf_array_len(names) / 2) - 1; while (l <= r) { int m = (l + r) >> 1; int c; pdf_obj *key = pdf_array_get(names, m * 2); pdf_obj *val = pdf_array_get(names, m * 2 + 1); c = pdf_objcmp(needle, key); if (c < 0) r = m - 1; else if (c > 0) l = m + 1; else return val; } /* Spec says names should be sorted (hence the binary search, * above), but Acrobat copes with non-sorted. Drop back to a * simple search if the binary search fails. */ r = pdf_array_len(names)/2; for (l = 0; l < r; l++) if (!pdf_objcmp(needle, pdf_array_get(names, l * 2))) return pdf_array_get(names, l * 2 + 1); } return NULL; }