/* * 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 #include #include #include #include #include #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 #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); }