diff options
Diffstat (limited to 'libxslt/documents.c')
-rw-r--r-- | libxslt/documents.c | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/libxslt/documents.c b/libxslt/documents.c new file mode 100644 index 0000000..3f3a731 --- /dev/null +++ b/libxslt/documents.c @@ -0,0 +1,434 @@ +/* + * documents.c: Implementation of the documents handling + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include <string.h> + +#include <libxml/xmlmemory.h> +#include <libxml/tree.h> +#include <libxml/hash.h> +#include <libxml/parser.h> +#include <libxml/parserInternals.h> +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "documents.h" +#include "transform.h" +#include "imports.h" +#include "keys.h" +#include "security.h" + +#ifdef LIBXML_XINCLUDE_ENABLED +#include <libxml/xinclude.h> +#endif + +#define WITH_XSLT_DEBUG_DOCUMENTS + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_DOCUMENTS +#endif + +/************************************************************************ + * * + * Hooks for the document loader * + * * + ************************************************************************/ + +/** + * xsltDocDefaultLoaderFunc: + * @URI: the URI of the document to load + * @dict: the dictionary to use when parsing that document + * @options: parsing options, a set of xmlParserOption + * @ctxt: the context, either a stylesheet or a transformation context + * @type: the xsltLoadType indicating the kind of loading required + * + * Default function to load document not provided by the compilation or + * transformation API themselve, for example when an xsl:import, + * xsl:include is found at compilation time or when a document() + * call is made at runtime. + * + * Returns the pointer to the document (which will be modified and + * freed by the engine later), or NULL in case of error. + */ +static xmlDocPtr +xsltDocDefaultLoaderFunc(const xmlChar * URI, xmlDictPtr dict, int options, + void *ctxt ATTRIBUTE_UNUSED, + xsltLoadType type ATTRIBUTE_UNUSED) +{ + xmlParserCtxtPtr pctxt; + xmlParserInputPtr inputStream; + xmlDocPtr doc; + + pctxt = xmlNewParserCtxt(); + if (pctxt == NULL) + return(NULL); + if ((dict != NULL) && (pctxt->dict != NULL)) { + xmlDictFree(pctxt->dict); + pctxt->dict = NULL; + } + if (dict != NULL) { + pctxt->dict = dict; + xmlDictReference(pctxt->dict); +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "Reusing dictionary for document\n"); +#endif + } + xmlCtxtUseOptions(pctxt, options); + inputStream = xmlLoadExternalEntity((const char *) URI, NULL, pctxt); + if (inputStream == NULL) { + xmlFreeParserCtxt(pctxt); + return(NULL); + } + inputPush(pctxt, inputStream); + if (pctxt->directory == NULL) + pctxt->directory = xmlParserGetDirectory((const char *) URI); + + xmlParseDocument(pctxt); + + if (pctxt->wellFormed) { + doc = pctxt->myDoc; + } + else { + doc = NULL; + xmlFreeDoc(pctxt->myDoc); + pctxt->myDoc = NULL; + } + xmlFreeParserCtxt(pctxt); + + return(doc); +} + + +xsltDocLoaderFunc xsltDocDefaultLoader = xsltDocDefaultLoaderFunc; + +/** + * xsltSetLoaderFunc: + * @f: the new function to handle document loading. + * + * Set the new function to load document, if NULL it resets it to the + * default function. + */ + +void +xsltSetLoaderFunc(xsltDocLoaderFunc f) { + if (f == NULL) + xsltDocDefaultLoader = xsltDocDefaultLoaderFunc; + else + xsltDocDefaultLoader = f; +} + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ + +/** + * xsltNewDocument: + * @ctxt: an XSLT transformation context (or NULL) + * @doc: a parsed XML document + * + * Register a new document, apply key computations + * + * Returns a handler to the document + */ +xsltDocumentPtr +xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) { + xsltDocumentPtr cur; + + cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument)); + if (cur == NULL) { + xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, + "xsltNewDocument : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltDocument)); + cur->doc = doc; + if (ctxt != NULL) { + if (! XSLT_IS_RES_TREE_FRAG(doc)) { + cur->next = ctxt->docList; + ctxt->docList = cur; + } + /* + * A key with a specific name for a specific document + * will only be computed if there's a call to the key() + * function using that specific name for that specific + * document. I.e. computation of keys will be done in + * xsltGetKey() (keys.c) on an on-demand basis. + * + * xsltInitCtxtKeys(ctxt, cur); not called here anymore + */ + } + return(cur); +} + +/** + * xsltNewStyleDocument: + * @style: an XSLT style sheet + * @doc: a parsed XML document + * + * Register a new document, apply key computations + * + * Returns a handler to the document + */ +xsltDocumentPtr +xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) { + xsltDocumentPtr cur; + + cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument)); + if (cur == NULL) { + xsltTransformError(NULL, style, (xmlNodePtr) doc, + "xsltNewStyleDocument : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltDocument)); + cur->doc = doc; + if (style != NULL) { + cur->next = style->docList; + style->docList = cur; + } + return(cur); +} + +/** + * xsltFreeStyleDocuments: + * @style: an XSLT stylesheet (representing a stylesheet-level) + * + * Frees the node-trees (and xsltDocument structures) of all + * stylesheet-modules of the stylesheet-level represented by + * the given @style. + */ +void +xsltFreeStyleDocuments(xsltStylesheetPtr style) { + xsltDocumentPtr doc, cur; +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + xsltNsMapPtr nsMap; +#endif + + if (style == NULL) + return; + +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + if (XSLT_HAS_INTERNAL_NSMAP(style)) + nsMap = XSLT_GET_INTERNAL_NSMAP(style); + else + nsMap = NULL; +#endif + + cur = style->docList; + while (cur != NULL) { + doc = cur; + cur = cur->next; +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + /* + * Restore all changed namespace URIs of ns-decls. + */ + if (nsMap) + xsltRestoreDocumentNamespaces(nsMap, doc->doc); +#endif + xsltFreeDocumentKeys(doc); + if (!doc->main) + xmlFreeDoc(doc->doc); + xmlFree(doc); + } +} + +/** + * xsltFreeDocuments: + * @ctxt: an XSLT transformation context + * + * Free up all the space used by the loaded documents + */ +void +xsltFreeDocuments(xsltTransformContextPtr ctxt) { + xsltDocumentPtr doc, cur; + + cur = ctxt->docList; + while (cur != NULL) { + doc = cur; + cur = cur->next; + xsltFreeDocumentKeys(doc); + if (!doc->main) + xmlFreeDoc(doc->doc); + xmlFree(doc); + } + cur = ctxt->styleList; + while (cur != NULL) { + doc = cur; + cur = cur->next; + xsltFreeDocumentKeys(doc); + if (!doc->main) + xmlFreeDoc(doc->doc); + xmlFree(doc); + } +} + +/** + * xsltLoadDocument: + * @ctxt: an XSLT transformation context + * @URI: the computed URI of the document + * + * Try to load a document (not a stylesheet) + * within the XSLT transformation context + * + * Returns the new xsltDocumentPtr or NULL in case of error + */ +xsltDocumentPtr +xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) { + xsltDocumentPtr ret; + xmlDocPtr doc; + + if ((ctxt == NULL) || (URI == NULL)) + return(NULL); + + /* + * Security framework check + */ + if (ctxt->sec != NULL) { + int res; + + res = xsltCheckRead(ctxt->sec, ctxt, URI); + if (res == 0) { + xsltTransformError(ctxt, NULL, NULL, + "xsltLoadDocument: read rights for %s denied\n", + URI); + return(NULL); + } + } + + /* + * Walk the context list to find the document if preparsed + */ + ret = ctxt->docList; + while (ret != NULL) { + if ((ret->doc != NULL) && (ret->doc->URL != NULL) && + (xmlStrEqual(ret->doc->URL, URI))) + return(ret); + ret = ret->next; + } + + doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions, + (void *) ctxt, XSLT_LOAD_DOCUMENT); + + if (doc == NULL) + return(NULL); + + if (ctxt->xinclude != 0) { +#ifdef LIBXML_XINCLUDE_ENABLED +#if LIBXML_VERSION >= 20603 + xmlXIncludeProcessFlags(doc, ctxt->parserOptions); +#else + xmlXIncludeProcess(doc); +#endif +#else + xsltTransformError(ctxt, NULL, NULL, + "xsltLoadDocument(%s) : XInclude processing not compiled in\n", + URI); +#endif + } + /* + * Apply white-space stripping if asked for + */ + if (xsltNeedElemSpaceHandling(ctxt)) + xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc)); + if (ctxt->debugStatus == XSLT_DEBUG_NONE) + xmlXPathOrderDocElems(doc); + + ret = xsltNewDocument(ctxt, doc); + return(ret); +} + +/** + * xsltLoadStyleDocument: + * @style: an XSLT style sheet + * @URI: the computed URI of the document + * + * Try to load a stylesheet document within the XSLT transformation context + * + * Returns the new xsltDocumentPtr or NULL in case of error + */ +xsltDocumentPtr +xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) { + xsltDocumentPtr ret; + xmlDocPtr doc; + xsltSecurityPrefsPtr sec; + + if ((style == NULL) || (URI == NULL)) + return(NULL); + + /* + * Security framework check + */ + sec = xsltGetDefaultSecurityPrefs(); + if (sec != NULL) { + int res; + + res = xsltCheckRead(sec, NULL, URI); + if (res == 0) { + xsltTransformError(NULL, NULL, NULL, + "xsltLoadStyleDocument: read rights for %s denied\n", + URI); + return(NULL); + } + } + + /* + * Walk the context list to find the document if preparsed + */ + ret = style->docList; + while (ret != NULL) { + if ((ret->doc != NULL) && (ret->doc->URL != NULL) && + (xmlStrEqual(ret->doc->URL, URI))) + return(ret); + ret = ret->next; + } + + doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS, + (void *) style, XSLT_LOAD_STYLESHEET); + if (doc == NULL) + return(NULL); + + ret = xsltNewStyleDocument(style, doc); + return(ret); +} + +/** + * xsltFindDocument: + * @ctxt: an XSLT transformation context + * @doc: a parsed XML document + * + * Try to find a document within the XSLT transformation context. + * This will not find document infos for temporary + * Result Tree Fragments. + * + * Returns the desired xsltDocumentPtr or NULL in case of error + */ +xsltDocumentPtr +xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) { + xsltDocumentPtr ret; + + if ((ctxt == NULL) || (doc == NULL)) + return(NULL); + + /* + * Walk the context list to find the document + */ + ret = ctxt->docList; + while (ret != NULL) { + if (ret->doc == doc) + return(ret); + ret = ret->next; + } + if (doc == ctxt->style->doc) + return(ctxt->document); + return(NULL); +} + |