Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/xps/xpsresource.c
Line
Count
Source
1
/* Copyright (C) 2001-2023 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* XPS interpreter - resource functions */
18
19
#include "ghostxps.h"
20
21
static xps_item_t *
22
xps_find_resource(xps_context_t *ctx, xps_resource_t *dict, char *name, char **urip)
23
0
{
24
0
    xps_resource_t *head, *node;
25
0
    for (head = dict; head; head = head->parent)
26
0
    {
27
0
        for (node = head; node; node = node->next)
28
0
        {
29
0
            if (!strcmp(node->name, name))
30
0
            {
31
0
                if (urip && head->base_uri)
32
0
                    *urip = head->base_uri;
33
0
                return node->data;
34
0
            }
35
0
        }
36
0
    }
37
0
    return NULL;
38
0
}
39
40
static xps_item_t *
41
xps_parse_resource_reference(xps_context_t *ctx, xps_resource_t *dict, char *att, char **urip)
42
5.72k
{
43
5.72k
    char name[1024];
44
5.72k
    char *s;
45
46
5.72k
    if (strstr(att, "{StaticResource ") != att)
47
5.72k
        return NULL;
48
49
0
    gs_strlcpy(name, att + 16, sizeof name);
50
0
    s = strrchr(name, '}');
51
0
    if (s)
52
0
        *s = 0;
53
54
0
    return xps_find_resource(ctx, dict, name, urip);
55
5.72k
}
56
57
void
58
xps_resolve_resource_reference(xps_context_t *ctx, xps_resource_t *dict,
59
        char **attp, xps_item_t **tagp, char **urip)
60
17.1k
{
61
17.1k
    if (*attp)
62
5.72k
    {
63
5.72k
        xps_item_t *rsrc = xps_parse_resource_reference(ctx, dict, *attp, urip);
64
5.72k
        if (rsrc)
65
0
        {
66
0
            *attp = NULL;
67
0
            *tagp = rsrc;
68
0
        }
69
5.72k
    }
70
17.1k
}
71
72
static int
73
xps_parse_remote_resource_dictionary(xps_context_t *ctx, xps_resource_t **dictp, char *base_uri, char *source_att)
74
0
{
75
0
    char part_name[1024];
76
0
    char part_uri[1024];
77
0
    xps_resource_t *dict = *dictp;
78
0
    xps_part_t *part;
79
0
    xps_item_t *xml;
80
0
    char *s;
81
0
    int code;
82
83
    /* External resource dictionaries MUST NOT reference other resource dictionaries */
84
0
    xps_absolute_path(part_name, base_uri, source_att, sizeof part_name);
85
0
    part = xps_read_part(ctx, part_name);
86
0
    if (!part)
87
0
    {
88
0
        return gs_throw1(-1, "cannot find remote resource part '%s'", part_name);
89
0
    }
90
91
0
    xml = xps_parse_xml(ctx, part->data, part->size);
92
0
    if (!xml)
93
0
    {
94
0
        xps_free_part(ctx, part);
95
0
        return gs_rethrow(-1, "cannot parse xml");
96
0
    }
97
98
0
    if (strcmp(xps_tag(xml), "ResourceDictionary"))
99
0
    {
100
0
        xps_free_item(ctx, xml);
101
0
        xps_free_part(ctx, part);
102
0
        return gs_throw1(-1, "expected ResourceDictionary element (found %s)", xps_tag(xml));
103
0
    }
104
105
0
    gs_strlcpy(part_uri, part_name, sizeof part_uri);
106
0
    s = strrchr(part_uri, '/');
107
0
    if (s)
108
0
        s[1] = 0;
109
110
0
    code = xps_parse_resource_dictionary(ctx, &dict, part_uri, xml);
111
0
    if (code)
112
0
    {
113
0
        xps_free_item(ctx, xml);
114
0
        xps_free_part(ctx, part);
115
0
        return gs_rethrow1(code, "cannot parse remote resource dictionary: %s", part_uri);
116
0
    }
117
118
0
    if (dict != NULL)
119
0
        dict->base_xml = xml; /* pass on ownership */
120
0
    else
121
0
        xps_free_item(ctx, xml);
122
123
0
    xps_free_part(ctx, part);
124
125
0
    *dictp = dict;
126
0
    return gs_okay;
127
0
}
128
129
int
130
xps_parse_resource_dictionary(xps_context_t *ctx, xps_resource_t **dictp, char *base_uri, xps_item_t *root)
131
0
{
132
0
    xps_resource_t *head;
133
0
    xps_resource_t *entry;
134
0
    xps_item_t *node;
135
0
    char *source;
136
0
    char *key;
137
0
    int code;
138
139
0
    if (*dictp)
140
0
    {
141
0
        gs_warn("multiple resource dictionaries; ignoring all but the first");
142
0
        return gs_okay;
143
0
    }
144
145
0
    source = xps_att(root, "Source");
146
0
    if (source)
147
0
    {
148
0
        code = xps_parse_remote_resource_dictionary(ctx, dictp, base_uri, source);
149
0
        if (code)
150
0
            return gs_rethrow(code, "cannot parse remote resource dictionary");
151
0
        return gs_okay;
152
0
    }
153
154
0
    head = NULL;
155
156
0
    for (node = xps_down(root); node; node = xps_next(node))
157
0
    {
158
        /* Usually "x:Key"; we have already processed and stripped namespace */
159
0
        key = xps_att(node, "Key");
160
0
        if (key)
161
0
        {
162
0
            entry = xps_alloc(ctx, sizeof(xps_resource_t));
163
0
            if (!entry)
164
0
                return gs_throw(gs_error_VMerror, "cannot allocate resource entry");
165
0
            entry->name = key;
166
0
            entry->base_uri = NULL;
167
0
            entry->base_xml = NULL;
168
0
            entry->data = node;
169
0
            entry->next = head;
170
0
            entry->parent = NULL;
171
0
            head = entry;
172
0
        }
173
0
    }
174
175
0
    if (head)
176
0
    {
177
0
        head->base_uri = xps_strdup(ctx, base_uri);
178
0
    }
179
0
    else
180
0
    {
181
0
        gs_warn("empty resource dictionary");
182
0
    }
183
184
0
    *dictp = head;
185
0
    return gs_okay;
186
0
}
187
188
void
189
xps_free_resource_dictionary(xps_context_t *ctx, xps_resource_t *dict)
190
0
{
191
0
    xps_resource_t *next;
192
0
    while (dict)
193
0
    {
194
0
        next = dict->next;
195
0
        if (dict->base_xml)
196
0
            xps_free_item(ctx, dict->base_xml);
197
0
        if (dict->base_uri)
198
0
            xps_free(ctx, dict->base_uri);
199
0
        xps_free(ctx, dict);
200
0
        dict = next;
201
0
    }
202
0
}
203
204
void
205
xps_debug_resource_dictionary(xps_context_t *ctx, xps_resource_t *dict)
206
0
{
207
0
    while (dict)
208
0
    {
209
0
        if (dict->base_uri)
210
0
            dmprintf1(ctx->memory, "URI = '%s'\n", dict->base_uri);
211
0
        dmprintf2(ctx->memory, "KEY = '%s' VAL = "PRI_INTPTR"\n",
212
0
                  dict->name, (intptr_t)dict->data);
213
0
        if (dict->parent)
214
0
        {
215
0
            dmputs(ctx->memory, "PARENT = {\n");
216
0
            xps_debug_resource_dictionary(ctx, dict->parent);
217
0
            dmputs(ctx->memory, "}\n");
218
0
        }
219
0
        dict = dict->next;
220
0
    }
221
0
}