- Create another branch for networking fixes
[reactos.git] / dll / 3rdparty / libxslt / documents.c
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 {
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
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
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
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
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
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
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
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
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