1#include "mupdf/fitz.h"
2#include "xps-imp.h"
3
4#include <string.h>
5
6static fz_xml *
7xps_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
25static fz_xml *
26xps_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
42void
43xps_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
57static xps_resource *
58xps_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
104xps_resource *
105xps_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
149void
150xps_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