• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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