| OLD | NEW |
| (Empty) |
| 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, | |
| 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 if (style->namedTemplates != NULL) { | |
| 404 cur = (xsltTemplatePtr) | |
| 405 xmlHashLookup2(style->namedTemplates, name, nameURI); | |
| 406 if (cur != NULL) | |
| 407 return(cur); | |
| 408 } | |
| 409 | |
| 410 style = xsltNextImport(style); | |
| 411 } | |
| 412 return(NULL); | |
| 413 } | |
| 414 | |
| OLD | NEW |