1 | /*
|
---|
2 | * documents.c: Implementation of the documents handling
|
---|
3 | *
|
---|
4 | * See Copyright for the status of this software.
|
---|
5 | *
|
---|
6 | * [email protected]
|
---|
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 | #ifdef XSLT_REFACTORED_KEYCOMP
|
---|
161 | /*
|
---|
162 | * A key with a specific name for a specific document
|
---|
163 | * will only be computed if there's a call to the key()
|
---|
164 | * function using that specific name for that specific
|
---|
165 | * document. I.e. computation of keys will be done in
|
---|
166 | * xsltGetKey() (keys.c) on an on-demand basis.
|
---|
167 | */
|
---|
168 | #else
|
---|
169 | /*
|
---|
170 | * Old behaviour.
|
---|
171 | */
|
---|
172 | xsltInitCtxtKeys(ctxt, cur);
|
---|
173 | #endif
|
---|
174 | }
|
---|
175 | return(cur);
|
---|
176 | }
|
---|
177 |
|
---|
178 | /**
|
---|
179 | * xsltNewStyleDocument:
|
---|
180 | * @style: an XSLT style sheet
|
---|
181 | * @doc: a parsed XML document
|
---|
182 | *
|
---|
183 | * Register a new document, apply key computations
|
---|
184 | *
|
---|
185 | * Returns a handler to the document
|
---|
186 | */
|
---|
187 | xsltDocumentPtr
|
---|
188 | xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) {
|
---|
189 | xsltDocumentPtr cur;
|
---|
190 |
|
---|
191 | cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
|
---|
192 | if (cur == NULL) {
|
---|
193 | xsltTransformError(NULL, style, (xmlNodePtr) doc,
|
---|
194 | "xsltNewStyleDocument : malloc failed\n");
|
---|
195 | return(NULL);
|
---|
196 | }
|
---|
197 | memset(cur, 0, sizeof(xsltDocument));
|
---|
198 | cur->doc = doc;
|
---|
199 | if (style != NULL) {
|
---|
200 | cur->next = style->docList;
|
---|
201 | style->docList = cur;
|
---|
202 | }
|
---|
203 | return(cur);
|
---|
204 | }
|
---|
205 |
|
---|
206 | /**
|
---|
207 | * xsltFreeStyleDocuments:
|
---|
208 | * @style: an XSLT stylesheet (representing a stylesheet-level)
|
---|
209 | *
|
---|
210 | * Frees the node-trees (and xsltDocument structures) of all
|
---|
211 | * stylesheet-modules of the stylesheet-level represented by
|
---|
212 | * the given @style.
|
---|
213 | */
|
---|
214 | void
|
---|
215 | xsltFreeStyleDocuments(xsltStylesheetPtr style) {
|
---|
216 | xsltDocumentPtr doc, cur;
|
---|
217 | #ifdef XSLT_REFACTORED_XSLT_NSCOMP
|
---|
218 | xsltNsMapPtr nsMap;
|
---|
219 | #endif
|
---|
220 |
|
---|
221 | if (style == NULL)
|
---|
222 | return;
|
---|
223 |
|
---|
224 | #ifdef XSLT_REFACTORED_XSLT_NSCOMP
|
---|
225 | if (XSLT_HAS_INTERNAL_NSMAP(style))
|
---|
226 | nsMap = XSLT_GET_INTERNAL_NSMAP(style);
|
---|
227 | else
|
---|
228 | nsMap = NULL;
|
---|
229 | #endif
|
---|
230 |
|
---|
231 | cur = style->docList;
|
---|
232 | while (cur != NULL) {
|
---|
233 | doc = cur;
|
---|
234 | cur = cur->next;
|
---|
235 | #ifdef XSLT_REFACTORED_XSLT_NSCOMP
|
---|
236 | /*
|
---|
237 | * Restore all changed namespace URIs of ns-decls.
|
---|
238 | */
|
---|
239 | if (nsMap)
|
---|
240 | xsltRestoreDocumentNamespaces(nsMap, doc->doc);
|
---|
241 | #endif
|
---|
242 | xsltFreeDocumentKeys(doc);
|
---|
243 | if (!doc->main)
|
---|
244 | xmlFreeDoc(doc->doc);
|
---|
245 | xmlFree(doc);
|
---|
246 | }
|
---|
247 | }
|
---|
248 |
|
---|
249 | /**
|
---|
250 | * xsltFreeDocuments:
|
---|
251 | * @ctxt: an XSLT transformation context
|
---|
252 | *
|
---|
253 | * Free up all the space used by the loaded documents
|
---|
254 | */
|
---|
255 | void
|
---|
256 | xsltFreeDocuments(xsltTransformContextPtr ctxt) {
|
---|
257 | xsltDocumentPtr doc, cur;
|
---|
258 |
|
---|
259 | cur = ctxt->docList;
|
---|
260 | while (cur != NULL) {
|
---|
261 | doc = cur;
|
---|
262 | cur = cur->next;
|
---|
263 | xsltFreeDocumentKeys(doc);
|
---|
264 | if (!doc->main)
|
---|
265 | xmlFreeDoc(doc->doc);
|
---|
266 | xmlFree(doc);
|
---|
267 | }
|
---|
268 | cur = ctxt->styleList;
|
---|
269 | while (cur != NULL) {
|
---|
270 | doc = cur;
|
---|
271 | cur = cur->next;
|
---|
272 | xsltFreeDocumentKeys(doc);
|
---|
273 | if (!doc->main)
|
---|
274 | xmlFreeDoc(doc->doc);
|
---|
275 | xmlFree(doc);
|
---|
276 | }
|
---|
277 | }
|
---|
278 |
|
---|
279 | /**
|
---|
280 | * xsltLoadDocument:
|
---|
281 | * @ctxt: an XSLT transformation context
|
---|
282 | * @URI: the computed URI of the document
|
---|
283 | *
|
---|
284 | * Try to load a document (not a stylesheet)
|
---|
285 | * within the XSLT transformation context
|
---|
286 | *
|
---|
287 | * Returns the new xsltDocumentPtr or NULL in case of error
|
---|
288 | */
|
---|
289 | xsltDocumentPtr
|
---|
290 | xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {
|
---|
291 | xsltDocumentPtr ret;
|
---|
292 | xmlDocPtr doc;
|
---|
293 |
|
---|
294 | if ((ctxt == NULL) || (URI == NULL))
|
---|
295 | return(NULL);
|
---|
296 |
|
---|
297 | /*
|
---|
298 | * Security framework check
|
---|
299 | */
|
---|
300 | if (ctxt->sec != NULL) {
|
---|
301 | int res;
|
---|
302 |
|
---|
303 | res = xsltCheckRead(ctxt->sec, ctxt, URI);
|
---|
304 | if (res == 0) {
|
---|
305 | xsltTransformError(ctxt, NULL, NULL,
|
---|
306 | "xsltLoadDocument: read rights for %s denied\n",
|
---|
307 | URI);
|
---|
308 | return(NULL);
|
---|
309 | }
|
---|
310 | }
|
---|
311 |
|
---|
312 | /*
|
---|
313 | * Walk the context list to find the document if preparsed
|
---|
314 | */
|
---|
315 | ret = ctxt->docList;
|
---|
316 | while (ret != NULL) {
|
---|
317 | if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
|
---|
318 | (xmlStrEqual(ret->doc->URL, URI)))
|
---|
319 | return(ret);
|
---|
320 | ret = ret->next;
|
---|
321 | }
|
---|
322 |
|
---|
323 | doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions,
|
---|
324 | (void *) ctxt, XSLT_LOAD_DOCUMENT);
|
---|
325 |
|
---|
326 | if (doc == NULL)
|
---|
327 | return(NULL);
|
---|
328 |
|
---|
329 | if (ctxt->xinclude != 0) {
|
---|
330 | #ifdef LIBXML_XINCLUDE_ENABLED
|
---|
331 | #if LIBXML_VERSION >= 20603
|
---|
332 | 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 | }
|
---|
342 | /*
|
---|
343 | * Apply white-space stripping if asked for
|
---|
344 | */
|
---|
345 | if (xsltNeedElemSpaceHandling(ctxt))
|
---|
346 | xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
|
---|
347 | if (ctxt->debugStatus == XSLT_DEBUG_NONE)
|
---|
348 | xmlXPathOrderDocElems(doc);
|
---|
349 |
|
---|
350 | ret = xsltNewDocument(ctxt, doc);
|
---|
351 | return(ret);
|
---|
352 | }
|
---|
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 | xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) {
|
---|
365 | xsltDocumentPtr ret;
|
---|
366 | xmlDocPtr doc;
|
---|
367 | xsltSecurityPrefsPtr sec;
|
---|
368 |
|
---|
369 | if ((style == NULL) || (URI == NULL))
|
---|
370 | return(NULL);
|
---|
371 |
|
---|
372 | /*
|
---|
373 | * Security framework check
|
---|
374 | */
|
---|
375 | sec = xsltGetDefaultSecurityPrefs();
|
---|
376 | if (sec != NULL) {
|
---|
377 | int res;
|
---|
378 |
|
---|
379 | res = xsltCheckRead(sec, NULL, URI);
|
---|
380 | if (res == 0) {
|
---|
381 | xsltTransformError(NULL, NULL, NULL,
|
---|
382 | "xsltLoadStyleDocument: read rights for %s denied\n",
|
---|
383 | URI);
|
---|
384 | return(NULL);
|
---|
385 | }
|
---|
386 | }
|
---|
387 |
|
---|
388 | /*
|
---|
389 | * Walk the context list to find the document if preparsed
|
---|
390 | */
|
---|
391 | ret = style->docList;
|
---|
392 | while (ret != NULL) {
|
---|
393 | if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
|
---|
394 | (xmlStrEqual(ret->doc->URL, URI)))
|
---|
395 | return(ret);
|
---|
396 | ret = ret->next;
|
---|
397 | }
|
---|
398 |
|
---|
399 | doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,
|
---|
400 | (void *) style, XSLT_LOAD_STYLESHEET);
|
---|
401 | if (doc == NULL)
|
---|
402 | return(NULL);
|
---|
403 |
|
---|
404 | ret = xsltNewStyleDocument(style, doc);
|
---|
405 | return(ret);
|
---|
406 | }
|
---|
407 |
|
---|
408 | /**
|
---|
409 | * xsltFindDocument:
|
---|
410 | * @ctxt: an XSLT transformation context
|
---|
411 | * @doc: a parsed XML document
|
---|
412 | *
|
---|
413 | * Try to find a document within the XSLT transformation context.
|
---|
414 | * This will not find document infos for temporary
|
---|
415 | * Result Tree Fragments.
|
---|
416 | *
|
---|
417 | * Returns the desired xsltDocumentPtr or NULL in case of error
|
---|
418 | */
|
---|
419 | xsltDocumentPtr
|
---|
420 | xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) {
|
---|
421 | xsltDocumentPtr ret;
|
---|
422 |
|
---|
423 | if ((ctxt == NULL) || (doc == NULL))
|
---|
424 | return(NULL);
|
---|
425 |
|
---|
426 | /*
|
---|
427 | * Walk the context list to find the document
|
---|
428 | */
|
---|
429 | ret = ctxt->docList;
|
---|
430 | while (ret != NULL) {
|
---|
431 | if (ret->doc == doc)
|
---|
432 | return(ret);
|
---|
433 | ret = ret->next;
|
---|
434 | }
|
---|
435 | if (doc == ctxt->style->doc)
|
---|
436 | return(ctxt->document);
|
---|
437 | return(NULL);
|
---|
438 | }
|
---|
439 |
|
---|