diff options
Diffstat (limited to 'source/pdf/pdf-nametree.c')
-rw-r--r-- | source/pdf/pdf-nametree.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/source/pdf/pdf-nametree.c b/source/pdf/pdf-nametree.c new file mode 100644 index 00000000..ea386dda --- /dev/null +++ b/source/pdf/pdf-nametree.c @@ -0,0 +1,166 @@ +#include "mupdf/pdf.h" + +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_obj_mark(node)) + break; + obj = pdf_lookup_name_imp(ctx, kid, needle); + pdf_obj_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; +} + +pdf_obj * +pdf_lookup_name(pdf_document *xref, char *which, pdf_obj *needle) +{ + fz_context *ctx = xref->ctx; + + pdf_obj *root = pdf_dict_gets(pdf_trailer(xref), "Root"); + pdf_obj *names = pdf_dict_gets(root, "Names"); + pdf_obj *tree = pdf_dict_gets(names, which); + return pdf_lookup_name_imp(ctx, tree, needle); +} + +pdf_obj * +pdf_lookup_dest(pdf_document *xref, pdf_obj *needle) +{ + fz_context *ctx = xref->ctx; + + pdf_obj *root = pdf_dict_gets(pdf_trailer(xref), "Root"); + pdf_obj *dests = pdf_dict_gets(root, "Dests"); + pdf_obj *names = pdf_dict_gets(root, "Names"); + pdf_obj *dest = NULL; + + /* PDF 1.1 has destinations in a dictionary */ + if (dests) + { + if (pdf_is_name(needle)) + return pdf_dict_get(dests, needle); + else + return pdf_dict_gets(dests, pdf_to_str_buf(needle)); + } + + /* PDF 1.2 has destinations in a name tree */ + if (names && !dest) + { + pdf_obj *tree = pdf_dict_gets(names, "Dests"); + return pdf_lookup_name_imp(ctx, tree, needle); + } + + return NULL; +} + +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; + + UNUSED(ctx); + + if (kids && !pdf_obj_mark(node)) + { + int len = pdf_array_len(kids); + for (i = 0; i < len; i++) + pdf_load_name_tree_imp(dict, xref, pdf_array_get(kids, i)); + pdf_obj_unmark(node); + } + + if (names) + { + int len = pdf_array_len(names); + for (i = 0; i + 1 < len; 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(xref, key); + pdf_dict_put(dict, key, val); + pdf_drop_obj(key); + } + else if (pdf_is_name(key)) + { + pdf_dict_put(dict, key, val); + } + } + } +} + +pdf_obj * +pdf_load_name_tree(pdf_document *xref, char *which) +{ + fz_context *ctx = xref->ctx; + + pdf_obj *root = pdf_dict_gets(pdf_trailer(xref), "Root"); + pdf_obj *names = pdf_dict_gets(root, "Names"); + pdf_obj *tree = pdf_dict_gets(names, which); + if (pdf_is_dict(tree)) + { + pdf_obj *dict = pdf_new_dict(ctx, 100); + pdf_load_name_tree_imp(dict, xref, tree); + return dict; + } + return NULL; +} |