Coverage Report

Created: 2024-01-20 12:32

/src/libxslt/libxslt/documents.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * documents.c: Implementation of the documents handling
3
 *
4
 * See Copyright for the status of this software.
5
 *
6
 * daniel@veillard.com
7
 */
8
9
#define IN_LIBXSLT
10
#include "libxslt.h"
11
12
#include <string.h>
13
14
#include <libxml/xmlmemory.h>
15
#include <libxml/tree.h>
16
#include <libxml/hash.h>
17
#include <libxml/parser.h>
18
#include <libxml/parserInternals.h>
19
#include "xslt.h"
20
#include "xsltInternals.h"
21
#include "xsltutils.h"
22
#include "documents.h"
23
#include "transform.h"
24
#include "imports.h"
25
#include "keys.h"
26
#include "security.h"
27
28
#ifdef LIBXML_XINCLUDE_ENABLED
29
#include <libxml/xinclude.h>
30
#endif
31
32
#define WITH_XSLT_DEBUG_DOCUMENTS
33
34
#ifdef WITH_XSLT_DEBUG
35
#define WITH_XSLT_DEBUG_DOCUMENTS
36
#endif
37
38
/************************************************************************
39
 *                  *
40
 *    Hooks for the document loader       *
41
 *                  *
42
 ************************************************************************/
43
44
/**
45
 * xsltDocDefaultLoaderFunc:
46
 * @URI: the URI of the document to load
47
 * @dict: the dictionary to use when parsing that document
48
 * @options: parsing options, a set of xmlParserOption
49
 * @ctxt: the context, either a stylesheet or a transformation context
50
 * @type: the xsltLoadType indicating the kind of loading required
51
 *
52
 * Default function to load document not provided by the compilation or
53
 * transformation API themselve, for example when an xsl:import,
54
 * xsl:include is found at compilation time or when a document()
55
 * call is made at runtime.
56
 *
57
 * Returns the pointer to the document (which will be modified and
58
 * freed by the engine later), or NULL in case of error.
59
 */
60
static xmlDocPtr
61
xsltDocDefaultLoaderFunc(const xmlChar * URI, xmlDictPtr dict, int options,
62
                         void *ctxt ATTRIBUTE_UNUSED,
63
       xsltLoadType type ATTRIBUTE_UNUSED)
64
0
{
65
0
    xmlParserCtxtPtr pctxt;
66
0
    xmlParserInputPtr inputStream;
67
0
    xmlDocPtr doc;
68
69
0
    pctxt = xmlNewParserCtxt();
70
0
    if (pctxt == NULL)
71
0
        return(NULL);
72
0
    if ((dict != NULL) && (pctxt->dict != NULL)) {
73
0
        xmlDictFree(pctxt->dict);
74
0
  pctxt->dict = NULL;
75
0
    }
76
0
    if (dict != NULL) {
77
0
  pctxt->dict = dict;
78
0
  xmlDictReference(pctxt->dict);
79
#ifdef WITH_XSLT_DEBUG
80
  xsltGenericDebug(xsltGenericDebugContext,
81
                     "Reusing dictionary for document\n");
82
#endif
83
0
    }
84
0
    xmlCtxtUseOptions(pctxt, options);
85
0
    inputStream = xmlLoadExternalEntity((const char *) URI, NULL, pctxt);
86
0
    if (inputStream == NULL) {
87
0
        xmlFreeParserCtxt(pctxt);
88
0
  return(NULL);
89
0
    }
90
0
    inputPush(pctxt, inputStream);
91
0
    if (pctxt->directory == NULL)
92
0
        pctxt->directory = xmlParserGetDirectory((const char *) URI);
93
94
0
    xmlParseDocument(pctxt);
95
96
0
    if (pctxt->wellFormed) {
97
0
        doc = pctxt->myDoc;
98
0
    }
99
0
    else {
100
0
        doc = NULL;
101
0
        xmlFreeDoc(pctxt->myDoc);
102
0
        pctxt->myDoc = NULL;
103
0
    }
104
0
    xmlFreeParserCtxt(pctxt);
105
106
0
    return(doc);
107
0
}
108
109
110
xsltDocLoaderFunc xsltDocDefaultLoader = xsltDocDefaultLoaderFunc;
111
112
/**
113
 * xsltSetLoaderFunc:
114
 * @f: the new function to handle document loading.
115
 *
116
 * Set the new function to load document, if NULL it resets it to the
117
 * default function.
118
 */
119
120
void
121
0
xsltSetLoaderFunc(xsltDocLoaderFunc f) {
122
0
    if (f == NULL)
123
0
        xsltDocDefaultLoader = xsltDocDefaultLoaderFunc;
124
0
    else
125
0
        xsltDocDefaultLoader = f;
126
0
}
127
128
/************************************************************************
129
 *                  *
130
 *      Module interfaces       *
131
 *                  *
132
 ************************************************************************/
133
134
/**
135
 * xsltNewDocument:
136
 * @ctxt: an XSLT transformation context (or NULL)
137
 * @doc:  a parsed XML document
138
 *
139
 * Register a new document, apply key computations
140
 *
141
 * Returns a handler to the document
142
 */
143
xsltDocumentPtr
144
3.14k
xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) {
145
3.14k
    xsltDocumentPtr cur;
146
147
3.14k
    cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
148
3.14k
    if (cur == NULL) {
149
0
  xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
150
0
    "xsltNewDocument : malloc failed\n");
151
0
  return(NULL);
152
0
    }
153
3.14k
    memset(cur, 0, sizeof(xsltDocument));
154
3.14k
    cur->doc = doc;
155
3.14k
    if (ctxt != NULL) {
156
3.14k
        if (! XSLT_IS_RES_TREE_FRAG(doc)) {
157
3.14k
      cur->next = ctxt->docList;
158
3.14k
      ctxt->docList = cur;
159
3.14k
  }
160
  /*
161
  * A key with a specific name for a specific document
162
  * will only be computed if there's a call to the key()
163
  * function using that specific name for that specific
164
  * document. I.e. computation of keys will be done in
165
  * xsltGetKey() (keys.c) on an on-demand basis.
166
  *
167
  * xsltInitCtxtKeys(ctxt, cur); not called here anymore
168
  */
169
3.14k
    }
170
3.14k
    return(cur);
171
3.14k
}
172
173
/**
174
 * xsltNewStyleDocument:
175
 * @style: an XSLT style sheet
176
 * @doc:  a parsed XML document
177
 *
178
 * Register a new document, apply key computations
179
 *
180
 * Returns a handler to the document
181
 */
182
xsltDocumentPtr
183
0
xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) {
184
0
    xsltDocumentPtr cur;
185
186
0
    cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
187
0
    if (cur == NULL) {
188
0
  xsltTransformError(NULL, style, (xmlNodePtr) doc,
189
0
    "xsltNewStyleDocument : malloc failed\n");
190
0
  return(NULL);
191
0
    }
192
0
    memset(cur, 0, sizeof(xsltDocument));
193
0
    cur->doc = doc;
194
0
    if (style != NULL) {
195
0
  cur->next = style->docList;
196
0
  style->docList = cur;
197
0
    }
198
0
    return(cur);
199
0
}
200
201
/**
202
 * xsltFreeStyleDocuments:
203
 * @style: an XSLT stylesheet (representing a stylesheet-level)
204
 *
205
 * Frees the node-trees (and xsltDocument structures) of all
206
 * stylesheet-modules of the stylesheet-level represented by
207
 * the given @style.
208
 */
209
void
210
0
xsltFreeStyleDocuments(xsltStylesheetPtr style) {
211
0
    xsltDocumentPtr doc, cur;
212
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
213
    xsltNsMapPtr nsMap;
214
#endif
215
216
0
    if (style == NULL)
217
0
  return;
218
219
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
220
    if (XSLT_HAS_INTERNAL_NSMAP(style))
221
  nsMap = XSLT_GET_INTERNAL_NSMAP(style);
222
    else
223
  nsMap = NULL;
224
#endif
225
226
0
    cur = style->docList;
227
0
    while (cur != NULL) {
228
0
  doc = cur;
229
0
  cur = cur->next;
230
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
231
  /*
232
  * Restore all changed namespace URIs of ns-decls.
233
  */
234
  if (nsMap)
235
      xsltRestoreDocumentNamespaces(nsMap, doc->doc);
236
#endif
237
0
  xsltFreeDocumentKeys(doc);
238
0
  if (!doc->main)
239
0
      xmlFreeDoc(doc->doc);
240
0
        xmlFree(doc);
241
0
    }
242
0
}
243
244
/**
245
 * xsltFreeDocuments:
246
 * @ctxt: an XSLT transformation context
247
 *
248
 * Free up all the space used by the loaded documents
249
 */
250
void
251
0
xsltFreeDocuments(xsltTransformContextPtr ctxt) {
252
0
    xsltDocumentPtr doc, cur;
253
254
0
    cur = ctxt->docList;
255
0
    while (cur != NULL) {
256
0
  doc = cur;
257
0
  cur = cur->next;
258
0
  xsltFreeDocumentKeys(doc);
259
0
  if (!doc->main)
260
0
      xmlFreeDoc(doc->doc);
261
0
        xmlFree(doc);
262
0
    }
263
0
    cur = ctxt->styleList;
264
0
    while (cur != NULL) {
265
0
  doc = cur;
266
0
  cur = cur->next;
267
0
  xsltFreeDocumentKeys(doc);
268
0
  if (!doc->main)
269
0
      xmlFreeDoc(doc->doc);
270
0
        xmlFree(doc);
271
0
    }
272
0
}
273
274
/**
275
 * xsltLoadDocument:
276
 * @ctxt: an XSLT transformation context
277
 * @URI:  the computed URI of the document
278
 *
279
 * Try to load a document (not a stylesheet)
280
 * within the XSLT transformation context
281
 *
282
 * Returns the new xsltDocumentPtr or NULL in case of error
283
 */
284
xsltDocumentPtr
285
1.21M
xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {
286
1.21M
    xsltDocumentPtr ret;
287
1.21M
    xmlDocPtr doc;
288
289
1.21M
    if ((ctxt == NULL) || (URI == NULL))
290
0
  return(NULL);
291
292
    /*
293
     * Security framework check
294
     */
295
1.21M
    if (ctxt->sec != NULL) {
296
1.21M
  int res;
297
298
1.21M
  res = xsltCheckRead(ctxt->sec, ctxt, URI);
299
1.21M
  if (res <= 0) {
300
1.21M
            if (res == 0)
301
1.21M
                xsltTransformError(ctxt, NULL, NULL,
302
1.21M
                     "xsltLoadDocument: read rights for %s denied\n",
303
1.21M
                                 URI);
304
1.21M
      return(NULL);
305
1.21M
  }
306
1.21M
    }
307
308
    /*
309
     * Walk the context list to find the document if preparsed
310
     */
311
0
    ret = ctxt->docList;
312
0
    while (ret != NULL) {
313
0
  if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
314
0
      (xmlStrEqual(ret->doc->URL, URI)))
315
0
      return(ret);
316
0
  ret = ret->next;
317
0
    }
318
319
0
    doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions,
320
0
                               (void *) ctxt, XSLT_LOAD_DOCUMENT);
321
322
0
    if (doc == NULL)
323
0
  return(NULL);
324
325
0
    if (ctxt->xinclude != 0) {
326
0
#ifdef LIBXML_XINCLUDE_ENABLED
327
0
#if LIBXML_VERSION >= 20603
328
0
  xmlXIncludeProcessFlags(doc, ctxt->parserOptions);
329
#else
330
  xmlXIncludeProcess(doc);
331
#endif
332
#else
333
  xsltTransformError(ctxt, NULL, NULL,
334
      "xsltLoadDocument(%s) : XInclude processing not compiled in\n",
335
                   URI);
336
#endif
337
0
    }
338
    /*
339
     * Apply white-space stripping if asked for
340
     */
341
0
    if (xsltNeedElemSpaceHandling(ctxt))
342
0
  xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
343
0
    if (ctxt->debugStatus == XSLT_DEBUG_NONE)
344
0
  xmlXPathOrderDocElems(doc);
345
346
0
    ret = xsltNewDocument(ctxt, doc);
347
0
    return(ret);
348
0
}
349
350
/**
351
 * xsltLoadStyleDocument:
352
 * @style: an XSLT style sheet
353
 * @URI:  the computed URI of the document
354
 *
355
 * Try to load a stylesheet document within the XSLT transformation context
356
 *
357
 * Returns the new xsltDocumentPtr or NULL in case of error
358
 */
359
xsltDocumentPtr
360
0
xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) {
361
0
    xsltDocumentPtr ret;
362
0
    xmlDocPtr doc;
363
0
    xsltSecurityPrefsPtr sec;
364
365
0
    if ((style == NULL) || (URI == NULL))
366
0
  return(NULL);
367
368
    /*
369
     * Security framework check
370
     */
371
0
    sec = xsltGetDefaultSecurityPrefs();
372
0
    if (sec != NULL) {
373
0
  int res;
374
375
0
  res = xsltCheckRead(sec, NULL, URI);
376
0
  if (res <= 0) {
377
0
            if (res == 0)
378
0
                xsltTransformError(NULL, NULL, NULL,
379
0
                     "xsltLoadStyleDocument: read rights for %s denied\n",
380
0
                                 URI);
381
0
      return(NULL);
382
0
  }
383
0
    }
384
385
    /*
386
     * Walk the context list to find the document if preparsed
387
     */
388
0
    ret = style->docList;
389
0
    while (ret != NULL) {
390
0
  if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
391
0
      (xmlStrEqual(ret->doc->URL, URI)))
392
0
      return(ret);
393
0
  ret = ret->next;
394
0
    }
395
396
0
    doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,
397
0
                               (void *) style, XSLT_LOAD_STYLESHEET);
398
0
    if (doc == NULL)
399
0
  return(NULL);
400
401
0
    ret = xsltNewStyleDocument(style, doc);
402
0
    return(ret);
403
0
}
404
405
/**
406
 * xsltFindDocument:
407
 * @ctxt: an XSLT transformation context
408
 * @doc: a parsed XML document
409
 *
410
 * Try to find a document within the XSLT transformation context.
411
 * This will not find document infos for temporary
412
 * Result Tree Fragments.
413
 *
414
 * Returns the desired xsltDocumentPtr or NULL in case of error
415
 */
416
xsltDocumentPtr
417
0
xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) {
418
0
    xsltDocumentPtr ret;
419
420
0
    if ((ctxt == NULL) || (doc == NULL))
421
0
  return(NULL);
422
423
    /*
424
     * Walk the context list to find the document
425
     */
426
0
    ret = ctxt->docList;
427
0
    while (ret != NULL) {
428
0
  if (ret->doc == doc)
429
0
      return(ret);
430
0
  ret = ret->next;
431
0
    }
432
0
    if (doc == ctxt->style->doc)
433
0
  return(ctxt->document);
434
0
    return(NULL);
435
0
}
436