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