Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7639 views
1
#include "mupdf/xps.h"
2
3
/*
4
* Parse the document structure / outline parts referenced from fixdoc relationships.
5
*/
6
7
static fz_outline *
8
xps_lookup_last_outline_at_level(fz_context *ctx, xps_document *doc, fz_outline *node, int level, int target_level)
9
{
10
while (node->next)
11
node = node->next;
12
if (level == target_level || !node->down)
13
return node;
14
return xps_lookup_last_outline_at_level(ctx, doc, node->down, level + 1, target_level);
15
}
16
17
static fz_outline *
18
xps_parse_document_outline(fz_context *ctx, xps_document *doc, fz_xml *root)
19
{
20
fz_xml *node;
21
fz_outline *head = NULL, *entry, *tail;
22
int last_level = 1, this_level;
23
for (node = fz_xml_down(root); node; node = fz_xml_next(node))
24
{
25
if (fz_xml_is_tag(node, "OutlineEntry"))
26
{
27
char *level = fz_xml_att(node, "OutlineLevel");
28
char *target = fz_xml_att(node, "OutlineTarget");
29
char *description = fz_xml_att(node, "Description");
30
if (!target || !description)
31
continue;
32
33
entry = fz_malloc_struct(ctx, fz_outline);
34
entry->title = fz_strdup(ctx, description);
35
entry->dest.kind = FZ_LINK_GOTO;
36
entry->dest.ld.gotor.flags = 0;
37
entry->dest.ld.gotor.page = xps_lookup_link_target(ctx, doc, target);
38
entry->down = NULL;
39
entry->next = NULL;
40
41
this_level = level ? atoi(level) : 1;
42
43
if (!head)
44
{
45
head = entry;
46
}
47
else
48
{
49
tail = xps_lookup_last_outline_at_level(ctx, doc, head, 1, this_level);
50
if (this_level > last_level)
51
tail->down = entry;
52
else
53
tail->next = entry;
54
}
55
56
last_level = this_level;
57
}
58
}
59
return head;
60
}
61
62
static fz_outline *
63
xps_parse_document_structure(fz_context *ctx, xps_document *doc, fz_xml *root)
64
{
65
fz_xml *node;
66
if (fz_xml_is_tag(root, "DocumentStructure"))
67
{
68
node = fz_xml_down(root);
69
if (node && fz_xml_is_tag(node, "DocumentStructure.Outline"))
70
{
71
node = fz_xml_down(node);
72
if (node && fz_xml_is_tag(node, "DocumentOutline"))
73
return xps_parse_document_outline(ctx, doc, node);
74
}
75
}
76
return NULL;
77
}
78
79
static fz_outline *
80
xps_load_document_structure(fz_context *ctx, xps_document *doc, xps_fixdoc *fixdoc)
81
{
82
xps_part *part;
83
fz_xml *root;
84
fz_outline *outline;
85
86
part = xps_read_part(ctx, doc, fixdoc->outline);
87
fz_try(ctx)
88
{
89
root = fz_parse_xml(ctx, part->data, part->size, 0);
90
}
91
fz_always(ctx)
92
{
93
xps_drop_part(ctx, doc, part);
94
}
95
fz_catch(ctx)
96
{
97
fz_rethrow(ctx);
98
}
99
if (!root)
100
return NULL;
101
102
fz_try(ctx)
103
{
104
outline = xps_parse_document_structure(ctx, doc, root);
105
}
106
fz_always(ctx)
107
{
108
fz_drop_xml(ctx, root);
109
}
110
fz_catch(ctx)
111
{
112
fz_rethrow(ctx);
113
}
114
115
return outline;
116
}
117
118
fz_outline *
119
xps_load_outline(fz_context *ctx, xps_document *doc)
120
{
121
xps_fixdoc *fixdoc;
122
fz_outline *head = NULL, *tail, *outline;
123
124
for (fixdoc = doc->first_fixdoc; fixdoc; fixdoc = fixdoc->next)
125
{
126
if (fixdoc->outline)
127
{
128
fz_try(ctx)
129
{
130
outline = xps_load_document_structure(ctx, doc, fixdoc);
131
}
132
fz_catch(ctx)
133
{
134
fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
135
outline = NULL;
136
}
137
if (!outline)
138
continue;
139
140
if (!head)
141
head = outline;
142
else
143
{
144
while (tail->next)
145
tail = tail->next;
146
tail->next = outline;
147
}
148
tail = outline;
149
}
150
}
151
return head;
152
}
153
154