/src/libxslt/libxslt/documents.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | inputPush(pctxt, inputStream); |
91 | 0 | if (pctxt->directory == NULL) |
92 | 0 | pctxt->directory = xmlParserGetDirectory((const char *) URI); |
93 | |
|
94 | 0 | xmlParseDocument(pctxt); |
95 | |
|
96 | 0 | if (pctxt->wellFormed) { |
97 | 0 | doc = pctxt->myDoc; |
98 | 0 | } |
99 | 0 | else { |
100 | 0 | doc = NULL; |
101 | 0 | xmlFreeDoc(pctxt->myDoc); |
102 | 0 | pctxt->myDoc = NULL; |
103 | 0 | } |
104 | 0 | xmlFreeParserCtxt(pctxt); |
105 | |
|
106 | 0 | return(doc); |
107 | 0 | } |
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 | 0 | xsltSetLoaderFunc(xsltDocLoaderFunc f) { |
122 | 0 | if (f == NULL) |
123 | 0 | xsltDocDefaultLoader = xsltDocDefaultLoaderFunc; |
124 | 0 | else |
125 | 0 | xsltDocDefaultLoader = f; |
126 | 0 | } |
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 | 3.14k | xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) { |
145 | 3.14k | xsltDocumentPtr cur; |
146 | | |
147 | 3.14k | cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument)); |
148 | 3.14k | if (cur == NULL) { |
149 | 0 | xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, |
150 | 0 | "xsltNewDocument : malloc failed\n"); |
151 | 0 | return(NULL); |
152 | 0 | } |
153 | 3.14k | memset(cur, 0, sizeof(xsltDocument)); |
154 | 3.14k | cur->doc = doc; |
155 | 3.14k | if (ctxt != NULL) { |
156 | 3.14k | if (! XSLT_IS_RES_TREE_FRAG(doc)) { |
157 | 3.14k | cur->next = ctxt->docList; |
158 | 3.14k | ctxt->docList = cur; |
159 | 3.14k | } |
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 | 3.14k | } |
170 | 3.14k | return(cur); |
171 | 3.14k | } |
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 | 0 | xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) { |
184 | 0 | xsltDocumentPtr cur; |
185 | |
|
186 | 0 | cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument)); |
187 | 0 | if (cur == NULL) { |
188 | 0 | xsltTransformError(NULL, style, (xmlNodePtr) doc, |
189 | 0 | "xsltNewStyleDocument : malloc failed\n"); |
190 | 0 | return(NULL); |
191 | 0 | } |
192 | 0 | memset(cur, 0, sizeof(xsltDocument)); |
193 | 0 | cur->doc = doc; |
194 | 0 | if (style != NULL) { |
195 | 0 | cur->next = style->docList; |
196 | 0 | style->docList = cur; |
197 | 0 | } |
198 | 0 | return(cur); |
199 | 0 | } |
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 | 0 | xsltFreeStyleDocuments(xsltStylesheetPtr style) { |
211 | 0 | xsltDocumentPtr doc, cur; |
212 | | #ifdef XSLT_REFACTORED_XSLT_NSCOMP |
213 | | xsltNsMapPtr nsMap; |
214 | | #endif |
215 | |
|
216 | 0 | if (style == NULL) |
217 | 0 | 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 | 0 | cur = style->docList; |
227 | 0 | while (cur != NULL) { |
228 | 0 | doc = cur; |
229 | 0 | 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 | 0 | xsltFreeDocumentKeys(doc); |
238 | 0 | if (!doc->main) |
239 | 0 | xmlFreeDoc(doc->doc); |
240 | 0 | xmlFree(doc); |
241 | 0 | } |
242 | 0 | } |
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 | 0 | xsltFreeDocuments(xsltTransformContextPtr ctxt) { |
252 | 0 | xsltDocumentPtr doc, cur; |
253 | |
|
254 | 0 | cur = ctxt->docList; |
255 | 0 | while (cur != NULL) { |
256 | 0 | doc = cur; |
257 | 0 | cur = cur->next; |
258 | 0 | xsltFreeDocumentKeys(doc); |
259 | 0 | if (!doc->main) |
260 | 0 | xmlFreeDoc(doc->doc); |
261 | 0 | xmlFree(doc); |
262 | 0 | } |
263 | 0 | cur = ctxt->styleList; |
264 | 0 | while (cur != NULL) { |
265 | 0 | doc = cur; |
266 | 0 | cur = cur->next; |
267 | 0 | xsltFreeDocumentKeys(doc); |
268 | 0 | if (!doc->main) |
269 | 0 | xmlFreeDoc(doc->doc); |
270 | 0 | xmlFree(doc); |
271 | 0 | } |
272 | 0 | } |
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 | 1.21M | xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) { |
286 | 1.21M | xsltDocumentPtr ret; |
287 | 1.21M | xmlDocPtr doc; |
288 | | |
289 | 1.21M | if ((ctxt == NULL) || (URI == NULL)) |
290 | 0 | return(NULL); |
291 | | |
292 | | /* |
293 | | * Security framework check |
294 | | */ |
295 | 1.21M | if (ctxt->sec != NULL) { |
296 | 1.21M | int res; |
297 | | |
298 | 1.21M | res = xsltCheckRead(ctxt->sec, ctxt, URI); |
299 | 1.21M | if (res <= 0) { |
300 | 1.21M | if (res == 0) |
301 | 1.21M | xsltTransformError(ctxt, NULL, NULL, |
302 | 1.21M | "xsltLoadDocument: read rights for %s denied\n", |
303 | 1.21M | URI); |
304 | 1.21M | return(NULL); |
305 | 1.21M | } |
306 | 1.21M | } |
307 | | |
308 | | /* |
309 | | * Walk the context list to find the document if preparsed |
310 | | */ |
311 | 0 | ret = ctxt->docList; |
312 | 0 | while (ret != NULL) { |
313 | 0 | if ((ret->doc != NULL) && (ret->doc->URL != NULL) && |
314 | 0 | (xmlStrEqual(ret->doc->URL, URI))) |
315 | 0 | return(ret); |
316 | 0 | ret = ret->next; |
317 | 0 | } |
318 | | |
319 | 0 | doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions, |
320 | 0 | (void *) ctxt, XSLT_LOAD_DOCUMENT); |
321 | |
|
322 | 0 | if (doc == NULL) |
323 | 0 | return(NULL); |
324 | | |
325 | 0 | if (ctxt->xinclude != 0) { |
326 | 0 | #ifdef LIBXML_XINCLUDE_ENABLED |
327 | 0 | #if LIBXML_VERSION >= 20603 |
328 | 0 | xmlXIncludeProcessFlags(doc, ctxt->parserOptions); |
329 | | #else |
330 | | xmlXIncludeProcess(doc); |
331 | | #endif |
332 | | #else |
333 | | xsltTransformError(ctxt, NULL, NULL, |
334 | | "xsltLoadDocument(%s) : XInclude processing not compiled in\n", |
335 | | URI); |
336 | | #endif |
337 | 0 | } |
338 | | /* |
339 | | * Apply white-space stripping if asked for |
340 | | */ |
341 | 0 | if (xsltNeedElemSpaceHandling(ctxt)) |
342 | 0 | xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc)); |
343 | 0 | if (ctxt->debugStatus == XSLT_DEBUG_NONE) |
344 | 0 | xmlXPathOrderDocElems(doc); |
345 | |
|
346 | 0 | ret = xsltNewDocument(ctxt, doc); |
347 | 0 | return(ret); |
348 | 0 | } |
349 | | |
350 | | /** |
351 | | * xsltLoadStyleDocument: |
352 | | * @style: an XSLT style sheet |
353 | | * @URI: the computed URI of the document |
354 | | * |
355 | | * Try to load a stylesheet document within the XSLT transformation context |
356 | | * |
357 | | * Returns the new xsltDocumentPtr or NULL in case of error |
358 | | */ |
359 | | xsltDocumentPtr |
360 | 0 | xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) { |
361 | 0 | xsltDocumentPtr ret; |
362 | 0 | xmlDocPtr doc; |
363 | 0 | xsltSecurityPrefsPtr sec; |
364 | |
|
365 | 0 | if ((style == NULL) || (URI == NULL)) |
366 | 0 | return(NULL); |
367 | | |
368 | | /* |
369 | | * Security framework check |
370 | | */ |
371 | 0 | sec = xsltGetDefaultSecurityPrefs(); |
372 | 0 | if (sec != NULL) { |
373 | 0 | int res; |
374 | |
|
375 | 0 | res = xsltCheckRead(sec, NULL, URI); |
376 | 0 | if (res <= 0) { |
377 | 0 | if (res == 0) |
378 | 0 | xsltTransformError(NULL, NULL, NULL, |
379 | 0 | "xsltLoadStyleDocument: read rights for %s denied\n", |
380 | 0 | URI); |
381 | 0 | return(NULL); |
382 | 0 | } |
383 | 0 | } |
384 | | |
385 | | /* |
386 | | * Walk the context list to find the document if preparsed |
387 | | */ |
388 | 0 | ret = style->docList; |
389 | 0 | while (ret != NULL) { |
390 | 0 | if ((ret->doc != NULL) && (ret->doc->URL != NULL) && |
391 | 0 | (xmlStrEqual(ret->doc->URL, URI))) |
392 | 0 | return(ret); |
393 | 0 | ret = ret->next; |
394 | 0 | } |
395 | | |
396 | 0 | doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS, |
397 | 0 | (void *) style, XSLT_LOAD_STYLESHEET); |
398 | 0 | if (doc == NULL) |
399 | 0 | return(NULL); |
400 | | |
401 | 0 | ret = xsltNewStyleDocument(style, doc); |
402 | 0 | return(ret); |
403 | 0 | } |
404 | | |
405 | | /** |
406 | | * xsltFindDocument: |
407 | | * @ctxt: an XSLT transformation context |
408 | | * @doc: a parsed XML document |
409 | | * |
410 | | * Try to find a document within the XSLT transformation context. |
411 | | * This will not find document infos for temporary |
412 | | * Result Tree Fragments. |
413 | | * |
414 | | * Returns the desired xsltDocumentPtr or NULL in case of error |
415 | | */ |
416 | | xsltDocumentPtr |
417 | 0 | xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) { |
418 | 0 | xsltDocumentPtr ret; |
419 | |
|
420 | 0 | if ((ctxt == NULL) || (doc == NULL)) |
421 | 0 | return(NULL); |
422 | | |
423 | | /* |
424 | | * Walk the context list to find the document |
425 | | */ |
426 | 0 | ret = ctxt->docList; |
427 | 0 | while (ret != NULL) { |
428 | 0 | if (ret->doc == doc) |
429 | 0 | return(ret); |
430 | 0 | ret = ret->next; |
431 | 0 | } |
432 | 0 | if (doc == ctxt->style->doc) |
433 | 0 | return(ctxt->document); |
434 | 0 | return(NULL); |
435 | 0 | } |
436 | | |