Coverage Report

Created: 2025-10-10 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libxslt/libxslt/documents.c
Line
Count
Source
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
91
0
#if LIBXML_VERSION >= 21300
92
0
    doc = xmlCtxtParseDocument(pctxt, inputStream);
93
#else
94
    inputPush(pctxt, inputStream);
95
96
    xmlParseDocument(pctxt);
97
98
    if (pctxt->wellFormed) {
99
        doc = pctxt->myDoc;
100
    }
101
    else {
102
        doc = NULL;
103
        xmlFreeDoc(pctxt->myDoc);
104
        pctxt->myDoc = NULL;
105
    }
106
#endif
107
108
0
    xmlFreeParserCtxt(pctxt);
109
110
0
    return(doc);
111
0
}
112
113
114
xsltDocLoaderFunc xsltDocDefaultLoader = xsltDocDefaultLoaderFunc;
115
116
/**
117
 * xsltSetLoaderFunc:
118
 * @f: the new function to handle document loading.
119
 *
120
 * Set the new function to load document, if NULL it resets it to the
121
 * default function.
122
 */
123
124
void
125
0
xsltSetLoaderFunc(xsltDocLoaderFunc f) {
126
0
    if (f == NULL)
127
0
        xsltDocDefaultLoader = xsltDocDefaultLoaderFunc;
128
0
    else
129
0
        xsltDocDefaultLoader = f;
130
0
}
131
132
/************************************************************************
133
 *                  *
134
 *      Module interfaces       *
135
 *                  *
136
 ************************************************************************/
137
138
/**
139
 * xsltNewDocument:
140
 * @ctxt: an XSLT transformation context (or NULL)
141
 * @doc:  a parsed XML document
142
 *
143
 * Register a new document, apply key computations
144
 *
145
 * Returns a handler to the document
146
 */
147
xsltDocumentPtr
148
0
xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) {
149
0
    xsltDocumentPtr cur;
150
151
0
    cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
152
0
    if (cur == NULL) {
153
0
  xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
154
0
    "xsltNewDocument : malloc failed\n");
155
0
  return(NULL);
156
0
    }
157
0
    memset(cur, 0, sizeof(xsltDocument));
158
0
    cur->doc = doc;
159
0
    if (ctxt != NULL) {
160
0
        if (! XSLT_IS_RES_TREE_FRAG(doc)) {
161
0
      cur->next = ctxt->docList;
162
0
      ctxt->docList = cur;
163
0
  }
164
  /*
165
  * A key with a specific name for a specific document
166
  * will only be computed if there's a call to the key()
167
  * function using that specific name for that specific
168
  * document. I.e. computation of keys will be done in
169
  * xsltGetKey() (keys.c) on an on-demand basis.
170
  *
171
  * xsltInitCtxtKeys(ctxt, cur); not called here anymore
172
  */
173
0
    }
174
0
    return(cur);
175
0
}
176
177
/**
178
 * xsltNewStyleDocument:
179
 * @style: an XSLT style sheet
180
 * @doc:  a parsed XML document
181
 *
182
 * Register a new document, apply key computations
183
 *
184
 * Returns a handler to the document
185
 */
186
xsltDocumentPtr
187
0
xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) {
188
0
    xsltDocumentPtr cur;
189
190
0
    cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
191
0
    if (cur == NULL) {
192
0
  xsltTransformError(NULL, style, (xmlNodePtr) doc,
193
0
    "xsltNewStyleDocument : malloc failed\n");
194
0
  return(NULL);
195
0
    }
196
0
    memset(cur, 0, sizeof(xsltDocument));
197
0
    cur->doc = doc;
198
0
    if (style != NULL) {
199
0
  cur->next = style->docList;
200
0
  style->docList = cur;
201
0
    }
202
0
    return(cur);
203
0
}
204
205
/**
206
 * xsltFreeStyleDocuments:
207
 * @style: an XSLT stylesheet (representing a stylesheet-level)
208
 *
209
 * Frees the node-trees (and xsltDocument structures) of all
210
 * stylesheet-modules of the stylesheet-level represented by
211
 * the given @style.
212
 */
213
void
214
0
xsltFreeStyleDocuments(xsltStylesheetPtr style) {
215
0
    xsltDocumentPtr doc, cur;
216
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
217
    xsltNsMapPtr nsMap;
218
#endif
219
220
0
    if (style == NULL)
221
0
  return;
222
223
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
224
    if (XSLT_HAS_INTERNAL_NSMAP(style))
225
  nsMap = XSLT_GET_INTERNAL_NSMAP(style);
226
    else
227
  nsMap = NULL;
228
#endif
229
230
0
    cur = style->docList;
231
0
    while (cur != NULL) {
232
0
  doc = cur;
233
0
  cur = cur->next;
234
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
235
  /*
236
  * Restore all changed namespace URIs of ns-decls.
237
  */
238
  if (nsMap)
239
      xsltRestoreDocumentNamespaces(nsMap, doc->doc);
240
#endif
241
0
  xsltFreeDocumentKeys(doc);
242
0
  if (!doc->main)
243
0
      xmlFreeDoc(doc->doc);
244
0
        xmlFree(doc);
245
0
    }
246
0
}
247
248
/**
249
 * xsltFreeDocuments:
250
 * @ctxt: an XSLT transformation context
251
 *
252
 * Free up all the space used by the loaded documents
253
 */
254
void
255
0
xsltFreeDocuments(xsltTransformContextPtr ctxt) {
256
0
    xsltDocumentPtr doc, cur;
257
258
0
    cur = ctxt->docList;
259
0
    while (cur != NULL) {
260
0
  doc = cur;
261
0
  cur = cur->next;
262
0
  xsltFreeDocumentKeys(doc);
263
0
  if (!doc->main)
264
0
      xmlFreeDoc(doc->doc);
265
0
        xmlFree(doc);
266
0
    }
267
0
    cur = ctxt->styleList;
268
0
    while (cur != NULL) {
269
0
  doc = cur;
270
0
  cur = cur->next;
271
0
  xsltFreeDocumentKeys(doc);
272
0
  if (!doc->main)
273
0
      xmlFreeDoc(doc->doc);
274
0
        xmlFree(doc);
275
0
    }
276
0
}
277
278
/**
279
 * xsltLoadDocument:
280
 * @ctxt: an XSLT transformation context
281
 * @URI:  the computed URI of the document
282
 *
283
 * Try to load a document (not a stylesheet)
284
 * within the XSLT transformation context
285
 *
286
 * Returns the new xsltDocumentPtr or NULL in case of error
287
 */
288
xsltDocumentPtr
289
0
xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {
290
0
    xsltDocumentPtr ret;
291
0
    xmlDocPtr doc;
292
293
0
    if ((ctxt == NULL) || (URI == NULL))
294
0
  return(NULL);
295
296
    /*
297
     * Security framework check
298
     */
299
0
    if (ctxt->sec != NULL) {
300
0
  int res;
301
302
0
  res = xsltCheckRead(ctxt->sec, ctxt, URI);
303
0
  if (res <= 0) {
304
0
            if (res == 0)
305
0
                xsltTransformError(ctxt, NULL, NULL,
306
0
                     "xsltLoadDocument: read rights for %s denied\n",
307
0
                                 URI);
308
0
      return(NULL);
309
0
  }
310
0
    }
311
312
    /*
313
     * Walk the context list to find the document if preparsed
314
     */
315
0
    ret = ctxt->docList;
316
0
    while (ret != NULL) {
317
0
  if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
318
0
      (xmlStrEqual(ret->doc->URL, URI)))
319
0
      return(ret);
320
0
  ret = ret->next;
321
0
    }
322
323
0
    doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions,
324
0
                               (void *) ctxt, XSLT_LOAD_DOCUMENT);
325
326
0
    if (doc == NULL)
327
0
  return(NULL);
328
329
0
    if (ctxt->xinclude != 0) {
330
0
#ifdef LIBXML_XINCLUDE_ENABLED
331
0
#if LIBXML_VERSION >= 20603
332
0
  xmlXIncludeProcessFlags(doc, ctxt->parserOptions);
333
#else
334
  xmlXIncludeProcess(doc);
335
#endif
336
#else
337
  xsltTransformError(ctxt, NULL, NULL,
338
      "xsltLoadDocument(%s) : XInclude processing not compiled in\n",
339
                   URI);
340
#endif
341
0
    }
342
    /*
343
     * Apply white-space stripping if asked for
344
     */
345
0
    if (xsltNeedElemSpaceHandling(ctxt))
346
0
  xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
347
0
    if (ctxt->debugStatus == XSLT_DEBUG_NONE)
348
0
  xmlXPathOrderDocElems(doc);
349
350
0
    ret = xsltNewDocument(ctxt, doc);
351
0
    return(ret);
352
0
}
353
354
/**
355
 * xsltLoadStyleDocument:
356
 * @style: an XSLT style sheet
357
 * @URI:  the computed URI of the document
358
 *
359
 * Try to load a stylesheet document within the XSLT transformation context
360
 *
361
 * Returns the new xsltDocumentPtr or NULL in case of error
362
 */
363
xsltDocumentPtr
364
0
xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) {
365
0
    xsltDocumentPtr ret;
366
0
    xmlDocPtr doc;
367
0
    xsltSecurityPrefsPtr sec;
368
369
0
    if ((style == NULL) || (URI == NULL))
370
0
  return(NULL);
371
372
    /*
373
     * Security framework check
374
     */
375
0
    sec = xsltGetDefaultSecurityPrefs();
376
0
    if (sec != NULL) {
377
0
  int res;
378
379
0
  res = xsltCheckRead(sec, NULL, URI);
380
0
  if (res <= 0) {
381
0
            if (res == 0)
382
0
                xsltTransformError(NULL, NULL, NULL,
383
0
                     "xsltLoadStyleDocument: read rights for %s denied\n",
384
0
                                 URI);
385
0
      return(NULL);
386
0
  }
387
0
    }
388
389
    /*
390
     * Walk the context list to find the document if preparsed
391
     */
392
0
    ret = style->docList;
393
0
    while (ret != NULL) {
394
0
  if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
395
0
      (xmlStrEqual(ret->doc->URL, URI)))
396
0
      return(ret);
397
0
  ret = ret->next;
398
0
    }
399
400
0
    doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,
401
0
                               (void *) style, XSLT_LOAD_STYLESHEET);
402
0
    if (doc == NULL)
403
0
  return(NULL);
404
405
0
    ret = xsltNewStyleDocument(style, doc);
406
0
    if (ret == NULL)
407
0
        xmlFreeDoc(doc);
408
0
    return(ret);
409
0
}
410
411
/**
412
 * xsltFindDocument:
413
 * @ctxt: an XSLT transformation context
414
 * @doc: a parsed XML document
415
 *
416
 * Try to find a document within the XSLT transformation context.
417
 * This will not find document infos for temporary
418
 * Result Tree Fragments.
419
 *
420
 * Returns the desired xsltDocumentPtr or NULL in case of error
421
 */
422
xsltDocumentPtr
423
0
xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) {
424
0
    xsltDocumentPtr ret;
425
426
0
    if ((ctxt == NULL) || (doc == NULL))
427
0
  return(NULL);
428
429
    /*
430
     * Walk the context list to find the document
431
     */
432
0
    ret = ctxt->docList;
433
0
    while (ret != NULL) {
434
0
  if (ret->doc == doc)
435
0
      return(ret);
436
0
  ret = ret->next;
437
0
    }
438
0
    if (doc == ctxt->style->doc)
439
0
  return(ctxt->document);
440
0
    return(NULL);
441
0
}
442