xref: /reactos/dll/3rdparty/libxslt/documents.c (revision c2c66aff)
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
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
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
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
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
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
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
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 	    xsltTransformError(ctxt, NULL, NULL,
284 		 "xsltLoadDocument: read rights for %s denied\n",
285 			     URI);
286 	    return(NULL);
287 	}
288     }
289 
290     /*
291      * Walk the context list to find the document if preparsed
292      */
293     ret = ctxt->docList;
294     while (ret != NULL) {
295 	if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
296 	    (xmlStrEqual(ret->doc->URL, URI)))
297 	    return(ret);
298 	ret = ret->next;
299     }
300 
301     doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions,
302                                (void *) ctxt, XSLT_LOAD_DOCUMENT);
303 
304     if (doc == NULL)
305 	return(NULL);
306 
307     if (ctxt->xinclude != 0) {
308 #ifdef LIBXML_XINCLUDE_ENABLED
309 #if LIBXML_VERSION >= 20603
310 	xmlXIncludeProcessFlags(doc, ctxt->parserOptions);
311 #else
312 	xmlXIncludeProcess(doc);
313 #endif
314 #else
315 	xsltTransformError(ctxt, NULL, NULL,
316 	    "xsltLoadDocument(%s) : XInclude processing not compiled in\n",
317 	                 URI);
318 #endif
319     }
320     /*
321      * Apply white-space stripping if asked for
322      */
323     if (xsltNeedElemSpaceHandling(ctxt))
324 	xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
325     if (ctxt->debugStatus == XSLT_DEBUG_NONE)
326 	xmlXPathOrderDocElems(doc);
327 
328     ret = xsltNewDocument(ctxt, doc);
329     return(ret);
330 }
331 
332 /**
333  * xsltLoadStyleDocument:
334  * @style: an XSLT style sheet
335  * @URI:  the computed URI of the document
336  *
337  * Try to load a stylesheet document within the XSLT transformation context
338  *
339  * Returns the new xsltDocumentPtr or NULL in case of error
340  */
341 xsltDocumentPtr
342 xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) {
343     xsltDocumentPtr ret;
344     xmlDocPtr doc;
345     xsltSecurityPrefsPtr sec;
346 
347     if ((style == NULL) || (URI == NULL))
348 	return(NULL);
349 
350     /*
351      * Security framework check
352      */
353     sec = xsltGetDefaultSecurityPrefs();
354     if (sec != NULL) {
355 	int res;
356 
357 	res = xsltCheckRead(sec, NULL, URI);
358 	if (res == 0) {
359 	    xsltTransformError(NULL, NULL, NULL,
360 		 "xsltLoadStyleDocument: read rights for %s denied\n",
361 			     URI);
362 	    return(NULL);
363 	}
364     }
365 
366     /*
367      * Walk the context list to find the document if preparsed
368      */
369     ret = style->docList;
370     while (ret != NULL) {
371 	if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
372 	    (xmlStrEqual(ret->doc->URL, URI)))
373 	    return(ret);
374 	ret = ret->next;
375     }
376 
377     doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,
378                                (void *) style, XSLT_LOAD_STYLESHEET);
379     if (doc == NULL)
380 	return(NULL);
381 
382     ret = xsltNewStyleDocument(style, doc);
383     return(ret);
384 }
385 
386 /**
387  * xsltFindDocument:
388  * @ctxt: an XSLT transformation context
389  * @doc: a parsed XML document
390  *
391  * Try to find a document within the XSLT transformation context.
392  * This will not find document infos for temporary
393  * Result Tree Fragments.
394  *
395  * Returns the desired xsltDocumentPtr or NULL in case of error
396  */
397 xsltDocumentPtr
398 xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) {
399     xsltDocumentPtr ret;
400 
401     if ((ctxt == NULL) || (doc == NULL))
402 	return(NULL);
403 
404     /*
405      * Walk the context list to find the document
406      */
407     ret = ctxt->docList;
408     while (ret != NULL) {
409 	if (ret->doc == doc)
410 	    return(ret);
411 	ret = ret->next;
412     }
413     if (doc == ctxt->style->doc)
414 	return(ctxt->document);
415     return(NULL);
416 }
417 
418