1 /*
2 * imports.c: Implementation of the XSLT imports
3 *
4 * Reference:
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * See Copyright for the status of this software.
8 *
9 * daniel@veillard.com
10 */
11
12 #define IN_LIBXSLT
13 #include "libxslt.h"
14
15 #include <string.h>
16
17 #ifdef HAVE_SYS_TYPES_H
18 #include <sys/types.h>
19 #endif
20 #ifdef HAVE_MATH_H
21 #include <math.h>
22 #endif
23 #ifdef HAVE_FLOAT_H
24 #include <float.h>
25 #endif
26 #ifdef HAVE_IEEEFP_H
27 #include <ieeefp.h>
28 #endif
29 #ifdef HAVE_NAN_H
30 #include <nan.h>
31 #endif
32 #ifdef HAVE_CTYPE_H
33 #include <ctype.h>
34 #endif
35
36 #include <libxml/xmlmemory.h>
37 #include <libxml/tree.h>
38 #include <libxml/hash.h>
39 #include <libxml/xmlerror.h>
40 #include <libxml/uri.h>
41 #include "xslt.h"
42 #include "xsltInternals.h"
43 #include "xsltutils.h"
44 #include "preproc.h"
45 #include "imports.h"
46 #include "documents.h"
47 #include "security.h"
48 #include "pattern.h"
49
50
51 /************************************************************************
52 * *
53 * Module interfaces *
54 * *
55 ************************************************************************/
56 /**
57 * xsltFixImportedCompSteps:
58 * @master: the "master" stylesheet
59 * @style: the stylesheet being imported by the master
60 *
61 * normalize the comp steps for the stylesheet being imported
62 * by the master, together with any imports within that.
63 *
64 */
xsltFixImportedCompSteps(xsltStylesheetPtr master,xsltStylesheetPtr style)65 static void xsltFixImportedCompSteps(xsltStylesheetPtr master,
66 xsltStylesheetPtr style) {
67 xsltStylesheetPtr res;
68 xmlHashScan(style->templatesHash,
69 (xmlHashScanner) xsltNormalizeCompSteps, master);
70 master->extrasNr += style->extrasNr;
71 for (res = style->imports; res != NULL; res = res->next) {
72 xsltFixImportedCompSteps(master, res);
73 }
74 }
75
76 /**
77 * xsltParseStylesheetImport:
78 * @style: the XSLT stylesheet
79 * @cur: the import element
80 *
81 * parse an XSLT stylesheet import element
82 *
83 * Returns 0 in case of success -1 in case of failure.
84 */
85
86 int
xsltParseStylesheetImport(xsltStylesheetPtr style,xmlNodePtr cur)87 xsltParseStylesheetImport(xsltStylesheetPtr style, xmlNodePtr cur) {
88 int ret = -1;
89 xmlDocPtr import = NULL;
90 xmlChar *base = NULL;
91 xmlChar *uriRef = NULL;
92 xmlChar *URI = NULL;
93 xsltStylesheetPtr res;
94 xsltSecurityPrefsPtr sec;
95
96 if ((cur == NULL) || (style == NULL))
97 return (ret);
98
99 uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL);
100 if (uriRef == NULL) {
101 xsltTransformError(NULL, style, cur,
102 "xsl:import : missing href attribute\n");
103 goto error;
104 }
105
106 base = xmlNodeGetBase(style->doc, cur);
107 URI = xmlBuildURI(uriRef, base);
108 if (URI == NULL) {
109 xsltTransformError(NULL, style, cur,
110 "xsl:import : invalid URI reference %s\n", uriRef);
111 goto error;
112 }
113
114 res = style;
115 while (res != NULL) {
116 if (res->doc == NULL)
117 break;
118 if (xmlStrEqual(res->doc->URL, URI)) {
119 xsltTransformError(NULL, style, cur,
120 "xsl:import : recursion detected on imported URL %s\n", URI);
121 goto error;
122 }
123 res = res->parent;
124 }
125
126 /*
127 * Security framework check
128 */
129 sec = xsltGetDefaultSecurityPrefs();
130 if (sec != NULL) {
131 int secres;
132
133 secres = xsltCheckRead(sec, NULL, URI);
134 if (secres == 0) {
135 xsltTransformError(NULL, NULL, NULL,
136 "xsl:import: read rights for %s denied\n",
137 URI);
138 goto error;
139 }
140 }
141
142 import = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,
143 (void *) style, XSLT_LOAD_STYLESHEET);
144 if (import == NULL) {
145 xsltTransformError(NULL, style, cur,
146 "xsl:import : unable to load %s\n", URI);
147 goto error;
148 }
149
150 res = xsltParseStylesheetImportedDoc(import, style);
151 if (res != NULL) {
152 res->next = style->imports;
153 style->imports = res;
154 if (style->parent == NULL) {
155 xsltFixImportedCompSteps(style, res);
156 }
157 ret = 0;
158 } else {
159 xmlFreeDoc(import);
160 }
161
162 error:
163 if (uriRef != NULL)
164 xmlFree(uriRef);
165 if (base != NULL)
166 xmlFree(base);
167 if (URI != NULL)
168 xmlFree(URI);
169
170 return (ret);
171 }
172
173 /**
174 * xsltParseStylesheetInclude:
175 * @style: the XSLT stylesheet
176 * @cur: the include node
177 *
178 * parse an XSLT stylesheet include element
179 *
180 * Returns 0 in case of success -1 in case of failure
181 */
182
183 int
xsltParseStylesheetInclude(xsltStylesheetPtr style,xmlNodePtr cur)184 xsltParseStylesheetInclude(xsltStylesheetPtr style, xmlNodePtr cur) {
185 int ret = -1;
186 xmlDocPtr oldDoc;
187 xmlChar *base = NULL;
188 xmlChar *uriRef = NULL;
189 xmlChar *URI = NULL;
190 xsltStylesheetPtr result;
191 xsltDocumentPtr include;
192 xsltDocumentPtr docptr;
193 int oldNopreproc;
194
195 if ((cur == NULL) || (style == NULL))
196 return (ret);
197
198 uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL);
199 if (uriRef == NULL) {
200 xsltTransformError(NULL, style, cur,
201 "xsl:include : missing href attribute\n");
202 goto error;
203 }
204
205 base = xmlNodeGetBase(style->doc, cur);
206 URI = xmlBuildURI(uriRef, base);
207 if (URI == NULL) {
208 xsltTransformError(NULL, style, cur,
209 "xsl:include : invalid URI reference %s\n", uriRef);
210 goto error;
211 }
212
213 /*
214 * in order to detect recursion, we check all previously included
215 * stylesheets.
216 */
217 docptr = style->includes;
218 while (docptr != NULL) {
219 if (xmlStrEqual(docptr->doc->URL, URI)) {
220 xsltTransformError(NULL, style, cur,
221 "xsl:include : recursion detected on included URL %s\n", URI);
222 goto error;
223 }
224 docptr = docptr->includes;
225 }
226
227 include = xsltLoadStyleDocument(style, URI);
228 if (include == NULL) {
229 xsltTransformError(NULL, style, cur,
230 "xsl:include : unable to load %s\n", URI);
231 goto error;
232 }
233 #ifdef XSLT_REFACTORED
234 if (IS_XSLT_ELEM_FAST(cur) && (cur->psvi != NULL)) {
235 ((xsltStyleItemIncludePtr) cur->psvi)->include = include;
236 } else {
237 xsltTransformError(NULL, style, cur,
238 "Internal error: (xsltParseStylesheetInclude) "
239 "The xsl:include element was not compiled.\n", URI);
240 style->errors++;
241 }
242 #endif
243 oldDoc = style->doc;
244 style->doc = include->doc;
245 /* chain to stylesheet for recursion checking */
246 include->includes = style->includes;
247 style->includes = include;
248 oldNopreproc = style->nopreproc;
249 style->nopreproc = include->preproc;
250 /*
251 * TODO: This will change some values of the
252 * including stylesheet with every included module
253 * (e.g. excluded-result-prefixes)
254 * We need to strictly seperate such stylesheet-owned values.
255 */
256 result = xsltParseStylesheetProcess(style, include->doc);
257 style->nopreproc = oldNopreproc;
258 include->preproc = 1;
259 style->includes = include->includes;
260 style->doc = oldDoc;
261 if (result == NULL) {
262 ret = -1;
263 goto error;
264 }
265 ret = 0;
266
267 error:
268 if (uriRef != NULL)
269 xmlFree(uriRef);
270 if (base != NULL)
271 xmlFree(base);
272 if (URI != NULL)
273 xmlFree(URI);
274
275 return (ret);
276 }
277
278 /**
279 * xsltNextImport:
280 * @cur: the current XSLT stylesheet
281 *
282 * Find the next stylesheet in import precedence.
283 *
284 * Returns the next stylesheet or NULL if it was the last one
285 */
286
287 xsltStylesheetPtr
xsltNextImport(xsltStylesheetPtr cur)288 xsltNextImport(xsltStylesheetPtr cur) {
289 if (cur == NULL)
290 return(NULL);
291 if (cur->imports != NULL)
292 return(cur->imports);
293 if (cur->next != NULL)
294 return(cur->next) ;
295 do {
296 cur = cur->parent;
297 if (cur == NULL) break;
298 if (cur->next != NULL) return(cur->next);
299 } while (cur != NULL);
300 return(cur);
301 }
302
303 /**
304 * xsltNeedElemSpaceHandling:
305 * @ctxt: an XSLT transformation context
306 *
307 * Checks whether that stylesheet requires white-space stripping
308 *
309 * Returns 1 if space should be stripped, 0 if not
310 */
311
312 int
xsltNeedElemSpaceHandling(xsltTransformContextPtr ctxt)313 xsltNeedElemSpaceHandling(xsltTransformContextPtr ctxt) {
314 xsltStylesheetPtr style;
315
316 if (ctxt == NULL)
317 return(0);
318 style = ctxt->style;
319 while (style != NULL) {
320 if (style->stripSpaces != NULL)
321 return(1);
322 style = xsltNextImport(style);
323 }
324 return(0);
325 }
326
327 /**
328 * xsltFindElemSpaceHandling:
329 * @ctxt: an XSLT transformation context
330 * @node: an XML node
331 *
332 * Find strip-space or preserve-space informations for an element
333 * respect the import precedence or the wildcards
334 *
335 * Returns 1 if space should be stripped, 0 if not, and 2 if everything
336 * should be CDTATA wrapped.
337 */
338
339 int
xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt,xmlNodePtr node)340 xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt, xmlNodePtr node) {
341 xsltStylesheetPtr style;
342 const xmlChar *val;
343
344 if ((ctxt == NULL) || (node == NULL))
345 return(0);
346 style = ctxt->style;
347 while (style != NULL) {
348 if (node->ns != NULL) {
349 val = (const xmlChar *)
350 xmlHashLookup2(style->stripSpaces, node->name, node->ns->href);
351 if (val == NULL) {
352 val = (const xmlChar *)
353 xmlHashLookup2(style->stripSpaces, BAD_CAST "*",
354 node->ns->href);
355 }
356 } else {
357 val = (const xmlChar *)
358 xmlHashLookup2(style->stripSpaces, node->name, NULL);
359 }
360 if (val != NULL) {
361 if (xmlStrEqual(val, (xmlChar *) "strip"))
362 return(1);
363 if (xmlStrEqual(val, (xmlChar *) "preserve"))
364 return(0);
365 }
366 if (style->stripAll == 1)
367 return(1);
368 if (style->stripAll == -1)
369 return(0);
370
371 style = xsltNextImport(style);
372 }
373 return(0);
374 }
375
376 /**
377 * xsltFindTemplate:
378 * @ctxt: an XSLT transformation context
379 * @name: the template name
380 * @nameURI: the template name URI
381 *
382 * Finds the named template, apply import precedence rule.
383 * REVISIT TODO: We'll change the nameURI fields of
384 * templates to be in the string dict, so if the
385 * specified @nameURI is in the same dict, then use pointer
386 * comparison. Check if this can be done in a sane way.
387 * Maybe this function is not needed internally at
388 * transformation-time if we hard-wire the called templates
389 * to the caller.
390 *
391 * Returns the xsltTemplatePtr or NULL if not found
392 */
393 xsltTemplatePtr
xsltFindTemplate(xsltTransformContextPtr ctxt,const xmlChar * name,const xmlChar * nameURI)394 xsltFindTemplate(xsltTransformContextPtr ctxt, const xmlChar *name,
395 const xmlChar *nameURI) {
396 xsltTemplatePtr cur;
397 xsltStylesheetPtr style;
398
399 if ((ctxt == NULL) || (name == NULL))
400 return(NULL);
401 style = ctxt->style;
402 while (style != NULL) {
403 cur = style->templates;
404 while (cur != NULL) {
405 if (xmlStrEqual(name, cur->name)) {
406 if (((nameURI == NULL) && (cur->nameURI == NULL)) ||
407 ((nameURI != NULL) && (cur->nameURI != NULL) &&
408 (xmlStrEqual(nameURI, cur->nameURI)))) {
409 return(cur);
410 }
411 }
412 cur = cur->next;
413 }
414
415 style = xsltNextImport(style);
416 }
417 return(NULL);
418 }
419
420