1 /* 2 * documents.c: Implementation of the documents handling 3 * 4 * See Copyright for the status of this software. 5 * 6 * daniel (at) 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 435