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