1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
#include "muxps-internal.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_document *doc, 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_struct(doc->ctx, fz_outline);
entry->title = fz_strdup(doc->ctx, description);
entry->dest.kind = FZ_LINK_GOTO;
entry->dest.ld.gotor.flags = 0;
entry->dest.ld.gotor.page = xps_find_link_target(doc, 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_document *doc, 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(doc, node);
}
}
return NULL;
}
static fz_outline *
xps_load_document_structure(xps_document *doc, xps_fixdoc *fixdoc)
{
xps_part *part;
xml_element *root;
fz_outline *outline;
part = xps_read_part(doc, fixdoc->outline);
fz_try(doc->ctx)
{
root = xml_parse_document(doc->ctx, part->data, part->size);
}
fz_catch(doc->ctx)
{
xps_free_part(doc, part);
fz_rethrow(doc->ctx);
}
xps_free_part(doc, part);
fz_try(doc->ctx)
{
outline = xps_parse_document_structure(doc, root);
}
fz_catch(doc->ctx)
{
xml_free_element(doc->ctx, root);
fz_rethrow(doc->ctx);
}
xml_free_element(doc->ctx, root);
return outline;
}
fz_outline *
xps_load_outline(xps_document *doc)
{
xps_fixdoc *fixdoc;
fz_outline *head = NULL, *tail, *outline;
for (fixdoc = doc->first_fixdoc; fixdoc; fixdoc = fixdoc->next) {
if (fixdoc->outline) {
outline = xps_load_document_structure(doc, fixdoc);
if (!head)
head = outline;
else
tail->next = outline;
tail = outline;
}
}
return head;
}
|