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 dictionnary 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 */ 60static xmlDocPtr 61xsltDocDefaultLoaderFunc(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 110xsltDocLoaderFunc 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 120void 121xsltSetLoaderFunc(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 */ 143xsltDocumentPtr 144xsltNewDocument(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#ifdef XSLT_REFACTORED_KEYCOMP 161 /* 162 * A key with a specific name for a specific document 163 * will only be computed if there's a call to the key() 164 * function using that specific name for that specific 165 * document. I.e. computation of keys will be done in 166 * xsltGetKey() (keys.c) on an on-demand basis. 167 */ 168#else 169 /* 170 * Old behaviour. 171 */ 172 xsltInitCtxtKeys(ctxt, cur); 173#endif 174 } 175 return(cur); 176} 177 178/** 179 * xsltNewStyleDocument: 180 * @style: an XSLT style sheet 181 * @doc: a parsed XML document 182 * 183 * Register a new document, apply key computations 184 * 185 * Returns a handler to the document 186 */ 187xsltDocumentPtr 188xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) { 189 xsltDocumentPtr cur; 190 191 cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument)); 192 if (cur == NULL) { 193 xsltTransformError(NULL, style, (xmlNodePtr) doc, 194 "xsltNewStyleDocument : malloc failed\n"); 195 return(NULL); 196 } 197 memset(cur, 0, sizeof(xsltDocument)); 198 cur->doc = doc; 199 if (style != NULL) { 200 cur->next = style->docList; 201 style->docList = cur; 202 } 203 return(cur); 204} 205 206/** 207 * xsltFreeStyleDocuments: 208 * @style: an XSLT stylesheet (representing a stylesheet-level) 209 * 210 * Frees the node-trees (and xsltDocument structures) of all 211 * stylesheet-modules of the stylesheet-level represented by 212 * the given @style. 213 */ 214void 215xsltFreeStyleDocuments(xsltStylesheetPtr style) { 216 xsltDocumentPtr doc, cur; 217#ifdef XSLT_REFACTORED_XSLT_NSCOMP 218 xsltNsMapPtr nsMap; 219#endif 220 221 if (style == NULL) 222 return; 223 224#ifdef XSLT_REFACTORED_XSLT_NSCOMP 225 if (XSLT_HAS_INTERNAL_NSMAP(style)) 226 nsMap = XSLT_GET_INTERNAL_NSMAP(style); 227 else 228 nsMap = NULL; 229#endif 230 231 cur = style->docList; 232 while (cur != NULL) { 233 doc = cur; 234 cur = cur->next; 235#ifdef XSLT_REFACTORED_XSLT_NSCOMP 236 /* 237 * Restore all changed namespace URIs of ns-decls. 238 */ 239 if (nsMap) 240 xsltRestoreDocumentNamespaces(nsMap, doc->doc); 241#endif 242 xsltFreeDocumentKeys(doc); 243 if (!doc->main) 244 xmlFreeDoc(doc->doc); 245 xmlFree(doc); 246 } 247} 248 249/** 250 * xsltFreeDocuments: 251 * @ctxt: an XSLT transformation context 252 * 253 * Free up all the space used by the loaded documents 254 */ 255void 256xsltFreeDocuments(xsltTransformContextPtr ctxt) { 257 xsltDocumentPtr doc, cur; 258 259 cur = ctxt->docList; 260 while (cur != NULL) { 261 doc = cur; 262 cur = cur->next; 263 xsltFreeDocumentKeys(doc); 264 if (!doc->main) 265 xmlFreeDoc(doc->doc); 266 xmlFree(doc); 267 } 268 cur = ctxt->styleList; 269 while (cur != NULL) { 270 doc = cur; 271 cur = cur->next; 272 xsltFreeDocumentKeys(doc); 273 if (!doc->main) 274 xmlFreeDoc(doc->doc); 275 xmlFree(doc); 276 } 277} 278 279/** 280 * xsltLoadDocument: 281 * @ctxt: an XSLT transformation context 282 * @URI: the computed URI of the document 283 * 284 * Try to load a document (not a stylesheet) 285 * within the XSLT transformation context 286 * 287 * Returns the new xsltDocumentPtr or NULL in case of error 288 */ 289xsltDocumentPtr 290xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) { 291 xsltDocumentPtr ret; 292 xmlDocPtr doc; 293 294 if ((ctxt == NULL) || (URI == NULL)) 295 return(NULL); 296 297 /* 298 * Security framework check 299 */ 300 if (ctxt->sec != NULL) { 301 int res; 302 303 res = xsltCheckRead(ctxt->sec, ctxt, URI); 304 if (res == 0) { 305 xsltTransformError(ctxt, NULL, NULL, 306 "xsltLoadDocument: read rights for %s denied\n", 307 URI); 308 return(NULL); 309 } 310 } 311 312 /* 313 * Walk the context list to find the document if preparsed 314 */ 315 ret = ctxt->docList; 316 while (ret != NULL) { 317 if ((ret->doc != NULL) && (ret->doc->URL != NULL) && 318 (xmlStrEqual(ret->doc->URL, URI))) 319 return(ret); 320 ret = ret->next; 321 } 322 323 doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions, 324 (void *) ctxt, XSLT_LOAD_DOCUMENT); 325 326 if (doc == NULL) 327 return(NULL); 328 329 if (ctxt->xinclude != 0) { 330#ifdef LIBXML_XINCLUDE_ENABLED 331#if LIBXML_VERSION >= 20603 332 xmlXIncludeProcessFlags(doc, ctxt->parserOptions); 333#else 334 xmlXIncludeProcess(doc); 335#endif 336#else 337 xsltTransformError(ctxt, NULL, NULL, 338 "xsltLoadDocument(%s) : XInclude processing not compiled in\n", 339 URI); 340#endif 341 } 342 /* 343 * Apply white-space stripping if asked for 344 */ 345 if (xsltNeedElemSpaceHandling(ctxt)) 346 xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc)); 347 if (ctxt->debugStatus == XSLT_DEBUG_NONE) 348 xmlXPathOrderDocElems(doc); 349 350 ret = xsltNewDocument(ctxt, doc); 351 return(ret); 352} 353 354/** 355 * xsltLoadStyleDocument: 356 * @style: an XSLT style sheet 357 * @URI: the computed URI of the document 358 * 359 * Try to load a stylesheet document within the XSLT transformation context 360 * 361 * Returns the new xsltDocumentPtr or NULL in case of error 362 */ 363xsltDocumentPtr 364xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) { 365 xsltDocumentPtr ret; 366 xmlDocPtr doc; 367 xsltSecurityPrefsPtr sec; 368 369 if ((style == NULL) || (URI == NULL)) 370 return(NULL); 371 372 /* 373 * Security framework check 374 */ 375 sec = xsltGetDefaultSecurityPrefs(); 376 if (sec != NULL) { 377 int res; 378 379 res = xsltCheckRead(sec, NULL, URI); 380 if (res == 0) { 381 xsltTransformError(NULL, NULL, NULL, 382 "xsltLoadStyleDocument: read rights for %s denied\n", 383 URI); 384 return(NULL); 385 } 386 } 387 388 /* 389 * Walk the context list to find the document if preparsed 390 */ 391 ret = style->docList; 392 while (ret != NULL) { 393 if ((ret->doc != NULL) && (ret->doc->URL != NULL) && 394 (xmlStrEqual(ret->doc->URL, URI))) 395 return(ret); 396 ret = ret->next; 397 } 398 399 doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS, 400 (void *) style, XSLT_LOAD_STYLESHEET); 401 if (doc == NULL) 402 return(NULL); 403 404 ret = xsltNewStyleDocument(style, doc); 405 return(ret); 406} 407 408/** 409 * xsltFindDocument: 410 * @ctxt: an XSLT transformation context 411 * @doc: a parsed XML document 412 * 413 * Try to find a document within the XSLT transformation context 414 * 415 * Returns the desired xsltDocumentPtr or NULL in case of error 416 */ 417xsltDocumentPtr 418xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) { 419 xsltDocumentPtr ret; 420 421 if ((ctxt == NULL) || (doc == NULL)) 422 return(NULL); 423 424 /* 425 * Walk the context list to find the document 426 */ 427 ret = ctxt->docList; 428 while (ret != NULL) { 429 if (ret->doc == doc) 430 return(ret); 431 ret = ret->next; 432 } 433 if (doc == ctxt->style->doc) 434 return(ctxt->document); 435 return(NULL); 436} 437 438