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