OLD | NEW |
| (Empty) |
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 | |
OLD | NEW |