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