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