Coverage Report

Created: 2023-03-26 06:14

/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
302k
{
65
302k
    xmlParserCtxtPtr pctxt;
66
302k
    xmlParserInputPtr inputStream;
67
302k
    xmlDocPtr doc;
68
69
302k
    pctxt = xmlNewParserCtxt();
70
302k
    if (pctxt == NULL)
71
148
        return(NULL);
72
302k
    if ((dict != NULL) && (pctxt->dict != NULL)) {
73
302k
        xmlDictFree(pctxt->dict);
74
302k
  pctxt->dict = NULL;
75
302k
    }
76
302k
    if (dict != NULL) {
77
302k
  pctxt->dict = dict;
78
302k
  xmlDictReference(pctxt->dict);
79
#ifdef WITH_XSLT_DEBUG
80
  xsltGenericDebug(xsltGenericDebugContext,
81
                     "Reusing dictionary for document\n");
82
#endif
83
302k
    }
84
302k
    xmlCtxtUseOptions(pctxt, options);
85
302k
    inputStream = xmlLoadExternalEntity((const char *) URI, NULL, pctxt);
86
302k
    if (inputStream == NULL) {
87
168k
        xmlFreeParserCtxt(pctxt);
88
168k
  return(NULL);
89
168k
    }
90
133k
    inputPush(pctxt, inputStream);
91
133k
    if (pctxt->directory == NULL)
92
133k
        pctxt->directory = xmlParserGetDirectory((const char *) URI);
93
94
133k
    xmlParseDocument(pctxt);
95
96
133k
    if (pctxt->wellFormed) {
97
38.1k
        doc = pctxt->myDoc;
98
38.1k
    }
99
95.1k
    else {
100
95.1k
        doc = NULL;
101
95.1k
        xmlFreeDoc(pctxt->myDoc);
102
95.1k
        pctxt->myDoc = NULL;
103
95.1k
    }
104
133k
    xmlFreeParserCtxt(pctxt);
105
106
133k
    return(doc);
107
302k
}
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
17.4k
xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) {
145
17.4k
    xsltDocumentPtr cur;
146
147
17.4k
    cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
148
17.4k
    if (cur == NULL) {
149
62
  xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
150
62
    "xsltNewDocument : malloc failed\n");
151
62
  return(NULL);
152
62
    }
153
17.3k
    memset(cur, 0, sizeof(xsltDocument));
154
17.3k
    cur->doc = doc;
155
17.3k
    if (ctxt != NULL) {
156
17.3k
        if (! XSLT_IS_RES_TREE_FRAG(doc)) {
157
12.2k
      cur->next = ctxt->docList;
158
12.2k
      ctxt->docList = cur;
159
12.2k
  }
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
17.3k
    }
170
17.3k
    return(cur);
171
17.4k
}
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
2.61k
xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) {
184
2.61k
    xsltDocumentPtr cur;
185
186
2.61k
    cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
187
2.61k
    if (cur == NULL) {
188
17
  xsltTransformError(NULL, style, (xmlNodePtr) doc,
189
17
    "xsltNewStyleDocument : malloc failed\n");
190
17
  return(NULL);
191
17
    }
192
2.60k
    memset(cur, 0, sizeof(xsltDocument));
193
2.60k
    cur->doc = doc;
194
2.60k
    if (style != NULL) {
195
2.60k
  cur->next = style->docList;
196
2.60k
  style->docList = cur;
197
2.60k
    }
198
2.60k
    return(cur);
199
2.61k
}
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
56.3k
xsltFreeStyleDocuments(xsltStylesheetPtr style) {
211
56.3k
    xsltDocumentPtr doc, cur;
212
#ifdef XSLT_REFACTORED_XSLT_NSCOMP
213
    xsltNsMapPtr nsMap;
214
#endif
215
216
56.3k
    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
56.3k
    cur = style->docList;
227
58.9k
    while (cur != NULL) {
228
2.60k
  doc = cur;
229
2.60k
  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
2.60k
  xsltFreeDocumentKeys(doc);
238
2.60k
  if (!doc->main)
239
2.60k
      xmlFreeDoc(doc->doc);
240
2.60k
        xmlFree(doc);
241
2.60k
    }
242
56.3k
}
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
12.3k
xsltFreeDocuments(xsltTransformContextPtr ctxt) {
252
12.3k
    xsltDocumentPtr doc, cur;
253
254
12.3k
    cur = ctxt->docList;
255
24.6k
    while (cur != NULL) {
256
12.2k
  doc = cur;
257
12.2k
  cur = cur->next;
258
12.2k
  xsltFreeDocumentKeys(doc);
259
12.2k
  if (!doc->main)
260
0
      xmlFreeDoc(doc->doc);
261
12.2k
        xmlFree(doc);
262
12.2k
    }
263
12.3k
    cur = ctxt->styleList;
264
12.3k
    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
12.3k
}
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
15.7k
xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {
286
15.7k
    xsltDocumentPtr ret;
287
15.7k
    xmlDocPtr doc;
288
289
15.7k
    if ((ctxt == NULL) || (URI == NULL))
290
0
  return(NULL);
291
292
    /*
293
     * Security framework check
294
     */
295
15.7k
    if (ctxt->sec != NULL) {
296
15.7k
  int res;
297
298
15.7k
  res = xsltCheckRead(ctxt->sec, ctxt, URI);
299
15.7k
  if (res <= 0) {
300
15.7k
            if (res == 0)
301
15.7k
                xsltTransformError(ctxt, NULL, NULL,
302
15.7k
                     "xsltLoadDocument: read rights for %s denied\n",
303
15.7k
                                 URI);
304
15.7k
      return(NULL);
305
15.7k
  }
306
15.7k
    }
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
198k
xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) {
361
198k
    xsltDocumentPtr ret;
362
198k
    xmlDocPtr doc;
363
198k
    xsltSecurityPrefsPtr sec;
364
365
198k
    if ((style == NULL) || (URI == NULL))
366
0
  return(NULL);
367
368
    /*
369
     * Security framework check
370
     */
371
198k
    sec = xsltGetDefaultSecurityPrefs();
372
198k
    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
198k
    ret = style->docList;
389
227k
    while (ret != NULL) {
390
44.9k
  if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
391
44.9k
      (xmlStrEqual(ret->doc->URL, URI)))
392
16.1k
      return(ret);
393
28.7k
  ret = ret->next;
394
28.7k
    }
395
396
182k
    doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,
397
182k
                               (void *) style, XSLT_LOAD_STYLESHEET);
398
182k
    if (doc == NULL)
399
179k
  return(NULL);
400
401
2.61k
    ret = xsltNewStyleDocument(style, doc);
402
2.61k
    if (ret == NULL)
403
17
        xmlFreeDoc(doc);
404
2.61k
    return(ret);
405
182k
}
406
407
/**
408
 * xsltFindDocument:
409
 * @ctxt: an XSLT transformation context
410
 * @doc: a parsed XML document
411
 *
412
 * Try to find a document within the XSLT transformation context.
413
 * This will not find document infos for temporary
414
 * Result Tree Fragments.
415
 *
416
 * Returns the desired xsltDocumentPtr or NULL in case of error
417
 */
418
xsltDocumentPtr
419
0
xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) {
420
0
    xsltDocumentPtr ret;
421
422
0
    if ((ctxt == NULL) || (doc == NULL))
423
0
  return(NULL);
424
425
    /*
426
     * Walk the context list to find the document
427
     */
428
0
    ret = ctxt->docList;
429
0
    while (ret != NULL) {
430
0
  if (ret->doc == doc)
431
0
      return(ret);
432
0
  ret = ret->next;
433
0
    }
434
0
    if (doc == ctxt->style->doc)
435
0
  return(ctxt->document);
436
0
    return(NULL);
437
0
}
438