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