summaryrefslogtreecommitdiff
path: root/xps/xps_resource.c
diff options
context:
space:
mode:
Diffstat (limited to 'xps/xps_resource.c')
-rw-r--r--xps/xps_resource.c188
1 files changed, 188 insertions, 0 deletions
diff --git a/xps/xps_resource.c b/xps/xps_resource.c
new file mode 100644
index 00000000..59dc3f9d
--- /dev/null
+++ b/xps/xps_resource.c
@@ -0,0 +1,188 @@
+#include "fitz.h"
+#include "muxps.h"
+
+static xml_element *
+xps_find_resource(xps_context *ctx, xps_resource *dict, char *name, char **urip)
+{
+ xps_resource *head, *node;
+ for (head = dict; head; head = head->parent)
+ {
+ for (node = head; node; node = node->next)
+ {
+ if (!strcmp(node->name, name))
+ {
+ if (urip && head->base_uri)
+ *urip = head->base_uri;
+ return node->data;
+ }
+ }
+ }
+ return NULL;
+}
+
+static xml_element *
+xps_parse_resource_reference(xps_context *ctx, xps_resource *dict, char *att, char **urip)
+{
+ char name[1024];
+ char *s;
+
+ if (strstr(att, "{StaticResource ") != att)
+ return NULL;
+
+ fz_strlcpy(name, att + 16, sizeof name);
+ s = strrchr(name, '}');
+ if (s)
+ *s = 0;
+
+ return xps_find_resource(ctx, dict, name, urip);
+}
+
+void
+xps_resolve_resource_reference(xps_context *ctx, xps_resource *dict,
+ char **attp, xml_element **tagp, char **urip)
+{
+ if (*attp)
+ {
+ xml_element *rsrc = xps_parse_resource_reference(ctx, dict, *attp, urip);
+ if (rsrc)
+ {
+ *attp = NULL;
+ *tagp = rsrc;
+ }
+ }
+}
+
+static int
+xps_parse_remote_resource_dictionary(xps_context *ctx, xps_resource **dictp, char *base_uri, char *source_att)
+{
+ char part_name[1024];
+ char part_uri[1024];
+ xps_resource *dict;
+ xps_part *part;
+ xml_element *xml;
+ char *s;
+ int code;
+
+ /* External resource dictionaries MUST NOT reference other resource dictionaries */
+ xps_absolute_path(part_name, base_uri, source_att, sizeof part_name);
+ part = xps_read_part(ctx, part_name);
+ if (!part)
+ {
+ return fz_throw("cannot find remote resource part '%s'", part_name);
+ }
+
+ xml = xml_parse_document(part->data, part->size);
+ if (!xml)
+ {
+ xps_free_part(ctx, part);
+ return fz_rethrow(-1, "cannot parse xml");
+ }
+
+ if (strcmp(xml_tag(xml), "ResourceDictionary"))
+ {
+ xml_free_element(xml);
+ xps_free_part(ctx, part);
+ return fz_throw("expected ResourceDictionary element (found %s)", xml_tag(xml));
+ }
+
+ fz_strlcpy(part_uri, part_name, sizeof part_uri);
+ s = strrchr(part_uri, '/');
+ if (s)
+ s[1] = 0;
+
+ code = xps_parse_resource_dictionary(ctx, &dict, part_uri, xml);
+ if (code)
+ {
+ xml_free_element(xml);
+ xps_free_part(ctx, part);
+ return fz_rethrow(code, "cannot parse remote resource dictionary: %s", part_uri);
+ }
+
+ dict->base_xml = xml; /* pass on ownership */
+
+ xps_free_part(ctx, part);
+
+ *dictp = dict;
+ return fz_okay;
+}
+
+int
+xps_parse_resource_dictionary(xps_context *ctx, xps_resource **dictp, char *base_uri, xml_element *root)
+{
+ xps_resource *head;
+ xps_resource *entry;
+ xml_element *node;
+ char *source;
+ char *key;
+ int code;
+
+ source = xml_att(root, "Source");
+ if (source)
+ {
+ code = xps_parse_remote_resource_dictionary(ctx, dictp, base_uri, source);
+ if (code)
+ return fz_rethrow(code, "cannot parse remote resource dictionary");
+ return fz_okay;
+ }
+
+ head = NULL;
+
+ for (node = xml_down(root); node; node = xml_next(node))
+ {
+ /* Usually "x:Key"; we have already processed and stripped namespace */
+ key = xml_att(node, "Key");
+ if (key)
+ {
+ entry = fz_malloc(sizeof(xps_resource));
+ entry->name = key;
+ entry->base_uri = NULL;
+ entry->base_xml = NULL;
+ entry->data = node;
+ entry->next = head;
+ entry->parent = NULL;
+ head = entry;
+ }
+ }
+
+ if (head)
+ {
+ head->base_uri = fz_strdup(base_uri);
+ }
+
+ *dictp = head;
+ return fz_okay;
+}
+
+void
+xps_free_resource_dictionary(xps_context *ctx, xps_resource *dict)
+{
+ xps_resource *next;
+ while (dict)
+ {
+ next = dict->next;
+ if (dict->base_xml)
+ xml_free_element(dict->base_xml);
+ if (dict->base_uri)
+ fz_free(dict->base_uri);
+ fz_free(dict);
+ dict = next;
+ }
+}
+
+void
+xps_debug_resource_dictionary(xps_resource *dict)
+{
+ while (dict)
+ {
+ if (dict->base_uri)
+ printf("URI = '%s'\n", dict->base_uri);
+ printf("KEY = '%s' VAL = %p\n", dict->name, dict->data);
+ if (dict->parent)
+ {
+ printf("PARENT = {\n");
+ xps_debug_resource_dictionary(dict->parent);
+ printf("}\n");
+ }
+ dict = dict->next;
+ }
+}