• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
xsltDocDefaultLoaderFunc(const xmlChar * URI,xmlDictPtr dict,int options,void * ctxt ATTRIBUTE_UNUSED,xsltLoadType type ATTRIBUTE_UNUSED)61 xsltDocDefaultLoaderFunc(const xmlChar * URI, xmlDictPtr dict, int options,
62                          void *ctxt ATTRIBUTE_UNUSED,
63 			 xsltLoadType type ATTRIBUTE_UNUSED)
64 {
65     xmlParserCtxtPtr pctxt;
66     xmlParserInputPtr inputStream;
67     xmlDocPtr doc;
68 
69     pctxt = xmlNewParserCtxt();
70     if (pctxt == NULL)
71         return(NULL);
72     if ((dict != NULL) && (pctxt->dict != NULL)) {
73         xmlDictFree(pctxt->dict);
74 	pctxt->dict = NULL;
75     }
76     if (dict != NULL) {
77 	pctxt->dict = dict;
78 	xmlDictReference(pctxt->dict);
79 #ifdef WITH_XSLT_DEBUG
80 	xsltGenericDebug(xsltGenericDebugContext,
81                      "Reusing dictionary for document\n");
82 #endif
83     }
84     xmlCtxtUseOptions(pctxt, options);
85     inputStream = xmlLoadExternalEntity((const char *) URI, NULL, pctxt);
86     if (inputStream == NULL) {
87         xmlFreeParserCtxt(pctxt);
88 	return(NULL);
89     }
90     inputPush(pctxt, inputStream);
91     if (pctxt->directory == NULL)
92         pctxt->directory = xmlParserGetDirectory((const char *) URI);
93 
94     xmlParseDocument(pctxt);
95 
96     if (pctxt->wellFormed) {
97         doc = pctxt->myDoc;
98     }
99     else {
100         doc = NULL;
101         xmlFreeDoc(pctxt->myDoc);
102         pctxt->myDoc = NULL;
103     }
104     xmlFreeParserCtxt(pctxt);
105 
106     return(doc);
107 }
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
xsltSetLoaderFunc(xsltDocLoaderFunc f)121 xsltSetLoaderFunc(xsltDocLoaderFunc f) {
122     if (f == NULL)
123         xsltDocDefaultLoader = xsltDocDefaultLoaderFunc;
124     else
125         xsltDocDefaultLoader = f;
126 }
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
xsltNewDocument(xsltTransformContextPtr ctxt,xmlDocPtr doc)144 xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) {
145     xsltDocumentPtr cur;
146 
147     cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
148     if (cur == NULL) {
149 	xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
150 		"xsltNewDocument : malloc failed\n");
151 	return(NULL);
152     }
153     memset(cur, 0, sizeof(xsltDocument));
154     cur->doc = doc;
155     if (ctxt != NULL) {
156         if (! XSLT_IS_RES_TREE_FRAG(doc)) {
157 	    cur->next = ctxt->docList;
158 	    ctxt->docList = cur;
159 	}
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     }
170     return(cur);
171 }
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
xsltNewStyleDocument(xsltStylesheetPtr style,xmlDocPtr doc)183 xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) {
184     xsltDocumentPtr cur;
185 
186     cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
187     if (cur == NULL) {
188 	xsltTransformError(NULL, style, (xmlNodePtr) doc,
189 		"xsltNewStyleDocument : malloc failed\n");
190 	return(NULL);
191     }
192     memset(cur, 0, sizeof(xsltDocument));
193     cur->doc = doc;
194     if (style != NULL) {
195 	cur->next = style->docList;
196 	style->docList = cur;
197     }
198     return(cur);
199 }
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
xsltFreeStyleDocuments(xsltStylesheetPtr style)210 xsltFreeStyleDocuments(xsltStylesheetPtr style) {
211     xsltDocumentPtr doc, cur;
212 #ifdef XSLT_REFACTORED_XSLT_NSCOMP
213     xsltNsMapPtr nsMap;
214 #endif
215 
216     if (style == NULL)
217 	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     cur = style->docList;
227     while (cur != NULL) {
228 	doc = cur;
229 	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 	xsltFreeDocumentKeys(doc);
238 	if (!doc->main)
239 	    xmlFreeDoc(doc->doc);
240         xmlFree(doc);
241     }
242 }
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
xsltFreeDocuments(xsltTransformContextPtr ctxt)251 xsltFreeDocuments(xsltTransformContextPtr ctxt) {
252     xsltDocumentPtr doc, cur;
253 
254     cur = ctxt->docList;
255     while (cur != NULL) {
256 	doc = cur;
257 	cur = cur->next;
258 	xsltFreeDocumentKeys(doc);
259 	if (!doc->main)
260 	    xmlFreeDoc(doc->doc);
261         xmlFree(doc);
262     }
263     cur = ctxt->styleList;
264     while (cur != NULL) {
265 	doc = cur;
266 	cur = cur->next;
267 	xsltFreeDocumentKeys(doc);
268 	if (!doc->main)
269 	    xmlFreeDoc(doc->doc);
270         xmlFree(doc);
271     }
272 }
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
xsltLoadDocument(xsltTransformContextPtr ctxt,const xmlChar * URI)285 xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {
286     xsltDocumentPtr ret;
287     xmlDocPtr doc;
288 
289     if ((ctxt == NULL) || (URI == NULL))
290 	return(NULL);
291 
292     /*
293      * Security framework check
294      */
295     if (ctxt->sec != NULL) {
296 	int res;
297 
298 	res = xsltCheckRead(ctxt->sec, ctxt, URI);
299 	if (res == 0) {
300 	    xsltTransformError(ctxt, NULL, NULL,
301 		 "xsltLoadDocument: read rights for %s denied\n",
302 			     URI);
303 	    return(NULL);
304 	}
305     }
306 
307     /*
308      * Walk the context list to find the document if preparsed
309      */
310     ret = ctxt->docList;
311     while (ret != NULL) {
312 	if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
313 	    (xmlStrEqual(ret->doc->URL, URI)))
314 	    return(ret);
315 	ret = ret->next;
316     }
317 
318     doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions,
319                                (void *) ctxt, XSLT_LOAD_DOCUMENT);
320 
321     if (doc == NULL)
322 	return(NULL);
323 
324     if (ctxt->xinclude != 0) {
325 #ifdef LIBXML_XINCLUDE_ENABLED
326 #if LIBXML_VERSION >= 20603
327 	xmlXIncludeProcessFlags(doc, ctxt->parserOptions);
328 #else
329 	xmlXIncludeProcess(doc);
330 #endif
331 #else
332 	xsltTransformError(ctxt, NULL, NULL,
333 	    "xsltLoadDocument(%s) : XInclude processing not compiled in\n",
334 	                 URI);
335 #endif
336     }
337     /*
338      * Apply white-space stripping if asked for
339      */
340     if (xsltNeedElemSpaceHandling(ctxt))
341 	xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
342     if (ctxt->debugStatus == XSLT_DEBUG_NONE)
343 	xmlXPathOrderDocElems(doc);
344 
345     ret = xsltNewDocument(ctxt, doc);
346     return(ret);
347 }
348 
349 /**
350  * xsltLoadStyleDocument:
351  * @style: an XSLT style sheet
352  * @URI:  the computed URI of the document
353  *
354  * Try to load a stylesheet document within the XSLT transformation context
355  *
356  * Returns the new xsltDocumentPtr or NULL in case of error
357  */
358 xsltDocumentPtr
xsltLoadStyleDocument(xsltStylesheetPtr style,const xmlChar * URI)359 xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) {
360     xsltDocumentPtr ret;
361     xmlDocPtr doc;
362     xsltSecurityPrefsPtr sec;
363 
364     if ((style == NULL) || (URI == NULL))
365 	return(NULL);
366 
367     /*
368      * Security framework check
369      */
370     sec = xsltGetDefaultSecurityPrefs();
371     if (sec != NULL) {
372 	int res;
373 
374 	res = xsltCheckRead(sec, NULL, URI);
375 	if (res == 0) {
376 	    xsltTransformError(NULL, NULL, NULL,
377 		 "xsltLoadStyleDocument: read rights for %s denied\n",
378 			     URI);
379 	    return(NULL);
380 	}
381     }
382 
383     /*
384      * Walk the context list to find the document if preparsed
385      */
386     ret = style->docList;
387     while (ret != NULL) {
388 	if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
389 	    (xmlStrEqual(ret->doc->URL, URI)))
390 	    return(ret);
391 	ret = ret->next;
392     }
393 
394     doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,
395                                (void *) style, XSLT_LOAD_STYLESHEET);
396     if (doc == NULL)
397 	return(NULL);
398 
399     ret = xsltNewStyleDocument(style, doc);
400     return(ret);
401 }
402 
403 /**
404  * xsltFindDocument:
405  * @ctxt: an XSLT transformation context
406  * @doc: a parsed XML document
407  *
408  * Try to find a document within the XSLT transformation context.
409  * This will not find document infos for temporary
410  * Result Tree Fragments.
411  *
412  * Returns the desired xsltDocumentPtr or NULL in case of error
413  */
414 xsltDocumentPtr
xsltFindDocument(xsltTransformContextPtr ctxt,xmlDocPtr doc)415 xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) {
416     xsltDocumentPtr ret;
417 
418     if ((ctxt == NULL) || (doc == NULL))
419 	return(NULL);
420 
421     /*
422      * Walk the context list to find the document
423      */
424     ret = ctxt->docList;
425     while (ret != NULL) {
426 	if (ret->doc == doc)
427 	    return(ret);
428 	ret = ret->next;
429     }
430     if (doc == ctxt->style->doc)
431 	return(ctxt->document);
432     return(NULL);
433 }
434 
435