diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2011-11-10 01:52:40 +0100 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2011-11-10 01:52:40 +0100 |
commit | 97d00440c043b712a2d16134e3b52850c7b36d47 (patch) | |
tree | e7b838f3b7c714037bb238b0c4d17ab4aaa3e0ed /xps/xps_outline.c | |
parent | c445538b312a45435df87086eed2e19b68ed5bc1 (diff) | |
download | mupdf-97d00440c043b712a2d16134e3b52850c7b36d47.tar.xz |
Add XPS outline parsing and move outline data struct to fz_outline.
Diffstat (limited to 'xps/xps_outline.c')
-rw-r--r-- | xps/xps_outline.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/xps/xps_outline.c b/xps/xps_outline.c new file mode 100644 index 00000000..a4ab6c19 --- /dev/null +++ b/xps/xps_outline.c @@ -0,0 +1,124 @@ +#include "fitz.h" +#include "muxps.h" + +/* + * Parse the document structure / outline parts referenced from fixdoc relationships. + */ + +static fz_outline * +xps_find_last_outline_at_level(fz_outline *node, int level, int target_level) +{ + while (node->next) + node = node->next; + if (level == target_level || !node->down) + return node; + return xps_find_last_outline_at_level(node->down, level + 1, target_level); +} + +static fz_outline * +xps_parse_document_outline(xps_context *ctx, xml_element *root) +{ + xml_element *node; + fz_outline *head = NULL, *entry, *tail; + int last_level = 1, this_level; + for (node = xml_down(root); node; node = xml_next(node)) + { + if (!strcmp(xml_tag(node), "OutlineEntry")) + { + char *level = xml_att(node, "OutlineLevel"); + char *target = xml_att(node, "OutlineTarget"); + char *description = xml_att(node, "Description"); + if (!target || !description) + continue; + + entry = fz_malloc(sizeof *entry); + entry->title = fz_strdup(description); + entry->page = xps_find_link_target(ctx, target); + entry->down = NULL; + entry->next = NULL; + + this_level = level ? atoi(level) : 1; + + if (!head) + { + head = entry; + } + else + { + tail = xps_find_last_outline_at_level(head, 1, this_level); + if (this_level > last_level) + tail->down = entry; + else + tail->next = entry; + } + + last_level = this_level; + } + } + return head; +} + +static fz_outline * +xps_parse_document_structure(xps_context *ctx, xml_element *root) +{ + xml_element *node; + if (!strcmp(xml_tag(root), "DocumentStructure")) + { + node = xml_down(root); + if (!strcmp(xml_tag(node), "DocumentStructure.Outline")) + { + node = xml_down(node); + if (!strcmp(xml_tag(node), "DocumentOutline")) + return xps_parse_document_outline(ctx, node); + } + } + return NULL; +} + +static fz_outline * +xps_load_document_structure(xps_context *ctx, xps_document *fixdoc) +{ + xps_part *part; + xml_element *root; + fz_outline *outline; + + part = xps_read_part(ctx, fixdoc->outline); + if (!part) + return NULL; + + root = xml_parse_document(part->data, part->size); + if (!root) { + fz_catch(-1, "cannot parse document structure part '%s'", part->name); + xps_free_part(ctx, part); + return NULL; + } + + outline = xps_parse_document_structure(ctx, root); + + xml_free_element(root); + xps_free_part(ctx, part); + + return outline; + +} + +fz_outline * +xps_load_outline(xps_context *ctx) +{ + xps_document *fixdoc; + fz_outline *head = NULL, *tail, *outline; + + for (fixdoc = ctx->first_fixdoc; fixdoc; fixdoc = fixdoc->next) { + if (fixdoc->outline) { + outline = xps_load_document_structure(ctx, fixdoc); + if (outline) { + if (!head) + head = outline; + else + tail->next = outline; + tail = outline; + } + } + } + return head; +} |