Home | History | Annotate | Download | only in libxslt
      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