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