summaryrefslogtreecommitdiffstats
path: root/libxslt/documents.c
diff options
context:
space:
mode:
Diffstat (limited to 'libxslt/documents.c')
-rw-r--r--libxslt/documents.c434
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);
+}
+