comparison mupdf-source/source/xps/xps-resource.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // Copyright (C) 2004-2021 Artifex Software, Inc.
2 //
3 // This file is part of MuPDF.
4 //
5 // MuPDF is free software: you can redistribute it and/or modify it under the
6 // terms of the GNU Affero General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or (at your option)
8 // any later version.
9 //
10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17 //
18 // Alternative licensing terms are available from the licensor.
19 // For commercial licensing, see <https://www.artifex.com/> or contact
20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21 // CA 94129, USA, for further information.
22
23 #include "mupdf/fitz.h"
24 #include "xps-imp.h"
25
26 #include <string.h>
27
28 static fz_xml *
29 xps_lookup_resource(fz_context *ctx, xps_document *doc, xps_resource *dict, char *name, char **urip)
30 {
31 xps_resource *head, *node;
32 for (head = dict; head; head = head->parent)
33 {
34 for (node = head; node; node = node->next)
35 {
36 if (!strcmp(node->name, name))
37 {
38 if (urip && head->base_uri)
39 *urip = head->base_uri;
40 return node->data;
41 }
42 }
43 }
44 return NULL;
45 }
46
47 static fz_xml *
48 xps_parse_resource_reference(fz_context *ctx, xps_document *doc, xps_resource *dict, char *att, char **urip)
49 {
50 char name[1024];
51 char *s;
52
53 if (strstr(att, "{StaticResource ") != att)
54 return NULL;
55
56 fz_strlcpy(name, att + 16, sizeof name);
57 s = strrchr(name, '}');
58 if (s)
59 *s = 0;
60
61 return xps_lookup_resource(ctx, doc, dict, name, urip);
62 }
63
64 void
65 xps_resolve_resource_reference(fz_context *ctx, xps_document *doc, xps_resource *dict,
66 char **attp, fz_xml **tagp, char **urip)
67 {
68 if (*attp)
69 {
70 fz_xml *rsrc = xps_parse_resource_reference(ctx, doc, dict, *attp, urip);
71 if (rsrc)
72 {
73 *attp = NULL;
74 *tagp = rsrc;
75 }
76 }
77 }
78
79 static xps_resource *
80 xps_parse_remote_resource_dictionary(fz_context *ctx, xps_document *doc, char *base_uri, char *source_att)
81 {
82 char part_name[1024];
83 char part_uri[1024];
84 xps_part *part;
85 xps_resource *dict = NULL;
86 fz_xml_doc *xml = NULL;
87 char *s;
88
89 fz_var(xml);
90
91 /* External resource dictionaries MUST NOT reference other resource dictionaries */
92 xps_resolve_url(ctx, doc, part_name, base_uri, source_att, sizeof part_name);
93
94 part = xps_read_part(ctx, doc, part_name);
95 fz_try(ctx)
96 {
97 xml = fz_parse_xml(ctx, part->data, 0);
98 if (!fz_xml_is_tag(fz_xml_root(xml), "ResourceDictionary"))
99 fz_throw(ctx, FZ_ERROR_FORMAT, "expected ResourceDictionary element");
100
101 fz_strlcpy(part_uri, part_name, sizeof part_uri);
102 s = strrchr(part_uri, '/');
103 if (s)
104 s[1] = 0;
105
106 dict = xps_parse_resource_dictionary(ctx, doc, part_uri, fz_xml_root(xml));
107 if (dict)
108 {
109 dict->base_xml = xml; /* pass on ownership */
110 xml = NULL;
111 }
112 }
113 fz_always(ctx)
114 {
115 xps_drop_part(ctx, doc, part);
116 fz_drop_xml(ctx, xml);
117 }
118 fz_catch(ctx)
119 {
120 fz_rethrow(ctx);
121 }
122
123 return dict;
124 }
125
126 xps_resource *
127 xps_parse_resource_dictionary(fz_context *ctx, xps_document *doc, char *base_uri, fz_xml *root)
128 {
129 xps_resource *head;
130 xps_resource *entry;
131 fz_xml *node;
132 char *source;
133 char *key;
134
135 source = fz_xml_att(root, "Source");
136 if (source)
137 return xps_parse_remote_resource_dictionary(ctx, doc, base_uri, source);
138
139 head = NULL;
140
141 for (node = fz_xml_down(root); node; node = fz_xml_next(node))
142 {
143 key = fz_xml_att(node, "x:Key");
144 if (key)
145 {
146 entry = fz_malloc_struct(ctx, xps_resource);
147 entry->name = key;
148 entry->base_uri = NULL;
149 entry->base_xml = NULL;
150 entry->data = node;
151 entry->next = head;
152 entry->parent = NULL;
153 head = entry;
154 }
155 }
156
157 if (head)
158 {
159 fz_try(ctx)
160 head->base_uri = fz_strdup(ctx, base_uri);
161 fz_catch(ctx)
162 {
163 fz_free(ctx, entry);
164 fz_rethrow(ctx);
165 }
166 }
167
168 return head;
169 }
170
171 void
172 xps_drop_resource_dictionary(fz_context *ctx, xps_document *doc, xps_resource *dict)
173 {
174 xps_resource *next;
175 while (dict)
176 {
177 next = dict->next;
178 fz_drop_xml(ctx, dict->base_xml);
179 fz_free(ctx, dict->base_uri);
180 fz_free(ctx, dict);
181 dict = next;
182 }
183 }