| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * documents.c: Implementation of the documents handling | |
| 3 * | |
| 4 * See Copyright for the status of this software. | |
| 5 * | |
| 6 * daniel@veillard.com | |
| 7 */ | |
| 8 | |
| 9 #define IN_LIBXSLT | |
| 10 #include "libxslt.h" | |
| 11 | |
| 12 #include <string.h> | |
| 13 | |
| 14 #include <libxml/xmlmemory.h> | |
| 15 #include <libxml/tree.h> | |
| 16 #include <libxml/hash.h> | |
| 17 #include <libxml/parser.h> | |
| 18 #include <libxml/parserInternals.h> | |
| 19 #include "xslt.h" | |
| 20 #include "xsltInternals.h" | |
| 21 #include "xsltutils.h" | |
| 22 #include "documents.h" | |
| 23 #include "transform.h" | |
| 24 #include "imports.h" | |
| 25 #include "keys.h" | |
| 26 #include "security.h" | |
| 27 | |
| 28 #ifdef LIBXML_XINCLUDE_ENABLED | |
| 29 #include <libxml/xinclude.h> | |
| 30 #endif | |
| 31 | |
| 32 #define WITH_XSLT_DEBUG_DOCUMENTS | |
| 33 | |
| 34 #ifdef WITH_XSLT_DEBUG | |
| 35 #define WITH_XSLT_DEBUG_DOCUMENTS | |
| 36 #endif | |
| 37 | |
| 38 /************************************************************************ | |
| 39 * * | |
| 40 * Hooks for the document loader * | |
| 41 * * | |
| 42 ************************************************************************/ | |
| 43 | |
| 44 /** | |
| 45 * xsltDocDefaultLoaderFunc: | |
| 46 * @URI: the URI of the document to load | |
| 47 * @dict: the dictionary to use when parsing that document | |
| 48 * @options: parsing options, a set of xmlParserOption | |
| 49 * @ctxt: the context, either a stylesheet or a transformation context | |
| 50 * @type: the xsltLoadType indicating the kind of loading required | |
| 51 * | |
| 52 * Default function to load document not provided by the compilation or | |
| 53 * transformation API themselve, for example when an xsl:import, | |
| 54 * xsl:include is found at compilation time or when a document() | |
| 55 * call is made at runtime. | |
| 56 * | |
| 57 * Returns the pointer to the document (which will be modified and | |
| 58 * freed by the engine later), or NULL in case of error. | |
| 59 */ | |
| 60 static xmlDocPtr | |
| 61 xsltDocDefaultLoaderFunc(const xmlChar * URI, xmlDictPtr dict, int options, | |
| 62 void *ctxt ATTRIBUTE_UNUSED, | |
| 63 xsltLoadType type ATTRIBUTE_UNUSED) | |
| 64 { | |
| 65 xmlParserCtxtPtr pctxt; | |
| 66 xmlParserInputPtr inputStream; | |
| 67 xmlDocPtr doc; | |
| 68 | |
| 69 pctxt = xmlNewParserCtxt(); | |
| 70 if (pctxt == NULL) | |
| 71 return(NULL); | |
| 72 if ((dict != NULL) && (pctxt->dict != NULL)) { | |
| 73 xmlDictFree(pctxt->dict); | |
| 74 pctxt->dict = NULL; | |
| 75 } | |
| 76 if (dict != NULL) { | |
| 77 pctxt->dict = dict; | |
| 78 xmlDictReference(pctxt->dict); | |
| 79 #ifdef WITH_XSLT_DEBUG | |
| 80 xsltGenericDebug(xsltGenericDebugContext, | |
| 81 "Reusing dictionary for document\n"); | |
| 82 #endif | |
| 83 } | |
| 84 xmlCtxtUseOptions(pctxt, options); | |
| 85 inputStream = xmlLoadExternalEntity((const char *) URI, NULL, pctxt); | |
| 86 if (inputStream == NULL) { | |
| 87 xmlFreeParserCtxt(pctxt); | |
| 88 return(NULL); | |
| 89 } | |
| 90 inputPush(pctxt, inputStream); | |
| 91 if (pctxt->directory == NULL) | |
| 92 pctxt->directory = xmlParserGetDirectory((const char *) URI); | |
| 93 | |
| 94 xmlParseDocument(pctxt); | |
| 95 | |
| 96 if (pctxt->wellFormed) { | |
| 97 doc = pctxt->myDoc; | |
| 98 } | |
| 99 else { | |
| 100 doc = NULL; | |
| 101 xmlFreeDoc(pctxt->myDoc); | |
| 102 pctxt->myDoc = NULL; | |
| 103 } | |
| 104 xmlFreeParserCtxt(pctxt); | |
| 105 | |
| 106 return(doc); | |
| 107 } | |
| 108 | |
| 109 | |
| 110 xsltDocLoaderFunc xsltDocDefaultLoader = xsltDocDefaultLoaderFunc; | |
| 111 | |
| 112 /** | |
| 113 * xsltSetLoaderFunc: | |
| 114 * @f: the new function to handle document loading. | |
| 115 * | |
| 116 * Set the new function to load document, if NULL it resets it to the | |
| 117 * default function. | |
| 118 */ | |
| 119 | |
| 120 void | |
| 121 xsltSetLoaderFunc(xsltDocLoaderFunc f) { | |
| 122 if (f == NULL) | |
| 123 xsltDocDefaultLoader = xsltDocDefaultLoaderFunc; | |
| 124 else | |
| 125 xsltDocDefaultLoader = f; | |
| 126 } | |
| 127 | |
| 128 /************************************************************************ | |
| 129 * * | |
| 130 * Module interfaces * | |
| 131 * * | |
| 132 ************************************************************************/ | |
| 133 | |
| 134 /** | |
| 135 * xsltNewDocument: | |
| 136 * @ctxt: an XSLT transformation context (or NULL) | |
| 137 * @doc: a parsed XML document | |
| 138 * | |
| 139 * Register a new document, apply key computations | |
| 140 * | |
| 141 * Returns a handler to the document | |
| 142 */ | |
| 143 xsltDocumentPtr | |
| 144 xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) { | |
| 145 xsltDocumentPtr cur; | |
| 146 | |
| 147 cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument)); | |
| 148 if (cur == NULL) { | |
| 149 xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, | |
| 150 "xsltNewDocument : malloc failed\n"); | |
| 151 return(NULL); | |
| 152 } | |
| 153 memset(cur, 0, sizeof(xsltDocument)); | |
| 154 cur->doc = doc; | |
| 155 if (ctxt != NULL) { | |
| 156 if (! XSLT_IS_RES_TREE_FRAG(doc)) { | |
| 157 cur->next = ctxt->docList; | |
| 158 ctxt->docList = cur; | |
| 159 } | |
| 160 /* | |
| 161 * A key with a specific name for a specific document | |
| 162 * will only be computed if there's a call to the key() | |
| 163 * function using that specific name for that specific | |
| 164 * document. I.e. computation of keys will be done in | |
| 165 * xsltGetKey() (keys.c) on an on-demand basis. | |
| 166 * | |
| 167 * xsltInitCtxtKeys(ctxt, cur); not called here anymore | |
| 168 */ | |
| 169 } | |
| 170 return(cur); | |
| 171 } | |
| 172 | |
| 173 /** | |
| 174 * xsltNewStyleDocument: | |
| 175 * @style: an XSLT style sheet | |
| 176 * @doc: a parsed XML document | |
| 177 * | |
| 178 * Register a new document, apply key computations | |
| 179 * | |
| 180 * Returns a handler to the document | |
| 181 */ | |
| 182 xsltDocumentPtr | |
| 183 xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) { | |
| 184 xsltDocumentPtr cur; | |
| 185 | |
| 186 cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument)); | |
| 187 if (cur == NULL) { | |
| 188 xsltTransformError(NULL, style, (xmlNodePtr) doc, | |
| 189 "xsltNewStyleDocument : malloc failed\n"); | |
| 190 return(NULL); | |
| 191 } | |
| 192 memset(cur, 0, sizeof(xsltDocument)); | |
| 193 cur->doc = doc; | |
| 194 if (style != NULL) { | |
| 195 cur->next = style->docList; | |
| 196 style->docList = cur; | |
| 197 } | |
| 198 return(cur); | |
| 199 } | |
| 200 | |
| 201 /** | |
| 202 * xsltFreeStyleDocuments: | |
| 203 * @style: an XSLT stylesheet (representing a stylesheet-level) | |
| 204 * | |
| 205 * Frees the node-trees (and xsltDocument structures) of all | |
| 206 * stylesheet-modules of the stylesheet-level represented by | |
| 207 * the given @style. | |
| 208 */ | |
| 209 void | |
| 210 xsltFreeStyleDocuments(xsltStylesheetPtr style) { | |
| 211 xsltDocumentPtr doc, cur; | |
| 212 #ifdef XSLT_REFACTORED_XSLT_NSCOMP | |
| 213 xsltNsMapPtr nsMap; | |
| 214 #endif | |
| 215 | |
| 216 if (style == NULL) | |
| 217 return; | |
| 218 | |
| 219 #ifdef XSLT_REFACTORED_XSLT_NSCOMP | |
| 220 if (XSLT_HAS_INTERNAL_NSMAP(style)) | |
| 221 nsMap = XSLT_GET_INTERNAL_NSMAP(style); | |
| 222 else | |
| 223 nsMap = NULL; | |
| 224 #endif | |
| 225 | |
| 226 cur = style->docList; | |
| 227 while (cur != NULL) { | |
| 228 doc = cur; | |
| 229 cur = cur->next; | |
| 230 #ifdef XSLT_REFACTORED_XSLT_NSCOMP | |
| 231 /* | |
| 232 * Restore all changed namespace URIs of ns-decls. | |
| 233 */ | |
| 234 if (nsMap) | |
| 235 xsltRestoreDocumentNamespaces(nsMap, doc->doc); | |
| 236 #endif | |
| 237 xsltFreeDocumentKeys(doc); | |
| 238 if (!doc->main) | |
| 239 xmlFreeDoc(doc->doc); | |
| 240 xmlFree(doc); | |
| 241 } | |
| 242 } | |
| 243 | |
| 244 /** | |
| 245 * xsltFreeDocuments: | |
| 246 * @ctxt: an XSLT transformation context | |
| 247 * | |
| 248 * Free up all the space used by the loaded documents | |
| 249 */ | |
| 250 void | |
| 251 xsltFreeDocuments(xsltTransformContextPtr ctxt) { | |
| 252 xsltDocumentPtr doc, cur; | |
| 253 | |
| 254 cur = ctxt->docList; | |
| 255 while (cur != NULL) { | |
| 256 doc = cur; | |
| 257 cur = cur->next; | |
| 258 xsltFreeDocumentKeys(doc); | |
| 259 if (!doc->main) | |
| 260 xmlFreeDoc(doc->doc); | |
| 261 xmlFree(doc); | |
| 262 } | |
| 263 cur = ctxt->styleList; | |
| 264 while (cur != NULL) { | |
| 265 doc = cur; | |
| 266 cur = cur->next; | |
| 267 xsltFreeDocumentKeys(doc); | |
| 268 if (!doc->main) | |
| 269 xmlFreeDoc(doc->doc); | |
| 270 xmlFree(doc); | |
| 271 } | |
| 272 } | |
| 273 | |
| 274 /** | |
| 275 * xsltLoadDocument: | |
| 276 * @ctxt: an XSLT transformation context | |
| 277 * @URI: the computed URI of the document | |
| 278 * | |
| 279 * Try to load a document (not a stylesheet) | |
| 280 * within the XSLT transformation context | |
| 281 * | |
| 282 * Returns the new xsltDocumentPtr or NULL in case of error | |
| 283 */ | |
| 284 xsltDocumentPtr | |
| 285 xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) { | |
| 286 xsltDocumentPtr ret; | |
| 287 xmlDocPtr doc; | |
| 288 | |
| 289 if ((ctxt == NULL) || (URI == NULL)) | |
| 290 return(NULL); | |
| 291 | |
| 292 /* | |
| 293 * Security framework check | |
| 294 */ | |
| 295 if (ctxt->sec != NULL) { | |
| 296 int res; | |
| 297 | |
| 298 res = xsltCheckRead(ctxt->sec, ctxt, URI); | |
| 299 if (res == 0) { | |
| 300 xsltTransformError(ctxt, NULL, NULL, | |
| 301 "xsltLoadDocument: read rights for %s denied\n", | |
| 302 URI); | |
| 303 return(NULL); | |
| 304 } | |
| 305 } | |
| 306 | |
| 307 /* | |
| 308 * Walk the context list to find the document if preparsed | |
| 309 */ | |
| 310 ret = ctxt->docList; | |
| 311 while (ret != NULL) { | |
| 312 if ((ret->doc != NULL) && (ret->doc->URL != NULL) && | |
| 313 (xmlStrEqual(ret->doc->URL, URI))) | |
| 314 return(ret); | |
| 315 ret = ret->next; | |
| 316 } | |
| 317 | |
| 318 doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions, | |
| 319 (void *) ctxt, XSLT_LOAD_DOCUMENT); | |
| 320 | |
| 321 if (doc == NULL) | |
| 322 return(NULL); | |
| 323 | |
| 324 if (ctxt->xinclude != 0) { | |
| 325 #ifdef LIBXML_XINCLUDE_ENABLED | |
| 326 #if LIBXML_VERSION >= 20603 | |
| 327 xmlXIncludeProcessFlags(doc, ctxt->parserOptions); | |
| 328 #else | |
| 329 xmlXIncludeProcess(doc); | |
| 330 #endif | |
| 331 #else | |
| 332 xsltTransformError(ctxt, NULL, NULL, | |
| 333 "xsltLoadDocument(%s) : XInclude processing not compiled in\n", | |
| 334 URI); | |
| 335 #endif | |
| 336 } | |
| 337 /* | |
| 338 * Apply white-space stripping if asked for | |
| 339 */ | |
| 340 if (xsltNeedElemSpaceHandling(ctxt)) | |
| 341 xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc)); | |
| 342 if (ctxt->debugStatus == XSLT_DEBUG_NONE) | |
| 343 xmlXPathOrderDocElems(doc); | |
| 344 | |
| 345 ret = xsltNewDocument(ctxt, doc); | |
| 346 return(ret); | |
| 347 } | |
| 348 | |
| 349 /** | |
| 350 * xsltLoadStyleDocument: | |
| 351 * @style: an XSLT style sheet | |
| 352 * @URI: the computed URI of the document | |
| 353 * | |
| 354 * Try to load a stylesheet document within the XSLT transformation context | |
| 355 * | |
| 356 * Returns the new xsltDocumentPtr or NULL in case of error | |
| 357 */ | |
| 358 xsltDocumentPtr | |
| 359 xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) { | |
| 360 xsltDocumentPtr ret; | |
| 361 xmlDocPtr doc; | |
| 362 xsltSecurityPrefsPtr sec; | |
| 363 | |
| 364 if ((style == NULL) || (URI == NULL)) | |
| 365 return(NULL); | |
| 366 | |
| 367 /* | |
| 368 * Security framework check | |
| 369 */ | |
| 370 sec = xsltGetDefaultSecurityPrefs(); | |
| 371 if (sec != NULL) { | |
| 372 int res; | |
| 373 | |
| 374 res = xsltCheckRead(sec, NULL, URI); | |
| 375 if (res == 0) { | |
| 376 xsltTransformError(NULL, NULL, NULL, | |
| 377 "xsltLoadStyleDocument: read rights for %s denied\n", | |
| 378 URI); | |
| 379 return(NULL); | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 /* | |
| 384 * Walk the context list to find the document if preparsed | |
| 385 */ | |
| 386 ret = style->docList; | |
| 387 while (ret != NULL) { | |
| 388 if ((ret->doc != NULL) && (ret->doc->URL != NULL) && | |
| 389 (xmlStrEqual(ret->doc->URL, URI))) | |
| 390 return(ret); | |
| 391 ret = ret->next; | |
| 392 } | |
| 393 | |
| 394 doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS, | |
| 395 (void *) style, XSLT_LOAD_STYLESHEET); | |
| 396 if (doc == NULL) | |
| 397 return(NULL); | |
| 398 | |
| 399 ret = xsltNewStyleDocument(style, doc); | |
| 400 return(ret); | |
| 401 } | |
| 402 | |
| 403 /** | |
| 404 * xsltFindDocument: | |
| 405 * @ctxt: an XSLT transformation context | |
| 406 * @doc: a parsed XML document | |
| 407 * | |
| 408 * Try to find a document within the XSLT transformation context. | |
| 409 * This will not find document infos for temporary | |
| 410 * Result Tree Fragments. | |
| 411 * | |
| 412 * Returns the desired xsltDocumentPtr or NULL in case of error | |
| 413 */ | |
| 414 xsltDocumentPtr | |
| 415 xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) { | |
| 416 xsltDocumentPtr ret; | |
| 417 | |
| 418 if ((ctxt == NULL) || (doc == NULL)) | |
| 419 return(NULL); | |
| 420 | |
| 421 /* | |
| 422 * Walk the context list to find the document | |
| 423 */ | |
| 424 ret = ctxt->docList; | |
| 425 while (ret != NULL) { | |
| 426 if (ret->doc == doc) | |
| 427 return(ret); | |
| 428 ret = ret->next; | |
| 429 } | |
| 430 if (doc == ctxt->style->doc) | |
| 431 return(ctxt->document); | |
| 432 return(NULL); | |
| 433 } | |
| 434 | |
| OLD | NEW |