Coverage Report

Created: 2025-08-26 07:06

/src/libxslt/libxslt/imports.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * imports.c: Implementation of the XSLT imports
3
 *
4
 * Reference:
5
 *   http://www.w3.org/TR/1999/REC-xslt-19991116
6
 *
7
 * See Copyright for the status of this software.
8
 *
9
 * daniel@veillard.com
10
 */
11
12
#define IN_LIBXSLT
13
#include "libxslt.h"
14
15
#include <string.h>
16
17
#include <libxml/xmlmemory.h>
18
#include <libxml/parser.h>
19
#include <libxml/hash.h>
20
#include <libxml/xmlerror.h>
21
#include <libxml/uri.h>
22
#include "xslt.h"
23
#include "xsltInternals.h"
24
#include "xsltutils.h"
25
#include "preproc.h"
26
#include "imports.h"
27
#include "documents.h"
28
#include "security.h"
29
#include "pattern.h"
30
31
32
/************************************************************************
33
 *                  *
34
 *      Module interfaces       *
35
 *                  *
36
 ************************************************************************/
37
/**
38
 * xsltFixImportedCompSteps:
39
 * @master: the "master" stylesheet
40
 * @style: the stylesheet being imported by the master
41
 *
42
 * normalize the comp steps for the stylesheet being imported
43
 * by the master, together with any imports within that.
44
 *
45
 */
46
static void xsltFixImportedCompSteps(xsltStylesheetPtr master,
47
0
      xsltStylesheetPtr style) {
48
0
    xsltStylesheetPtr res;
49
0
    xmlHashScan(style->templatesHash, xsltNormalizeCompSteps, master);
50
0
    master->extrasNr += style->extrasNr;
51
0
    for (res = style->imports; res != NULL; res = res->next) {
52
0
        xsltFixImportedCompSteps(master, res);
53
0
    }
54
0
}
55
56
0
#define XSLT_MAX_NESTING 40
57
58
static int
59
0
xsltCheckCycle(xsltStylesheetPtr style, xmlNodePtr cur, const xmlChar *URI) {
60
0
    xsltStylesheetPtr ancestor;
61
0
    xsltDocumentPtr docptr;
62
0
    int depth;
63
64
    /*
65
     * Check imported stylesheets.
66
     */
67
0
    depth = 0;
68
0
    ancestor = style;
69
0
    while (ancestor != NULL) {
70
0
        if (++depth >= XSLT_MAX_NESTING) {
71
0
            xsltTransformError(NULL, style, cur,
72
0
               "maximum nesting depth exceeded: %s\n", URI);
73
0
            return(-1);
74
0
        }
75
0
  if (xmlStrEqual(ancestor->doc->URL, URI)) {
76
0
            xsltTransformError(NULL, style, cur,
77
0
               "recursion detected on imported URL %s\n", URI);
78
0
      return(-1);
79
0
        }
80
81
        /*
82
         * Check included stylesheets.
83
         */
84
0
        docptr = ancestor->includes;
85
0
        while (docptr != NULL) {
86
0
            if (++depth >= XSLT_MAX_NESTING) {
87
0
                xsltTransformError(NULL, style, cur,
88
0
                   "maximum nesting depth exceeded: %s\n", URI);
89
0
                return(-1);
90
0
            }
91
0
            if (xmlStrEqual(docptr->doc->URL, URI)) {
92
0
                xsltTransformError(NULL, style, cur,
93
0
                   "recursion detected on included URL %s\n", URI);
94
0
                return(-1);
95
0
            }
96
0
            docptr = docptr->includes;
97
0
        }
98
99
0
  ancestor = ancestor->parent;
100
0
    }
101
102
0
    return(0);
103
0
}
104
105
/**
106
 * xsltParseStylesheetImport:
107
 * @style:  the XSLT stylesheet
108
 * @cur:  the import element
109
 *
110
 * parse an XSLT stylesheet import element
111
 *
112
 * Returns 0 in case of success -1 in case of failure.
113
 */
114
115
int
116
0
xsltParseStylesheetImport(xsltStylesheetPtr style, xmlNodePtr cur) {
117
0
    int ret = -1;
118
0
    xmlDocPtr import = NULL;
119
0
    xmlChar *base = NULL;
120
0
    xmlChar *uriRef = NULL;
121
0
    xmlChar *URI = NULL;
122
0
    xsltStylesheetPtr res;
123
0
    xsltSecurityPrefsPtr sec;
124
125
0
    if ((cur == NULL) || (style == NULL))
126
0
  return (ret);
127
128
0
    uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL);
129
0
    if (uriRef == NULL) {
130
0
  xsltTransformError(NULL, style, cur,
131
0
      "xsl:import : missing href attribute\n");
132
0
  goto error;
133
0
    }
134
135
0
    base = xmlNodeGetBase(style->doc, cur);
136
0
    URI = xmlBuildURI(uriRef, base);
137
0
    if (URI == NULL) {
138
0
  xsltTransformError(NULL, style, cur,
139
0
      "xsl:import : invalid URI reference %s\n", uriRef);
140
0
  goto error;
141
0
    }
142
143
0
    if (xsltCheckCycle(style, cur, URI) < 0)
144
0
        goto error;
145
146
    /*
147
     * Security framework check
148
     */
149
0
    sec = xsltGetDefaultSecurityPrefs();
150
0
    if (sec != NULL) {
151
0
  int secres;
152
153
0
  secres = xsltCheckRead(sec, NULL, URI);
154
0
  if (secres <= 0) {
155
0
            if (secres == 0)
156
0
                xsltTransformError(NULL, NULL, NULL,
157
0
                     "xsl:import: read rights for %s denied\n",
158
0
                                 URI);
159
0
      goto error;
160
0
  }
161
0
    }
162
163
0
    import = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,
164
0
                                  (void *) style, XSLT_LOAD_STYLESHEET);
165
0
    if (import == NULL) {
166
0
  xsltTransformError(NULL, style, cur,
167
0
      "xsl:import : unable to load %s\n", URI);
168
0
  goto error;
169
0
    }
170
171
0
    res = xsltParseStylesheetImportedDoc(import, style);
172
0
    if (res != NULL) {
173
0
  res->next = style->imports;
174
0
  style->imports = res;
175
0
  if (style->parent == NULL) {
176
0
      xsltFixImportedCompSteps(style, res);
177
0
  }
178
0
  ret = 0;
179
0
    } else {
180
0
  xmlFreeDoc(import);
181
0
  }
182
183
0
error:
184
0
    if (uriRef != NULL)
185
0
  xmlFree(uriRef);
186
0
    if (base != NULL)
187
0
  xmlFree(base);
188
0
    if (URI != NULL)
189
0
  xmlFree(URI);
190
191
0
    return (ret);
192
0
}
193
194
/**
195
 * xsltParseStylesheetInclude:
196
 * @style:  the XSLT stylesheet
197
 * @cur:  the include node
198
 *
199
 * parse an XSLT stylesheet include element
200
 *
201
 * Returns 0 in case of success -1 in case of failure
202
 */
203
204
int
205
0
xsltParseStylesheetInclude(xsltStylesheetPtr style, xmlNodePtr cur) {
206
0
    int ret = -1;
207
0
    xmlDocPtr oldDoc;
208
0
    xmlChar *base = NULL;
209
0
    xmlChar *uriRef = NULL;
210
0
    xmlChar *URI = NULL;
211
0
    xsltStylesheetPtr result;
212
0
    xsltDocumentPtr include;
213
0
    int oldNopreproc;
214
215
0
    if ((cur == NULL) || (style == NULL))
216
0
  return (ret);
217
218
0
    uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL);
219
0
    if (uriRef == NULL) {
220
0
  xsltTransformError(NULL, style, cur,
221
0
      "xsl:include : missing href attribute\n");
222
0
  goto error;
223
0
    }
224
225
0
    base = xmlNodeGetBase(style->doc, cur);
226
0
    URI = xmlBuildURI(uriRef, base);
227
0
    if (URI == NULL) {
228
0
  xsltTransformError(NULL, style, cur,
229
0
      "xsl:include : invalid URI reference %s\n", uriRef);
230
0
  goto error;
231
0
    }
232
233
0
    if (xsltCheckCycle(style, cur, URI) < 0)
234
0
        goto error;
235
236
0
    include = xsltLoadStyleDocument(style, URI);
237
0
    if (include == NULL) {
238
0
  xsltTransformError(NULL, style, cur,
239
0
      "xsl:include : unable to load %s\n", URI);
240
0
  goto error;
241
0
    }
242
#ifdef XSLT_REFACTORED
243
    if (IS_XSLT_ELEM_FAST(cur) && (cur->psvi != NULL)) {
244
  ((xsltStyleItemIncludePtr) cur->psvi)->include = include;
245
    } else {
246
  xsltTransformError(NULL, style, cur,
247
      "Internal error: (xsltParseStylesheetInclude) "
248
      "The xsl:include element was not compiled.\n", URI);
249
  style->errors++;
250
    }
251
#endif
252
0
    oldDoc = style->doc;
253
0
    style->doc = include->doc;
254
    /* chain to stylesheet for recursion checking */
255
0
    include->includes = style->includes;
256
0
    style->includes = include;
257
0
    oldNopreproc = style->nopreproc;
258
0
    style->nopreproc = include->preproc;
259
    /*
260
    * TODO: This will change some values of the
261
    *  including stylesheet with every included module
262
    *  (e.g. excluded-result-prefixes)
263
    *  We need to strictly seperate such stylesheet-owned values.
264
    */
265
0
    result = xsltParseStylesheetProcess(style, include->doc);
266
0
    style->nopreproc = oldNopreproc;
267
0
    include->preproc = 1;
268
0
    style->includes = include->includes;
269
0
    style->doc = oldDoc;
270
0
    if (result == NULL) {
271
0
  ret = -1;
272
0
  goto error;
273
0
    }
274
0
    ret = 0;
275
276
0
error:
277
0
    if (uriRef != NULL)
278
0
  xmlFree(uriRef);
279
0
    if (base != NULL)
280
0
  xmlFree(base);
281
0
    if (URI != NULL)
282
0
  xmlFree(URI);
283
284
0
    return (ret);
285
0
}
286
287
/**
288
 * xsltNextImport:
289
 * @cur:  the current XSLT stylesheet
290
 *
291
 * Find the next stylesheet in import precedence.
292
 *
293
 * Returns the next stylesheet or NULL if it was the last one
294
 */
295
296
xsltStylesheetPtr
297
0
xsltNextImport(xsltStylesheetPtr cur) {
298
0
    if (cur == NULL)
299
0
  return(NULL);
300
0
    if (cur->imports != NULL)
301
0
  return(cur->imports);
302
0
    if (cur->next != NULL)
303
0
  return(cur->next) ;
304
0
    do {
305
0
  cur = cur->parent;
306
0
  if (cur == NULL) break;
307
0
  if (cur->next != NULL) return(cur->next);
308
0
    } while (cur != NULL);
309
0
    return(cur);
310
0
}
311
312
/**
313
 * xsltNeedElemSpaceHandling:
314
 * @ctxt:  an XSLT transformation context
315
 *
316
 * Checks whether that stylesheet requires white-space stripping
317
 *
318
 * Returns 1 if space should be stripped, 0 if not
319
 */
320
321
int
322
0
xsltNeedElemSpaceHandling(xsltTransformContextPtr ctxt) {
323
0
    xsltStylesheetPtr style;
324
325
0
    if (ctxt == NULL)
326
0
  return(0);
327
0
    style = ctxt->style;
328
0
    while (style != NULL) {
329
0
  if (style->stripSpaces != NULL)
330
0
      return(1);
331
0
  style = xsltNextImport(style);
332
0
    }
333
0
    return(0);
334
0
}
335
336
/**
337
 * xsltFindElemSpaceHandling:
338
 * @ctxt:  an XSLT transformation context
339
 * @node:  an XML node
340
 *
341
 * Find strip-space or preserve-space information for an element
342
 * respect the import precedence or the wildcards
343
 *
344
 * Returns 1 if space should be stripped, 0 if not, and 2 if everything
345
 *         should be CDTATA wrapped.
346
 */
347
348
int
349
0
xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt, xmlNodePtr node) {
350
0
    xsltStylesheetPtr style;
351
0
    const xmlChar *val;
352
353
0
    if ((ctxt == NULL) || (node == NULL))
354
0
  return(0);
355
0
    style = ctxt->style;
356
0
    while (style != NULL) {
357
0
  if (node->ns != NULL) {
358
0
      val = (const xmlChar *)
359
0
        xmlHashLookup2(style->stripSpaces, node->name, node->ns->href);
360
0
            if (val == NULL) {
361
0
                val = (const xmlChar *)
362
0
                    xmlHashLookup2(style->stripSpaces, BAD_CAST "*",
363
0
                                   node->ns->href);
364
0
            }
365
0
  } else {
366
0
      val = (const xmlChar *)
367
0
      xmlHashLookup2(style->stripSpaces, node->name, NULL);
368
0
  }
369
0
  if (val != NULL) {
370
0
      if (xmlStrEqual(val, (xmlChar *) "strip"))
371
0
    return(1);
372
0
      if (xmlStrEqual(val, (xmlChar *) "preserve"))
373
0
    return(0);
374
0
  }
375
0
  if (style->stripAll == 1)
376
0
      return(1);
377
0
  if (style->stripAll == -1)
378
0
      return(0);
379
380
0
  style = xsltNextImport(style);
381
0
    }
382
0
    return(0);
383
0
}
384
385
/**
386
 * xsltFindTemplate:
387
 * @ctxt:  an XSLT transformation context
388
 * @name: the template name
389
 * @nameURI: the template name URI
390
 *
391
 * Finds the named template, apply import precedence rule.
392
 * REVISIT TODO: We'll change the nameURI fields of
393
 *  templates to be in the string dict, so if the
394
 *  specified @nameURI is in the same dict, then use pointer
395
 *  comparison. Check if this can be done in a sane way.
396
 *  Maybe this function is not needed internally at
397
 *  transformation-time if we hard-wire the called templates
398
 *  to the caller.
399
 *
400
 * Returns the xsltTemplatePtr or NULL if not found
401
 */
402
xsltTemplatePtr
403
xsltFindTemplate(xsltTransformContextPtr ctxt, const xmlChar *name,
404
0
           const xmlChar *nameURI) {
405
0
    xsltTemplatePtr cur;
406
0
    xsltStylesheetPtr style;
407
408
0
    if ((ctxt == NULL) || (name == NULL))
409
0
  return(NULL);
410
0
    style = ctxt->style;
411
0
    while (style != NULL) {
412
0
        if (style->namedTemplates != NULL) {
413
0
            cur = (xsltTemplatePtr)
414
0
                xmlHashLookup2(style->namedTemplates, name, nameURI);
415
0
            if (cur != NULL)
416
0
                return(cur);
417
0
        }
418
419
0
  style = xsltNextImport(style);
420
0
    }
421
0
    return(NULL);
422
0
}
423