Home | History | Annotate | Download | only in libxslt
      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 (at) 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  */
     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
     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
    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
    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
    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
    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
    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