root/third_party/libxslt/libxslt/documents.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xsltDocDefaultLoaderFunc
  2. xsltSetLoaderFunc
  3. xsltNewDocument
  4. xsltNewStyleDocument
  5. xsltFreeStyleDocuments
  6. xsltFreeDocuments
  7. xsltLoadDocument
  8. xsltLoadStyleDocument
  9. xsltFindDocument

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


/* [<][>][^][v][top][bottom][index][help] */