1 | #include "mupdf/fitz.h" |
2 | #include "xps-imp.h" |
3 | |
4 | #include <string.h> |
5 | |
6 | static fz_xml * |
7 | xps_lookup_resource(fz_context *ctx, xps_document *doc, xps_resource *dict, char *name, char **urip) |
8 | { |
9 | xps_resource *head, *node; |
10 | for (head = dict; head; head = head->parent) |
11 | { |
12 | for (node = head; node; node = node->next) |
13 | { |
14 | if (!strcmp(node->name, name)) |
15 | { |
16 | if (urip && head->base_uri) |
17 | *urip = head->base_uri; |
18 | return node->data; |
19 | } |
20 | } |
21 | } |
22 | return NULL; |
23 | } |
24 | |
25 | static fz_xml * |
26 | xps_parse_resource_reference(fz_context *ctx, xps_document *doc, xps_resource *dict, char *att, char **urip) |
27 | { |
28 | char name[1024]; |
29 | char *s; |
30 | |
31 | if (strstr(att, "{StaticResource " ) != att) |
32 | return NULL; |
33 | |
34 | fz_strlcpy(name, att + 16, sizeof name); |
35 | s = strrchr(name, '}'); |
36 | if (s) |
37 | *s = 0; |
38 | |
39 | return xps_lookup_resource(ctx, doc, dict, name, urip); |
40 | } |
41 | |
42 | void |
43 | xps_resolve_resource_reference(fz_context *ctx, xps_document *doc, xps_resource *dict, |
44 | char **attp, fz_xml **tagp, char **urip) |
45 | { |
46 | if (*attp) |
47 | { |
48 | fz_xml *rsrc = xps_parse_resource_reference(ctx, doc, dict, *attp, urip); |
49 | if (rsrc) |
50 | { |
51 | *attp = NULL; |
52 | *tagp = rsrc; |
53 | } |
54 | } |
55 | } |
56 | |
57 | static xps_resource * |
58 | xps_parse_remote_resource_dictionary(fz_context *ctx, xps_document *doc, char *base_uri, char *source_att) |
59 | { |
60 | char part_name[1024]; |
61 | char part_uri[1024]; |
62 | xps_part *part; |
63 | xps_resource *dict = NULL; |
64 | fz_xml_doc *xml = NULL; |
65 | char *s; |
66 | |
67 | fz_var(xml); |
68 | |
69 | /* External resource dictionaries MUST NOT reference other resource dictionaries */ |
70 | xps_resolve_url(ctx, doc, part_name, base_uri, source_att, sizeof part_name); |
71 | |
72 | part = xps_read_part(ctx, doc, part_name); |
73 | fz_try(ctx) |
74 | { |
75 | xml = fz_parse_xml(ctx, part->data, 0); |
76 | if (!fz_xml_is_tag(fz_xml_root(xml), "ResourceDictionary" )) |
77 | fz_throw(ctx, FZ_ERROR_GENERIC, "expected ResourceDictionary element" ); |
78 | |
79 | fz_strlcpy(part_uri, part_name, sizeof part_uri); |
80 | s = strrchr(part_uri, '/'); |
81 | if (s) |
82 | s[1] = 0; |
83 | |
84 | dict = xps_parse_resource_dictionary(ctx, doc, part_uri, fz_xml_root(xml)); |
85 | if (dict) |
86 | { |
87 | dict->base_xml = xml; /* pass on ownership */ |
88 | xml = NULL; |
89 | } |
90 | } |
91 | fz_always(ctx) |
92 | { |
93 | xps_drop_part(ctx, doc, part); |
94 | fz_drop_xml(ctx, xml); |
95 | } |
96 | fz_catch(ctx) |
97 | { |
98 | fz_rethrow(ctx); |
99 | } |
100 | |
101 | return dict; |
102 | } |
103 | |
104 | xps_resource * |
105 | xps_parse_resource_dictionary(fz_context *ctx, xps_document *doc, char *base_uri, fz_xml *root) |
106 | { |
107 | xps_resource *head; |
108 | xps_resource *entry; |
109 | fz_xml *node; |
110 | char *source; |
111 | char *key; |
112 | |
113 | source = fz_xml_att(root, "Source" ); |
114 | if (source) |
115 | return xps_parse_remote_resource_dictionary(ctx, doc, base_uri, source); |
116 | |
117 | head = NULL; |
118 | |
119 | for (node = fz_xml_down(root); node; node = fz_xml_next(node)) |
120 | { |
121 | key = fz_xml_att(node, "x:Key" ); |
122 | if (key) |
123 | { |
124 | entry = fz_malloc_struct(ctx, xps_resource); |
125 | entry->name = key; |
126 | entry->base_uri = NULL; |
127 | entry->base_xml = NULL; |
128 | entry->data = node; |
129 | entry->next = head; |
130 | entry->parent = NULL; |
131 | head = entry; |
132 | } |
133 | } |
134 | |
135 | if (head) |
136 | { |
137 | fz_try(ctx) |
138 | head->base_uri = fz_strdup(ctx, base_uri); |
139 | fz_catch(ctx) |
140 | { |
141 | fz_free(ctx, entry); |
142 | fz_rethrow(ctx); |
143 | } |
144 | } |
145 | |
146 | return head; |
147 | } |
148 | |
149 | void |
150 | xps_drop_resource_dictionary(fz_context *ctx, xps_document *doc, xps_resource *dict) |
151 | { |
152 | xps_resource *next; |
153 | while (dict) |
154 | { |
155 | next = dict->next; |
156 | fz_drop_xml(ctx, dict->base_xml); |
157 | fz_free(ctx, dict->base_uri); |
158 | fz_free(ctx, dict); |
159 | dict = next; |
160 | } |
161 | } |
162 | |