Skip to content
Snippets Groups Projects
SAX2.c 83.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * SAX2.c : Default SAX2 handler to build a tree.
     *
     * See Copyright for the status of this software.
     *
     * Daniel Veillard <daniel@veillard.com>
     */
    
    
    #define IN_LIBXML
    #include "libxml.h"
    #include <stdlib.h>
    #include <string.h>
    
    #include <stddef.h>
    
    #include <libxml/xmlmemory.h>
    #include <libxml/tree.h>
    #include <libxml/parser.h>
    #include <libxml/parserInternals.h>
    #include <libxml/valid.h>
    #include <libxml/entities.h>
    #include <libxml/xmlerror.h>
    #include <libxml/debugXML.h>
    #include <libxml/xmlIO.h>
    #include <libxml/SAX.h>
    #include <libxml/uri.h>
    #include <libxml/valid.h>
    #include <libxml/HTMLtree.h>
    #include <libxml/globals.h>
    
    
    /* Define SIZE_T_MAX unless defined through <limits.h>. */
    #ifndef SIZE_T_MAX
    # define SIZE_T_MAX     ((size_t)-1)
    #endif /* !SIZE_T_MAX */
    
    
    /* #define DEBUG_SAX2 */
    /* #define DEBUG_SAX2_TREE */
    
    /**
    
     * TODO:
     *
     * macro to flag unimplemented blocks
    
     * XML_CATALOG_PREFER user env to select between system/public preferred
    
     * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
     *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
     *> values "system" and "public".  I have made the default be "system" to
     *> match yours.
     */
    
    #define TODO								\
    
        xmlGenericError(xmlGenericErrorContext,				\
    	    "Unimplemented block at %s:%d\n",				\
                __FILE__, __LINE__);
    
    
    /*
     * xmlSAX2ErrMemory:
     * @ctxt:  an XML validation parser context
     * @msg:   a string to accompany the error message
     */
    
    static void LIBXML_ATTR_FORMAT(2,0)
    
    xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt, const char *msg) {
    
        xmlStructuredErrorFunc schannel = NULL;
        const char *str1 = "out of memory\n";
    
    
    	ctxt->errNo = XML_ERR_NO_MEMORY;
    	if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC))
    	    schannel = ctxt->sax->serror;
    	__xmlRaiseError(schannel,
    			ctxt->vctxt.error, ctxt->vctxt.userData,
    			ctxt, NULL, XML_FROM_PARSER, XML_ERR_NO_MEMORY,
    			XML_ERR_ERROR, NULL, 0, (const char *) str1,
    			NULL, NULL, 0, 0,
    			msg, (const char *) str1, NULL);
    
    	ctxt->errNo = XML_ERR_NO_MEMORY;
    	ctxt->instate = XML_PARSER_EOF;
    	ctxt->disableSAX = 1;
    
        } else {
    	__xmlRaiseError(schannel,
    			NULL, NULL,
    			ctxt, NULL, XML_FROM_PARSER, XML_ERR_NO_MEMORY,
    			XML_ERR_ERROR, NULL, 0, (const char *) str1,
    			NULL, NULL, 0, 0,
    			msg, (const char *) str1, NULL);
    
     * xmlValidError:
     * @ctxt:  an XML validation parser context
     * @error:  the error number
     * @msg:  the error message
     * @str1:  extra data
     * @str2:  extra data
     *
     * Handle a validation error
     */
    
    static void LIBXML_ATTR_FORMAT(3,0)
    
    xmlErrValid(xmlParserCtxtPtr ctxt, xmlParserErrors error,
                const char *msg, const char *str1, const char *str2)
    {
        xmlStructuredErrorFunc schannel = NULL;
    
        if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
            (ctxt->instate == XML_PARSER_EOF))
    	return;
    
        if (ctxt != NULL) {
    	ctxt->errNo = error;
    	if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC))
    	    schannel = ctxt->sax->serror;
    
    	__xmlRaiseError(schannel,
    			ctxt->vctxt.error, ctxt->vctxt.userData,
    			ctxt, NULL, XML_FROM_DTD, error,
    			XML_ERR_ERROR, NULL, 0, (const char *) str1,
    			(const char *) str2, NULL, 0, 0,
    			msg, (const char *) str1, (const char *) str2);
    	ctxt->valid = 0;
        } else {
    	__xmlRaiseError(schannel,
    			NULL, NULL,
    			ctxt, NULL, XML_FROM_DTD, error,
    			XML_ERR_ERROR, NULL, 0, (const char *) str1,
    			(const char *) str2, NULL, 0, 0,
    			msg, (const char *) str1, (const char *) str2);
    
     * xmlFatalErrMsg:
     * @ctxt:  an XML parser context
     * @error:  the error number
     * @msg:  the error message
     * @str1:  an error string
     * @str2:  an error string
     *
     * Handle a fatal parser error, i.e. violating Well-Formedness constraints
     */
    
    static void LIBXML_ATTR_FORMAT(3,0)
    
    xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
                   const char *msg, const xmlChar *str1, const xmlChar *str2)
    {
        if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
            (ctxt->instate == XML_PARSER_EOF))
    	return;
        if (ctxt != NULL)
    	ctxt->errNo = error;
        __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error,
    
                        XML_ERR_FATAL, NULL, 0,
    
    		    (const char *) str1, (const char *) str2,
    		    NULL, 0, 0, msg, str1, str2);
        if (ctxt != NULL) {
    	ctxt->wellFormed = 0;
    	ctxt->valid = 0;
    	if (ctxt->recovery == 0)
    	    ctxt->disableSAX = 1;
        }
    }
    
    /**
     * xmlWarnMsg:
     * @ctxt:  an XML parser context
     * @error:  the error number
     * @msg:  the error message
     * @str1:  an error string
     * @str2:  an error string
     *
     * Handle a parser warning
     */
    
    static void LIBXML_ATTR_FORMAT(3,0)
    
    xmlWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
                   const char *msg, const xmlChar *str1)
    {
        if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
            (ctxt->instate == XML_PARSER_EOF))
    	return;
        if (ctxt != NULL)
    	ctxt->errNo = error;
        __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error,
    
                        XML_ERR_WARNING, NULL, 0,
    
    		    (const char *) str1, NULL,
    		    NULL, 0, 0, msg, str1);
    }
    
    /**
     * xmlNsWarnMsg:
     * @ctxt:  an XML parser context
     * @error:  the error number
     * @msg:  the error message
     * @str1:  an error string
     *
     * Handle a namespace warning
     */
    
    static void LIBXML_ATTR_FORMAT(3,0)
    
    xmlNsWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
                 const char *msg, const xmlChar *str1, const xmlChar *str2)
    {
        if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
            (ctxt->instate == XML_PARSER_EOF))
    	return;
        if (ctxt != NULL)
    	ctxt->errNo = error;
        __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error,
    
                        XML_ERR_WARNING, NULL, 0,
    
    		    (const char *) str1, (const char *) str2,
    		    NULL, 0, 0, msg, str1, str2);
    }
    
    /**
    
     * xmlSAX2GetPublicId:
     * @ctx: the user data (XML parser context)
     *
     * Provides the public ID e.g. "-//SGMLSOURCE//DTD DEMO//EN"
     *
     * Returns a xmlChar *
     */
    const xmlChar *
    xmlSAX2GetPublicId(void *ctx ATTRIBUTE_UNUSED)
    {
        /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
        return(NULL);
    }
    
    /**
     * xmlSAX2GetSystemId:
     * @ctx: the user data (XML parser context)
     *
     * Provides the system ID, basically URL or filename e.g.
     * http://www.sgmlsource.com/dtds/memo.dtd
     *
     * Returns a xmlChar *
     */
    const xmlChar *
    xmlSAX2GetSystemId(void *ctx)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    
        if ((ctx == NULL) || (ctxt->input == NULL)) return(NULL);
    
        return((const xmlChar *) ctxt->input->filename);
    
    }
    
    /**
     * xmlSAX2GetLineNumber:
     * @ctx: the user data (XML parser context)
     *
     * Provide the line number of the current parsing point.
     *
     * Returns an int
     */
    int
    xmlSAX2GetLineNumber(void *ctx)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    
        if ((ctx == NULL) || (ctxt->input == NULL)) return(0);
    
        return(ctxt->input->line);
    }
    
    /**
     * xmlSAX2GetColumnNumber:
     * @ctx: the user data (XML parser context)
     *
     * Provide the column number of the current parsing point.
     *
     * Returns an int
     */
    int
    xmlSAX2GetColumnNumber(void *ctx)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    
        if ((ctx == NULL) || (ctxt->input == NULL)) return(0);
    
        return(ctxt->input->col);
    }
    
    /**
     * xmlSAX2IsStandalone:
     * @ctx: the user data (XML parser context)
     *
     * Is this document tagged standalone ?
     *
     * Returns 1 if true
     */
    int
    xmlSAX2IsStandalone(void *ctx)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    
        if ((ctx == NULL) || (ctxt->myDoc == NULL)) return(0);
    
        return(ctxt->myDoc->standalone == 1);
    }
    
    /**
     * xmlSAX2HasInternalSubset:
     * @ctx: the user data (XML parser context)
     *
     * Does this document has an internal subset
     *
     * Returns 1 if true
     */
    int
    xmlSAX2HasInternalSubset(void *ctx)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    
        if ((ctxt == NULL) || (ctxt->myDoc == NULL)) return(0);
    
        return(ctxt->myDoc->intSubset != NULL);
    }
    
    /**
     * xmlSAX2HasExternalSubset:
     * @ctx: the user data (XML parser context)
     *
     * Does this document has an external subset
     *
     * Returns 1 if true
     */
    int
    xmlSAX2HasExternalSubset(void *ctx)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    
        if ((ctxt == NULL) || (ctxt->myDoc == NULL)) return(0);
    
        return(ctxt->myDoc->extSubset != NULL);
    }
    
    /**
     * xmlSAX2InternalSubset:
     * @ctx:  the user data (XML parser context)
     * @name:  the root element name
     * @ExternalID:  the external ID
     * @SystemID:  the SYSTEM ID (e.g. filename or URL)
     *
     * Callback on internal subset declaration.
     */
    void
    xmlSAX2InternalSubset(void *ctx, const xmlChar *name,
    	       const xmlChar *ExternalID, const xmlChar *SystemID)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlDtdPtr dtd;
    
    #ifdef DEBUG_SAX
        xmlGenericError(xmlGenericErrorContext,
    	    "SAX.xmlSAX2InternalSubset(%s, %s, %s)\n",
                name, ExternalID, SystemID);
    #endif
    
        if (ctxt->myDoc == NULL)
    	return;
        dtd = xmlGetIntSubset(ctxt->myDoc);
        if (dtd != NULL) {
    	if (ctxt->html)
    	    return;
    	xmlUnlinkNode((xmlNodePtr) dtd);
    	xmlFreeDtd(dtd);
    	ctxt->myDoc->intSubset = NULL;
        }
    
        ctxt->myDoc->intSubset =
    
    	xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
    
        if (ctxt->myDoc->intSubset == NULL)
            xmlSAX2ErrMemory(ctxt, "xmlSAX2InternalSubset");
    
    }
    
    /**
     * xmlSAX2ExternalSubset:
     * @ctx: the user data (XML parser context)
     * @name:  the root element name
     * @ExternalID:  the external ID
     * @SystemID:  the SYSTEM ID (e.g. filename or URL)
     *
     * Callback on external subset declaration.
     */
    void
    xmlSAX2ExternalSubset(void *ctx, const xmlChar *name,
    	       const xmlChar *ExternalID, const xmlChar *SystemID)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    
    #ifdef DEBUG_SAX
        xmlGenericError(xmlGenericErrorContext,
    	    "SAX.xmlSAX2ExternalSubset(%s, %s, %s)\n",
                name, ExternalID, SystemID);
    #endif
        if (((ExternalID != NULL) || (SystemID != NULL)) &&
            (((ctxt->validate) || (ctxt->loadsubset != 0)) &&
    	 (ctxt->wellFormed && ctxt->myDoc))) {
    	/*
    	 * Try to fetch and parse the external subset.
    	 */
    	xmlParserInputPtr oldinput;
    	int oldinputNr;
    	int oldinputMax;
    	xmlParserInputPtr *oldinputTab;
    	xmlParserInputPtr input = NULL;
    	xmlCharEncoding enc;
    	int oldcharset;
    
    	const xmlChar *oldencoding;
    
    
    	/*
    	 * Ask the Entity resolver to load the damn thing
    	 */
    	if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
    	    input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID,
    	                                        SystemID);
    	if (input == NULL) {
    	    return;
    	}
    
    	xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID);
    
    	/*
    	 * make sure we won't destroy the main document context
    	 */
    	oldinput = ctxt->input;
    	oldinputNr = ctxt->inputNr;
    	oldinputMax = ctxt->inputMax;
    	oldinputTab = ctxt->inputTab;
    	oldcharset = ctxt->charset;
    
    	oldencoding = ctxt->encoding;
    	ctxt->encoding = NULL;
    
    
    	ctxt->inputTab = (xmlParserInputPtr *)
    	                 xmlMalloc(5 * sizeof(xmlParserInputPtr));
    	if (ctxt->inputTab == NULL) {
    
    	    xmlSAX2ErrMemory(ctxt, "xmlSAX2ExternalSubset");
    
    	    ctxt->input = oldinput;
    	    ctxt->inputNr = oldinputNr;
    	    ctxt->inputMax = oldinputMax;
    	    ctxt->inputTab = oldinputTab;
    	    ctxt->charset = oldcharset;
    
    	    ctxt->encoding = oldencoding;
    
    	    return;
    	}
    	ctxt->inputNr = 0;
    	ctxt->inputMax = 5;
    	ctxt->input = NULL;
    	xmlPushInput(ctxt, input);
    
    	/*
    	 * On the fly encoding conversion if needed
    	 */
    	if (ctxt->input->length >= 4) {
    	    enc = xmlDetectCharEncoding(ctxt->input->cur, 4);
    	    xmlSwitchEncoding(ctxt, enc);
    	}
    
    	if (input->filename == NULL)
    	    input->filename = (char *) xmlCanonicPath(SystemID);
    	input->line = 1;
    	input->col = 1;
    	input->base = ctxt->input->cur;
    	input->cur = ctxt->input->cur;
    	input->free = NULL;
    
    	/*
    	 * let's parse that entity knowing it's an external subset.
    	 */
    	xmlParseExternalSubset(ctxt, ExternalID, SystemID);
    
            /*
    	 * Free up the external entities
    	 */
    
    	while (ctxt->inputNr > 1)
    	    xmlPopInput(ctxt);
    	xmlFreeInputStream(ctxt->input);
            xmlFree(ctxt->inputTab);
    
    	/*
    	 * Restore the parsing context of the main entity
    	 */
    	ctxt->input = oldinput;
    	ctxt->inputNr = oldinputNr;
    	ctxt->inputMax = oldinputMax;
    	ctxt->inputTab = oldinputTab;
    	ctxt->charset = oldcharset;
    
    	if ((ctxt->encoding != NULL) &&
    	    ((ctxt->dict == NULL) ||
    	     (!xmlDictOwns(ctxt->dict, ctxt->encoding))))
    	    xmlFree((xmlChar *) ctxt->encoding);
    	ctxt->encoding = oldencoding;
    
    	/* ctxt->wellFormed = oldwellFormed; */
        }
    }
    
    /**
     * xmlSAX2ResolveEntity:
     * @ctx: the user data (XML parser context)
     * @publicId: The public ID of the entity
     * @systemId: The system ID of the entity
     *
     * The entity loader, to control the loading of external entities,
     * the application can either:
     *    - override this xmlSAX2ResolveEntity() callback in the SAX block
     *    - or better use the xmlSetExternalEntityLoader() function to
     *      set up it's own entity resolution routine
     *
     * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
     */
    xmlParserInputPtr
    xmlSAX2ResolveEntity(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlParserInputPtr ret;
        xmlChar *URI;
        const char *base = NULL;
    
    
        if (ctxt->input != NULL)
    	base = ctxt->input->filename;
        if (base == NULL)
    	base = ctxt->directory;
    
        URI = xmlBuildURI(systemId, (const xmlChar *) base);
    
    #ifdef DEBUG_SAX
        xmlGenericError(xmlGenericErrorContext,
    	    "SAX.xmlSAX2ResolveEntity(%s, %s)\n", publicId, systemId);
    #endif
    
        ret = xmlLoadExternalEntity((const char *) URI,
    				(const char *) publicId, ctxt);
        if (URI != NULL)
    	xmlFree(URI);
        return(ret);
    }
    
    /**
     * xmlSAX2GetEntity:
     * @ctx: the user data (XML parser context)
     * @name: The entity name
     *
     * Get an entity by name
     *
     * Returns the xmlEntityPtr if found.
     */
    xmlEntityPtr
    xmlSAX2GetEntity(void *ctx, const xmlChar *name)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlEntityPtr ret = NULL;
    
    
    #ifdef DEBUG_SAX
        xmlGenericError(xmlGenericErrorContext,
    	    "SAX.xmlSAX2GetEntity(%s)\n", name);
    #endif
    
        if (ctxt->inSubset == 0) {
    	ret = xmlGetPredefinedEntity(name);
    	if (ret != NULL)
    	    return(ret);
        }
        if ((ctxt->myDoc != NULL) && (ctxt->myDoc->standalone == 1)) {
    	if (ctxt->inSubset == 2) {
    	    ctxt->myDoc->standalone = 0;
    	    ret = xmlGetDocEntity(ctxt->myDoc, name);
    	    ctxt->myDoc->standalone = 1;
    	} else {
    	    ret = xmlGetDocEntity(ctxt->myDoc, name);
    	    if (ret == NULL) {
    		ctxt->myDoc->standalone = 0;
    		ret = xmlGetDocEntity(ctxt->myDoc, name);
    		if (ret != NULL) {
    
    		    xmlFatalErrMsg(ctxt, XML_ERR_NOT_STANDALONE,
    	 "Entity(%s) document marked standalone but requires external subset\n",
    				   name, NULL);
    
    		}
    		ctxt->myDoc->standalone = 1;
    	    }
    	}
        } else {
    	ret = xmlGetDocEntity(ctxt->myDoc, name);
        }
        return(ret);
    }
    
    /**
     * xmlSAX2GetParameterEntity:
     * @ctx: the user data (XML parser context)
     * @name: The entity name
     *
     * Get a parameter entity by name
     *
     * Returns the xmlEntityPtr if found.
     */
    xmlEntityPtr
    xmlSAX2GetParameterEntity(void *ctx, const xmlChar *name)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlEntityPtr ret;
    
    
    #ifdef DEBUG_SAX
        xmlGenericError(xmlGenericErrorContext,
    	    "SAX.xmlSAX2GetParameterEntity(%s)\n", name);
    #endif
    
        ret = xmlGetParameterEntity(ctxt->myDoc, name);
        return(ret);
    }
    
    
    /**
     * xmlSAX2EntityDecl:
     * @ctx: the user data (XML parser context)
    
     * @name:  the entity name
     * @type:  the entity type
    
     * @publicId: The public ID of the entity
     * @systemId: The system ID of the entity
     * @content: the entity value (without processing).
     *
     * An entity definition has been parsed
     */
    void
    xmlSAX2EntityDecl(void *ctx, const xmlChar *name, int type,
              const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
    {
        xmlEntityPtr ent;
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    
    
    #ifdef DEBUG_SAX
        xmlGenericError(xmlGenericErrorContext,
    	    "SAX.xmlSAX2EntityDecl(%s, %d, %s, %s, %s)\n",
                name, type, publicId, systemId, content);
    #endif
        if (ctxt->inSubset == 1) {
    	ent = xmlAddDocEntity(ctxt->myDoc, name, type, publicId,
    		              systemId, content);
    
    	if ((ent == NULL) && (ctxt->pedantic))
    	    xmlWarnMsg(ctxt, XML_WAR_ENTITY_REDEFINED,
    	     "Entity(%s) already defined in the internal subset\n",
    	               name);
    
    	if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
    	    xmlChar *URI;
    	    const char *base = NULL;
    
    	    if (ctxt->input != NULL)
    		base = ctxt->input->filename;
    	    if (base == NULL)
    		base = ctxt->directory;
    
    	    URI = xmlBuildURI(systemId, (const xmlChar *) base);
    	    ent->URI = URI;
    	}
        } else if (ctxt->inSubset == 2) {
    	ent = xmlAddDtdEntity(ctxt->myDoc, name, type, publicId,
    		              systemId, content);
    	if ((ent == NULL) && (ctxt->pedantic) &&
    	    (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
    
    	    ctxt->sax->warning(ctxt->userData,
    
    	     "Entity(%s) already defined in the external subset\n", name);
    	if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
    	    xmlChar *URI;
    	    const char *base = NULL;
    
    	    if (ctxt->input != NULL)
    		base = ctxt->input->filename;
    	    if (base == NULL)
    		base = ctxt->directory;
    
    	    URI = xmlBuildURI(systemId, (const xmlChar *) base);
    	    ent->URI = URI;
    	}
        } else {
    
    	xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_PROCESSING,
    	               "SAX.xmlSAX2EntityDecl(%s) called while not in subset\n",
    		       name, NULL);
    
        }
    }
    
    /**
     * xmlSAX2AttributeDecl:
     * @ctx: the user data (XML parser context)
     * @elem:  the name of the element
    
     * @fullname:  the attribute name
     * @type:  the attribute type
    
     * @def:  the type of default value
     * @defaultValue: the attribute default value
     * @tree:  the tree of enumerated value set
     *
     * An attribute definition has been parsed
     */
    void
    xmlSAX2AttributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname,
                  int type, int def, const xmlChar *defaultValue,
    	      xmlEnumerationPtr tree)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlAttributePtr attr;
        xmlChar *name = NULL, *prefix = NULL;
    
    
        /* Avoid unused variable warning if features are disabled. */
        (void) attr;
    
    
        if ((ctxt == NULL) || (ctxt->myDoc == NULL))
            return;
    
    
    #ifdef DEBUG_SAX
        xmlGenericError(xmlGenericErrorContext,
    	    "SAX.xmlSAX2AttributeDecl(%s, %s, %d, %d, %s, ...)\n",
                elem, fullname, type, def, defaultValue);
    #endif
    
        if ((xmlStrEqual(fullname, BAD_CAST "xml:id")) &&
            (type != XML_ATTRIBUTE_ID)) {
    	/*
    	 * Raise the error but keep the validity flag
    	 */
    	int tmp = ctxt->valid;
    	xmlErrValid(ctxt, XML_DTD_XMLID_TYPE,
    	      "xml:id : attribute type should be ID\n", NULL, NULL);
    	ctxt->valid = tmp;
        }
    
        /* TODO: optimize name/prefix allocation */
    
        name = xmlSplitQName(ctxt, fullname, &prefix);
        ctxt->vctxt.valid = 1;
        if (ctxt->inSubset == 1)
    	attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem,
    	       name, prefix, (xmlAttributeType) type,
    	       (xmlAttributeDefault) def, defaultValue, tree);
        else if (ctxt->inSubset == 2)
    	attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, elem,
    
    	   name, prefix, (xmlAttributeType) type,
    
    	   (xmlAttributeDefault) def, defaultValue, tree);
        else {
    
            xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
    	     "SAX.xmlSAX2AttributeDecl(%s) called while not in subset\n",
    	               name, NULL);
    
    	xmlFree(name);
    
        if (ctxt->vctxt.valid == 0)
    	ctxt->valid = 0;
        if ((attr != NULL) && (ctxt->validate) && (ctxt->wellFormed) &&
    
            (ctxt->myDoc->intSubset != NULL))
    
    	ctxt->valid &= xmlValidateAttributeDecl(&ctxt->vctxt, ctxt->myDoc,
    	                                        attr);
    
    #endif /* LIBXML_VALID_ENABLED */
    
        if (prefix != NULL)
    	xmlFree(prefix);
        if (name != NULL)
    	xmlFree(name);
    }
    
    /**
     * xmlSAX2ElementDecl:
     * @ctx: the user data (XML parser context)
    
     * @name:  the element name
     * @type:  the element type
    
     * @content: the element value tree
     *
     * An element definition has been parsed
     */
    void
    xmlSAX2ElementDecl(void *ctx, const xmlChar * name, int type,
                xmlElementContentPtr content)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlElementPtr elem = NULL;
    
    
        /* Avoid unused variable warning if features are disabled. */
        (void) elem;
    
    
        if ((ctxt == NULL) || (ctxt->myDoc == NULL))
            return;
    
    
    #ifdef DEBUG_SAX
        xmlGenericError(xmlGenericErrorContext,
                        "SAX.xmlSAX2ElementDecl(%s, %d, ...)\n", name, type);
    #endif
    
        if (ctxt->inSubset == 1)
            elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->intSubset,
                                     name, (xmlElementTypeVal) type, content);
        else if (ctxt->inSubset == 2)
            elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->extSubset,
                                     name, (xmlElementTypeVal) type, content);
        else {
    
            xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
    	     "SAX.xmlSAX2ElementDecl(%s) called while not in subset\n",
    	               name, NULL);
    
        if (elem == NULL)
            ctxt->valid = 0;
        if (ctxt->validate && ctxt->wellFormed &&
            ctxt->myDoc && ctxt->myDoc->intSubset)
            ctxt->valid &=
                xmlValidateElementDecl(&ctxt->vctxt, ctxt->myDoc, elem);
    
    #endif /* LIBXML_VALID_ENABLED */
    
    }
    
    /**
     * xmlSAX2NotationDecl:
     * @ctx: the user data (XML parser context)
     * @name: The name of the notation
     * @publicId: The public ID of the entity
     * @systemId: The system ID of the entity
     *
     * What to do when a notation declaration has been parsed.
     */
    void
    xmlSAX2NotationDecl(void *ctx, const xmlChar *name,
    	     const xmlChar *publicId, const xmlChar *systemId)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlNotationPtr nota = NULL;
    
    
        /* Avoid unused variable warning if features are disabled. */
        (void) nota;
    
    
        if ((ctxt == NULL) || (ctxt->myDoc == NULL))
            return;
    
    
    #ifdef DEBUG_SAX
        xmlGenericError(xmlGenericErrorContext,
    	    "SAX.xmlSAX2NotationDecl(%s, %s, %s)\n", name, publicId, systemId);
    #endif
    
        if ((publicId == NULL) && (systemId == NULL)) {
    
    	xmlFatalErrMsg(ctxt, XML_ERR_NOTATION_PROCESSING,
    	     "SAX.xmlSAX2NotationDecl(%s) externalID or PublicID missing\n",
    	               name, NULL);
    
    	return;
        } else if (ctxt->inSubset == 1)
    	nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
                                  publicId, systemId);
        else if (ctxt->inSubset == 2)
    	nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, name,
                                  publicId, systemId);
        else {
    
    	xmlFatalErrMsg(ctxt, XML_ERR_NOTATION_PROCESSING,
    	     "SAX.xmlSAX2NotationDecl(%s) called while not in subset\n",
    	               name, NULL);
    
        if (nota == NULL) ctxt->valid = 0;
    
        if ((ctxt->validate) && (ctxt->wellFormed) &&
            (ctxt->myDoc->intSubset != NULL))
    
    	ctxt->valid &= xmlValidateNotationDecl(&ctxt->vctxt, ctxt->myDoc,
    	                                       nota);
    
    #endif /* LIBXML_VALID_ENABLED */
    
    }
    
    /**
     * xmlSAX2UnparsedEntityDecl:
     * @ctx: the user data (XML parser context)
     * @name: The name of the entity
     * @publicId: The public ID of the entity
     * @systemId: The system ID of the entity
     * @notationName: the name of the notation
     *
     * What to do when an unparsed entity declaration is parsed
     */
    void
    xmlSAX2UnparsedEntityDecl(void *ctx, const xmlChar *name,
    		   const xmlChar *publicId, const xmlChar *systemId,
    		   const xmlChar *notationName)
    {
        xmlEntityPtr ent;
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    
    #ifdef DEBUG_SAX
        xmlGenericError(xmlGenericErrorContext,
    	    "SAX.xmlSAX2UnparsedEntityDecl(%s, %s, %s, %s)\n",
                name, publicId, systemId, notationName);
    #endif
        if (ctxt->inSubset == 1) {
    	ent = xmlAddDocEntity(ctxt->myDoc, name,
    			XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
    			publicId, systemId, notationName);
    	if ((ent == NULL) && (ctxt->pedantic) &&
    	    (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
    
    	    ctxt->sax->warning(ctxt->userData,
    
    	     "Entity(%s) already defined in the internal subset\n", name);
    	if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
    	    xmlChar *URI;
    	    const char *base = NULL;
    
    	    if (ctxt->input != NULL)
    		base = ctxt->input->filename;
    	    if (base == NULL)
    		base = ctxt->directory;
    
    	    URI = xmlBuildURI(systemId, (const xmlChar *) base);
    	    ent->URI = URI;
    	}
        } else if (ctxt->inSubset == 2) {
    	ent = xmlAddDtdEntity(ctxt->myDoc, name,
    			XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
    			publicId, systemId, notationName);
    	if ((ent == NULL) && (ctxt->pedantic) &&
    	    (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
    
    	    ctxt->sax->warning(ctxt->userData,
    
    	     "Entity(%s) already defined in the external subset\n", name);
    	if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
    	    xmlChar *URI;
    	    const char *base = NULL;
    
    	    if (ctxt->input != NULL)
    		base = ctxt->input->filename;
    	    if (base == NULL)
    		base = ctxt->directory;
    
    	    URI = xmlBuildURI(systemId, (const xmlChar *) base);
    	    ent->URI = URI;
    	}
        } else {
    
            xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
    	     "SAX.xmlSAX2UnparsedEntityDecl(%s) called while not in subset\n",
    	               name, NULL);
    
        }
    }
    
    /**
     * xmlSAX2SetDocumentLocator:
     * @ctx: the user data (XML parser context)
     * @loc: A SAX Locator
     *
     * Receive the document locator at startup, actually xmlDefaultSAXLocator
     * Everything is available on the context, so this is useless in our case.
     */
    void
    xmlSAX2SetDocumentLocator(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
    {
        /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
    #ifdef DEBUG_SAX
        xmlGenericError(xmlGenericErrorContext,
    	    "SAX.xmlSAX2SetDocumentLocator()\n");
    #endif
    }
    
    /**
     * xmlSAX2StartDocument:
     * @ctx: the user data (XML parser context)
     *
     * called when the document start being processed.
     */
    void
    xmlSAX2StartDocument(void *ctx)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlDocPtr doc;
    
    
    #ifdef DEBUG_SAX
        xmlGenericError(xmlGenericErrorContext,
    	    "SAX.xmlSAX2StartDocument()\n");
    #endif
        if (ctxt->html) {
    #ifdef LIBXML_HTML_ENABLED
    	if (ctxt->myDoc == NULL)
    	    ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL);
    	if (ctxt->myDoc == NULL) {
    
    	    xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
    
    Gaurav's avatar
    Gaurav committed
    	ctxt->myDoc->properties = XML_DOC_HTML;
    	ctxt->myDoc->parseFlags = ctxt->options;
    
    #else
            xmlGenericError(xmlGenericErrorContext,
    		"libxml2 built without HTML support\n");
    	ctxt->errNo = XML_ERR_INTERNAL_ERROR;
    	ctxt->instate = XML_PARSER_EOF;
    	ctxt->disableSAX = 1;
    	return;
    #endif
        } else {
    	doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
    	if (doc != NULL) {
    
    	    doc->properties = 0;
    	    if (ctxt->options & XML_PARSE_OLD10)
    	        doc->properties |= XML_DOC_OLD10;
    	    doc->parseFlags = ctxt->options;
    
    	    if (ctxt->encoding != NULL)
    		doc->encoding = xmlStrdup(ctxt->encoding);
    	    else
    		doc->encoding = NULL;
    	    doc->standalone = ctxt->standalone;
    	} else {
    
    	    xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
    
    	if ((ctxt->dictNames) && (doc != NULL)) {
    
        }
        if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) &&
    	(ctxt->input != NULL) && (ctxt->input->filename != NULL)) {
    
    	ctxt->myDoc->URL = xmlPathToURI((const xmlChar *)ctxt->input->filename);
    
    	    xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
    
        }
    }
    
    /**
     * xmlSAX2EndDocument:
     * @ctx: the user data (XML parser context)
     *
     * called when the document end has been detected.