Coverage Report

Created: 2023-05-05 14:18

/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/tree.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
/**
57
 * xsltParseStylesheetImport:
58
 * @style:  the XSLT stylesheet
59
 * @cur:  the import element
60
 *
61
 * parse an XSLT stylesheet import element
62
 *
63
 * Returns 0 in case of success -1 in case of failure.
64
 */
65
66
int
67
0
xsltParseStylesheetImport(xsltStylesheetPtr style, xmlNodePtr cur) {
68
0
    int ret = -1;
69
0
    xmlDocPtr import = NULL;
70
0
    xmlChar *base = NULL;
71
0
    xmlChar *uriRef = NULL;
72
0
    xmlChar *URI = NULL;
73
0
    xsltStylesheetPtr res;
74
0
    xsltSecurityPrefsPtr sec;
75
76
0
    if ((cur == NULL) || (style == NULL))
77
0
  return (ret);
78
79
0
    uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL);
80
0
    if (uriRef == NULL) {
81
0
  xsltTransformError(NULL, style, cur,
82
0
      "xsl:import : missing href attribute\n");
83
0
  goto error;
84
0
    }
85
86
0
    base = xmlNodeGetBase(style->doc, cur);
87
0
    URI = xmlBuildURI(uriRef, base);
88
0
    if (URI == NULL) {
89
0
  xsltTransformError(NULL, style, cur,
90
0
      "xsl:import : invalid URI reference %s\n", uriRef);
91
0
  goto error;
92
0
    }
93
94
0
    res = style;
95
0
    while (res != NULL) {
96
0
        if (res->doc == NULL)
97
0
      break;
98
0
  if (xmlStrEqual(res->doc->URL, URI)) {
99
0
      xsltTransformError(NULL, style, cur,
100
0
         "xsl:import : recursion detected on imported URL %s\n", URI);
101
0
      goto error;
102
0
  }
103
0
  res = res->parent;
104
0
    }
105
106
    /*
107
     * Security framework check
108
     */
109
0
    sec = xsltGetDefaultSecurityPrefs();
110
0
    if (sec != NULL) {
111
0
  int secres;
112
113
0
  secres = xsltCheckRead(sec, NULL, URI);
114
0
  if (secres <= 0) {
115
0
            if (secres == 0)
116
0
                xsltTransformError(NULL, NULL, NULL,
117
0
                     "xsl:import: read rights for %s denied\n",
118
0
                                 URI);
119
0
      goto error;
120
0
  }
121
0
    }
122
123
0
    import = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,
124
0
                                  (void *) style, XSLT_LOAD_STYLESHEET);
125
0
    if (import == NULL) {
126
0
  xsltTransformError(NULL, style, cur,
127
0
      "xsl:import : unable to load %s\n", URI);
128
0
  goto error;
129
0
    }
130
131
0
    res = xsltParseStylesheetImportedDoc(import, style);
132
0
    if (res != NULL) {
133
0
  res->next = style->imports;
134
0
  style->imports = res;
135
0
  if (style->parent == NULL) {
136
0
      xsltFixImportedCompSteps(style, res);
137
0
  }
138
0
  ret = 0;
139
0
    } else {
140
0
  xmlFreeDoc(import);
141
0
  }
142
143
0
error:
144
0
    if (uriRef != NULL)
145
0
  xmlFree(uriRef);
146
0
    if (base != NULL)
147
0
  xmlFree(base);
148
0
    if (URI != NULL)
149
0
  xmlFree(URI);
150
151
0
    return (ret);
152
0
}
153
154
/**
155
 * xsltParseStylesheetInclude:
156
 * @style:  the XSLT stylesheet
157
 * @cur:  the include node
158
 *
159
 * parse an XSLT stylesheet include element
160
 *
161
 * Returns 0 in case of success -1 in case of failure
162
 */
163
164
int
165
0
xsltParseStylesheetInclude(xsltStylesheetPtr style, xmlNodePtr cur) {
166
0
    int ret = -1;
167
0
    xmlDocPtr oldDoc;
168
0
    xmlChar *base = NULL;
169
0
    xmlChar *uriRef = NULL;
170
0
    xmlChar *URI = NULL;
171
0
    xsltStylesheetPtr result;
172
0
    xsltDocumentPtr include;
173
0
    xsltDocumentPtr docptr;
174
0
    int oldNopreproc;
175
176
0
    if ((cur == NULL) || (style == NULL))
177
0
  return (ret);
178
179
0
    uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL);
180
0
    if (uriRef == NULL) {
181
0
  xsltTransformError(NULL, style, cur,
182
0
      "xsl:include : missing href attribute\n");
183
0
  goto error;
184
0
    }
185
186
0
    base = xmlNodeGetBase(style->doc, cur);
187
0
    URI = xmlBuildURI(uriRef, base);
188
0
    if (URI == NULL) {
189
0
  xsltTransformError(NULL, style, cur,
190
0
      "xsl:include : invalid URI reference %s\n", uriRef);
191
0
  goto error;
192
0
    }
193
194
    /*
195
     * in order to detect recursion, we check all previously included
196
     * stylesheets.
197
     */
198
0
    docptr = style->includes;
199
0
    while (docptr != NULL) {
200
0
        if (xmlStrEqual(docptr->doc->URL, URI)) {
201
0
      xsltTransformError(NULL, style, cur,
202
0
          "xsl:include : recursion detected on included URL %s\n", URI);
203
0
      goto error;
204
0
  }
205
0
  docptr = docptr->includes;
206
0
    }
207
208
0
    include = xsltLoadStyleDocument(style, URI);
209
0
    if (include == NULL) {
210
0
  xsltTransformError(NULL, style, cur,
211
0
      "xsl:include : unable to load %s\n", URI);
212
0
  goto error;
213
0
    }
214
#ifdef XSLT_REFACTORED
215
    if (IS_XSLT_ELEM_FAST(cur) && (cur->psvi != NULL)) {
216
  ((xsltStyleItemIncludePtr) cur->psvi)->include = include;
217
    } else {
218
  xsltTransformError(NULL, style, cur,
219
      "Internal error: (xsltParseStylesheetInclude) "
220
      "The xsl:include element was not compiled.\n", URI);
221
  style->errors++;
222
    }
223
#endif
224
0
    oldDoc = style->doc;
225
0
    style->doc = include->doc;
226
    /* chain to stylesheet for recursion checking */
227
0
    include->includes = style->includes;
228
0
    style->includes = include;
229
0
    oldNopreproc = style->nopreproc;
230
0
    style->nopreproc = include->preproc;
231
    /*
232
    * TODO: This will change some values of the
233
    *  including stylesheet with every included module
234
    *  (e.g. excluded-result-prefixes)
235
    *  We need to strictly seperate such stylesheet-owned values.
236
    */
237
0
    result = xsltParseStylesheetProcess(style, include->doc);
238
0
    style->nopreproc = oldNopreproc;
239
0
    include->preproc = 1;
240
0
    style->includes = include->includes;
241
0
    style->doc = oldDoc;
242
0
    if (result == NULL) {
243
0
  ret = -1;
244
0
  goto error;
245
0
    }
246
0
    ret = 0;
247
248
0
error:
249
0
    if (uriRef != NULL)
250
0
  xmlFree(uriRef);
251
0
    if (base != NULL)
252
0
  xmlFree(base);
253
0
    if (URI != NULL)
254
0
  xmlFree(URI);
255
256
0
    return (ret);
257
0
}
258
259
/**
260
 * xsltNextImport:
261
 * @cur:  the current XSLT stylesheet
262
 *
263
 * Find the next stylesheet in import precedence.
264
 *
265
 * Returns the next stylesheet or NULL if it was the last one
266
 */
267
268
xsltStylesheetPtr
269
58
xsltNextImport(xsltStylesheetPtr cur) {
270
58
    if (cur == NULL)
271
0
  return(NULL);
272
58
    if (cur->imports != NULL)
273
0
  return(cur->imports);
274
58
    if (cur->next != NULL)
275
0
  return(cur->next) ;
276
58
    do {
277
58
  cur = cur->parent;
278
58
  if (cur == NULL) break;
279
0
  if (cur->next != NULL) return(cur->next);
280
0
    } while (cur != NULL);
281
58
    return(cur);
282
58
}
283
284
/**
285
 * xsltNeedElemSpaceHandling:
286
 * @ctxt:  an XSLT transformation context
287
 *
288
 * Checks whether that stylesheet requires white-space stripping
289
 *
290
 * Returns 1 if space should be stripped, 0 if not
291
 */
292
293
int
294
0
xsltNeedElemSpaceHandling(xsltTransformContextPtr ctxt) {
295
0
    xsltStylesheetPtr style;
296
297
0
    if (ctxt == NULL)
298
0
  return(0);
299
0
    style = ctxt->style;
300
0
    while (style != NULL) {
301
0
  if (style->stripSpaces != NULL)
302
0
      return(1);
303
0
  style = xsltNextImport(style);
304
0
    }
305
0
    return(0);
306
0
}
307
308
/**
309
 * xsltFindElemSpaceHandling:
310
 * @ctxt:  an XSLT transformation context
311
 * @node:  an XML node
312
 *
313
 * Find strip-space or preserve-space information for an element
314
 * respect the import precedence or the wildcards
315
 *
316
 * Returns 1 if space should be stripped, 0 if not, and 2 if everything
317
 *         should be CDTATA wrapped.
318
 */
319
320
int
321
0
xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt, xmlNodePtr node) {
322
0
    xsltStylesheetPtr style;
323
0
    const xmlChar *val;
324
325
0
    if ((ctxt == NULL) || (node == NULL))
326
0
  return(0);
327
0
    style = ctxt->style;
328
0
    while (style != NULL) {
329
0
  if (node->ns != NULL) {
330
0
      val = (const xmlChar *)
331
0
        xmlHashLookup2(style->stripSpaces, node->name, node->ns->href);
332
0
            if (val == NULL) {
333
0
                val = (const xmlChar *)
334
0
                    xmlHashLookup2(style->stripSpaces, BAD_CAST "*",
335
0
                                   node->ns->href);
336
0
            }
337
0
  } else {
338
0
      val = (const xmlChar *)
339
0
      xmlHashLookup2(style->stripSpaces, node->name, NULL);
340
0
  }
341
0
  if (val != NULL) {
342
0
      if (xmlStrEqual(val, (xmlChar *) "strip"))
343
0
    return(1);
344
0
      if (xmlStrEqual(val, (xmlChar *) "preserve"))
345
0
    return(0);
346
0
  }
347
0
  if (style->stripAll == 1)
348
0
      return(1);
349
0
  if (style->stripAll == -1)
350
0
      return(0);
351
352
0
  style = xsltNextImport(style);
353
0
    }
354
0
    return(0);
355
0
}
356
357
/**
358
 * xsltFindTemplate:
359
 * @ctxt:  an XSLT transformation context
360
 * @name: the template name
361
 * @nameURI: the template name URI
362
 *
363
 * Finds the named template, apply import precedence rule.
364
 * REVISIT TODO: We'll change the nameURI fields of
365
 *  templates to be in the string dict, so if the
366
 *  specified @nameURI is in the same dict, then use pointer
367
 *  comparison. Check if this can be done in a sane way.
368
 *  Maybe this function is not needed internally at
369
 *  transformation-time if we hard-wire the called templates
370
 *  to the caller.
371
 *
372
 * Returns the xsltTemplatePtr or NULL if not found
373
 */
374
xsltTemplatePtr
375
xsltFindTemplate(xsltTransformContextPtr ctxt, const xmlChar *name,
376
0
           const xmlChar *nameURI) {
377
0
    xsltTemplatePtr cur;
378
0
    xsltStylesheetPtr style;
379
380
0
    if ((ctxt == NULL) || (name == NULL))
381
0
  return(NULL);
382
0
    style = ctxt->style;
383
0
    while (style != NULL) {
384
0
        if (style->namedTemplates != NULL) {
385
0
            cur = (xsltTemplatePtr)
386
0
                xmlHashLookup2(style->namedTemplates, name, nameURI);
387
0
            if (cur != NULL)
388
0
                return(cur);
389
0
        }
390
391
0
  style = xsltNextImport(style);
392
0
    }
393
0
    return(NULL);
394
0
}
395