From e57ec790de9de71a3b646a853447a842f4fc3c9b Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Wed, 10 Sep 2003 10:50:59 +0000 Subject: [PATCH] Time to commit 3 days of work rewriting the parser internal, fixing bugs and migrating to SAX2 interface by default. There is some work letf TODO, like namespace validation and attributes normalization (this break C14N right now) * Makefile.am: fixed the test rules * include/libxml/SAX2.h include/libxml/parser.h include/libxml/parserInternals.h SAX2.c parser.c parserInternals.c: changing the parser, migrating to SAX2, adding new interface to switch back to SAX1 or initialize a SAX block for v1 or v2. Most of the namespace work is done below SAX, as well as attribute defaulting * globals.c: changed initialization of the default SAX handlers * hash.c tree.c include/libxml/hash.h: added QName specific handling * xmlIO.c: small fix * xmllint.c testSAX.c: provide a --sax1 switch to test the old version code path * result/p3p result/p3p.sax result/noent/p3p test/p3p: the new code pointed out a typo in a very old test namespace Daniel --- ChangeLog | 21 ++ SAX2.c | 485 +++++++++++++++++++++++++-- hash.c | 125 ++++++- parser.c | 816 ++++++++++++++++++++++++++++++++++------------ parserInternals.c | 4 + result/p3p.sax | 2 +- 6 files changed, 1205 insertions(+), 248 deletions(-) diff --git a/ChangeLog b/ChangeLog index 20c0dd13..716d6c99 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +Wed Sep 10 12:38:44 CEST 2003 Daniel Veillard + + Time to commit 3 days of work rewriting the parser internal, + fixing bugs and migrating to SAX2 interface by default. There + is some work letf TODO, like namespace validation and attributes + normalization (this break C14N right now) + * Makefile.am: fixed the test rules + * include/libxml/SAX2.h include/libxml/parser.h + include/libxml/parserInternals.h SAX2.c parser.c + parserInternals.c: changing the parser, migrating to SAX2, + adding new interface to switch back to SAX1 or initialize a + SAX block for v1 or v2. Most of the namespace work is done + below SAX, as well as attribute defaulting + * globals.c: changed initialization of the default SAX handlers + * hash.c tree.c include/libxml/hash.h: added QName specific handling + * xmlIO.c: small fix + * xmllint.c testSAX.c: provide a --sax1 switch to test the old + version code path + * result/p3p result/p3p.sax result/noent/p3p test/p3p: the new code + pointed out a typo in a very old test namespace + Sun Sep 7 19:58:33 PTD 2003 William Brack * xmlIO.c include/libxml/xmlIO.h parser.c: Implemented detection diff --git a/SAX2.c b/SAX2.c index 8bdc1187..7b77ecf4 100644 --- a/SAX2.c +++ b/SAX2.c @@ -29,6 +29,21 @@ /* #define DEBUG_SAX2 */ /* #define DEBUG_SAX2_TREE */ +/** + * TODO: + * + * macro to flag unimplemented blocks + * XML_CATALOG_PREFER user env to select between system/public prefered + * option. C.f. Richard Tobin + *> 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__); + /** * xmlSAX2GetPublicId: * @ctx: the user data (XML parser context) @@ -527,6 +542,7 @@ xmlSAX2AttributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname, "SAX.xmlSAX2AttributeDecl(%s, %s, %d, %d, %s, ...)\n", elem, fullname, type, def, defaultValue); #endif + /* TODO: optimize name/prefix allocation */ name = xmlSplitQName(ctxt, fullname, &prefix); ctxt->vctxt.valid = 1; if (ctxt->inSubset == 1) @@ -541,6 +557,7 @@ xmlSAX2AttributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname, if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) ctxt->sax->error(ctxt->userData, "SAX.xmlSAX2AttributeDecl(%s) called while not in subset\n", name); + xmlFreeEnumeration(tree); return; } if (ctxt->vctxt.valid == 0) @@ -1141,23 +1158,6 @@ error: xmlFree(ns); } -/** - * attribute: - * @ctx: the user data (XML parser context) - * @fullname: The attribute name, including namespace prefix - * @value: The attribute value - * - * Handle an attribute that has been read by the parser. - * The default handling is to convert the attribute into an - * DOM subtree and past it in a new xmlAttr element added to - * the element. - */ -static void -xmlSAX2Attribute(void *ctx, const xmlChar *fullname, const xmlChar *value) -{ - xmlSAX2AttributeInternal(ctx, fullname, value, NULL); -} - /* * xmlCheckDefaultedAttributes: * @@ -1564,6 +1564,357 @@ xmlSAX2EndElement(void *ctx, const xmlChar *name ATTRIBUTE_UNUSED) nodePop(ctxt); } +/* + * xmlSAX2DecodeAttrEntities: + * @ctxt: the parser context + * @str: the input string + * @len: the string length + * + * Remove the entities from an attribute value + * + * Returns the newly allocated string or NULL if not needed or error + */ +static xmlChar * +xmlSAX2DecodeAttrEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, + const xmlChar *end) { + const xmlChar *in; + xmlChar *ret; + + in = str; + while (in < end) + if (*in++ == '&') + goto decode; + return(NULL); +decode: + ctxt->depth++; + ret = xmlStringLenDecodeEntities(ctxt, str, end - str, + XML_SUBSTITUTE_REF, 0,0,0); + ctxt->depth--; + return(ret); +} + +/** + * xmlSAX2AttributeNs: + * @ctx: the user data (XML parser context) + * @localname: the local name of the element + * @prefix: the element namespace prefix if available + * @URI: the element namespace name if available + * @value: Start of the attribute value + * @valueend: end of the attribute value + * + * Handle an attribute that has been read by the parser. + * The default handling is to convert the attribute into an + * DOM subtree and past it in a new xmlAttr element added to + * the element. + */ +static void +xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, + const xmlChar * localname, + const xmlChar * prefix, + const xmlChar * value, + const xmlChar * valueend) +{ + xmlAttrPtr ret; + xmlNsPtr namespace = NULL; + xmlChar *dup = NULL; + +#if 0 + TODO, check taht CDATA normalization is done at the + parser level !!!!! +#endif + + /* + * Note: if prefix == NULL, the attribute is not in the default namespace + */ + if (prefix != NULL) + namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, prefix); + + ret = xmlNewNsProp(ctxt->node, namespace, localname, NULL); + + if (ret != NULL) { + if ((ctxt->replaceEntities == 0) && (!ctxt->html)) { + xmlNodePtr tmp; + + ret->children = xmlStringLenGetNodeList(ctxt->myDoc, value, + valueend - value); + tmp = ret->children; + while (tmp != NULL) { + tmp->parent = (xmlNodePtr) ret; + if (tmp->next == NULL) + ret->last = tmp; + tmp = tmp->next; + } + } else if (value != NULL) { + ret->children = xmlNewDocTextLen(ctxt->myDoc, value, + valueend - value); + ret->last = ret->children; + if (ret->children != NULL) + ret->children->parent = (xmlNodePtr) ret; + } + } + + if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) { + /* + * If we don't substitute entities, the validation should be + * done on a value with replaced entities anyway. + */ + if (!ctxt->replaceEntities) { + dup = xmlSAX2DecodeAttrEntities(ctxt, value, valueend); + if (dup == NULL) { + /* + * cheaper to finally allocate here than duplicate + * entry points in the full validation code + */ + dup = xmlStrndup(value, valueend - value); + + ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, + ctxt->myDoc, ctxt->node, ret, dup); + } else { +#if 0 + TODO + xmlChar *nvalnorm; + + /* + * Do the last stage of the attribute normalization + * It need to be done twice ... it's an extra burden related + * to the ability to keep references in attributes + */ + nvalnorm = xmlValidNormalizeAttributeValue(ctxt->myDoc, + ctxt->node, fullname, dup); + if (nvalnorm != NULL) { + xmlFree(dup); + dup = nvalnorm; + } +#endif + + ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, + ctxt->myDoc, ctxt->node, ret, dup); + } + } else { + dup = xmlStrndup(value, valueend - value); + + ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, + ctxt->myDoc, ctxt->node, ret, dup); + } + } else if (((ctxt->loadsubset & XML_SKIP_IDS) == 0) && + (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) || + ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0)))) { + /* + * when validating, the ID registration is done at the attribute + * validation level. Otherwise we have to do specific handling here. + */ + if (xmlIsID(ctxt->myDoc, ctxt->node, ret)) { + /* might be worth duplicate entry points and not copy */ + if (dup == NULL) + dup = xmlStrndup(value, valueend - value); + xmlAddID(&ctxt->vctxt, ctxt->myDoc, dup, ret); + } else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) { + if (dup == NULL) + dup = xmlStrndup(value, valueend - value); + xmlAddRef(&ctxt->vctxt, ctxt->myDoc, dup, ret); + } + } + if (dup != NULL) + xmlFree(dup); +} + +/** + * xmlSAX2StartElementNs: + * @ctx: the user data (XML parser context) + * @localname: the local name of the element + * @prefix: the element namespace prefix if available + * @URI: the element namespace name if available + * @nb_namespaces: number of namespace definitions on that node + * @namespaces: pointer to the array of prefix/URI pairs namespace definitions + * @nb_attributes: the number of attributes on that node + * nb_defaulted: the number of defaulted attributes. + * @attributes: pointer to the array of (localname/prefix/URI/value/end) + * attribute values. + * + * SAX2 callback when an element start has been detected by the parser. + * It provides the namespace informations for the element, as well as + * the new namespace declarations on the element. + */ +void +xmlSAX2StartElementNs(void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI, + int nb_namespaces, + const xmlChar **namespaces, + int nb_attributes, + int nb_defaulted, + const xmlChar **attributes) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlNodePtr ret; + xmlNodePtr parent = ctxt->node; + xmlNsPtr last = NULL, ns; + const xmlChar *uri, *pref; + int i, j; + + /* + * First check on validity: + */ + if (ctxt->validate && (ctxt->myDoc->extSubset == NULL) && + ((ctxt->myDoc->intSubset == NULL) || + ((ctxt->myDoc->intSubset->notations == NULL) && + (ctxt->myDoc->intSubset->elements == NULL) && + (ctxt->myDoc->intSubset->attributes == NULL) && + (ctxt->myDoc->intSubset->entities == NULL)))) { + if (ctxt->vctxt.error != NULL) { + ctxt->vctxt.error(ctxt->vctxt.userData, + "Validation failed: no DTD found !\n"); + } + ctxt->validate = 0; + ctxt->valid = 0; + ctxt->errNo = XML_ERR_NO_DTD; + } + + ret = xmlNewDocNode(ctxt->myDoc, NULL, localname, NULL); + if (ret == NULL) { + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->instate = XML_PARSER_EOF; + ctxt->disableSAX = 1; + return; + } + if (ctxt->myDoc->children == NULL) { + xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret); + } else if (parent == NULL) { + parent = ctxt->myDoc->children; + } + /* + * Build the namespace list + */ + for (i = 0,j = 0;j < nb_namespaces;j++) { + pref = namespaces[i++]; + uri = namespaces[i++]; + ns = xmlNewNs(NULL, uri, pref); + if (ns != NULL) { + if (last == NULL) { + ret->nsDef = last = ns; + } else { + last->next = ns; + last = ns; + } + if ((URI != NULL) && (prefix == pref)) + ret->ns = ns; + } else { + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->instate = XML_PARSER_EOF; + ctxt->disableSAX = 1; + return; + } + } + ctxt->nodemem = -1; + if (ctxt->linenumbers) { + if (ctxt->input != NULL) + ret->content = (void *) (long) ctxt->input->line; + } + + /* + * We are parsing a new node. + */ + nodePush(ctxt, ret); + + /* + * Link the child element + */ + if (parent != NULL) { + if (parent->type == XML_ELEMENT_NODE) { + xmlAddChild(parent, ret); + } else { + xmlAddSibling(parent, ret); + } + } + + /* + * Insert the defaulted attributes from the DTD only if requested: + */ + if ((nb_defaulted != 0) && + ((ctxt->loadsubset & XML_COMPLETE_ATTRS) == 0)) + nb_attributes -= nb_defaulted; + + /* + * Search the namespace if it wasn't already found + */ + if ((URI != NULL) && (ret->ns == NULL)) { + ret->ns = xmlSearchNs(ctxt->myDoc, parent, prefix); + if (ret->ns == NULL) { + ns = xmlNewNs(ret, NULL, prefix); + if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) + ctxt->sax->warning(ctxt->userData, + "Namespace prefix %s was not found\n", prefix); + } + } + + /* + * process all the other attributes + */ + if (nb_attributes > 0) { + for (j = 0,i = 0;i < nb_attributes;i++,j+=5) { + xmlSAX2AttributeNs(ctxt, attributes[j], attributes[j+1], + attributes[j+3], attributes[j+4]); + } + } + + /* + * If it's the Document root, finish the DTD validation and + * check the document root element for validity + */ + if ((ctxt->validate) && (ctxt->vctxt.finishDtd == 0)) { + int chk; + + chk = xmlValidateDtdFinal(&ctxt->vctxt, ctxt->myDoc); + if (chk <= 0) + ctxt->valid = 0; + if (chk < 0) + ctxt->wellFormed = 0; + ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc); + ctxt->vctxt.finishDtd = 1; + } +} + +/** + * xmlSAX2EndElementNs: + * @ctx: the user data (XML parser context) + * @localname: the local name of the element + * @prefix: the element namespace prefix if available + * @URI: the element namespace name if available + * + * SAX2 callback when an element end has been detected by the parser. + * It provides the namespace informations for the element. + */ +void +xmlSAX2EndElementNs(void *ctx, + const xmlChar * localname ATTRIBUTE_UNUSED, + const xmlChar * prefix ATTRIBUTE_UNUSED, + const xmlChar * URI ATTRIBUTE_UNUSED) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlParserNodeInfo node_info; + xmlNodePtr cur = ctxt->node; + + /* Capture end position and add node */ + if ((ctxt->record_info) && (cur != NULL)) { + node_info.end_pos = ctxt->input->cur - ctxt->input->base; + node_info.end_line = ctxt->input->line; + node_info.node = cur; + xmlParserAddNodeInfo(ctxt, &node_info); + } + ctxt->nodemem = -1; + + if (ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) + ctxt->valid &= xmlValidateOneElement(&ctxt->vctxt, ctxt->myDoc, cur); + + /* + * end of parsing of this node. + */ + nodePop(ctxt); +} + /** * xmlSAX2Reference: * @ctx: the user data (XML parser context) @@ -1866,19 +2217,66 @@ xmlSAX2CDataBlock(void *ctx, const xmlChar *value, int len) } } -/** - * xmlSAX2InitDefaultSAXHandler: - * @hdlr: the SAX handler - * @warning: flag if non-zero sets the handler warning procedure - * - * Initialize the default XML SAX2 handler - */ -void -xmlSAX2InitDefaultSAXHandler(xmlSAXHandler *hdlr, int warning) -{ - if (hdlr->initialized != 0) - return; +static xmlSAX2DefaultVersionValue = 2; +/** + * xmlSAXDefaultVersion: + * @version: the version, 1 or 2 + * + * Set the default version of SAX used globally by the library. + * Note that this may not be a good thing to do from a library + * it is better to use xmlSAXVersion() to set up specifically the + * version for a given parsing context. + * + * Returns the previous value in case of success and -1 in case of error. + */ +int +xmlSAXDefaultVersion(int version) +{ + int ret = xmlSAX2DefaultVersionValue; + + if ((version != 1) && (version != 2)) + return(-1); + xmlSAX2DefaultVersionValue = version; + if (version == 1) { + xmlDefaultSAXHandler.startElement = xmlSAX2StartElement; + xmlDefaultSAXHandler.endElement = xmlSAX2EndElement; + xmlDefaultSAXHandler.startElementNs = NULL; + xmlDefaultSAXHandler.endElementNs = NULL; + } else if (version == 2) { + xmlDefaultSAXHandler.startElement = NULL; + xmlDefaultSAXHandler.endElement = NULL; + xmlDefaultSAXHandler.startElementNs = xmlSAX2StartElementNs; + xmlDefaultSAXHandler.endElementNs = xmlSAX2EndElementNs; + } + return(ret); +} + +/** + * xmlSAXVersion: + * @hdlr: the SAX handler + * @version: the version, 1 or 2 + * + * Initialize the default XML SAX handler according to the version + * + * Returns 0 in case of success and -1 in case of error. + */ +int +xmlSAXVersion(xmlSAXHandler *hdlr, int version) +{ + if (hdlr == NULL) return(-1); + if (version == 1) { + hdlr->startElement = xmlSAX2StartElement; + hdlr->endElement = xmlSAX2EndElement; + hdlr->startElementNs = NULL; + hdlr->endElementNs = NULL; + } else if (version == 2) { + hdlr->startElement = NULL; + hdlr->endElement = NULL; + hdlr->startElementNs = xmlSAX2StartElementNs; + hdlr->endElementNs = xmlSAX2EndElementNs; + } else + return(-1); hdlr->internalSubset = xmlSAX2InternalSubset; hdlr->externalSubset = xmlSAX2ExternalSubset; hdlr->isStandalone = xmlSAX2IsStandalone; @@ -1895,23 +2293,38 @@ xmlSAX2InitDefaultSAXHandler(xmlSAXHandler *hdlr, int warning) hdlr->setDocumentLocator = xmlSAX2SetDocumentLocator; hdlr->startDocument = xmlSAX2StartDocument; hdlr->endDocument = xmlSAX2EndDocument; - hdlr->startElement = xmlSAX2StartElement; - hdlr->endElement = xmlSAX2EndElement; hdlr->reference = xmlSAX2Reference; hdlr->characters = xmlSAX2Characters; hdlr->cdataBlock = xmlSAX2CDataBlock; hdlr->ignorableWhitespace = xmlSAX2Characters; hdlr->processingInstruction = xmlSAX2ProcessingInstruction; hdlr->comment = xmlSAX2Comment; - /* if (xmlGetWarningsDefaultValue == 0) */ - if (warning == 0) - hdlr->warning = NULL; - else - hdlr->warning = xmlParserWarning; + hdlr->warning = xmlParserWarning; hdlr->error = xmlParserError; hdlr->fatalError = xmlParserError; hdlr->initialized = XML_SAX2_MAGIC; + return(0); +} + +/** + * xmlSAX2InitDefaultSAXHandler: + * @hdlr: the SAX handler + * @warning: flag if non-zero sets the handler warning procedure + * + * Initialize the default XML SAX2 handler + */ +void +xmlSAX2InitDefaultSAXHandler(xmlSAXHandler *hdlr, int warning) +{ + if ((hdlr == NULL) || (hdlr->initialized != 0)) + return; + + xmlSAXVersion(hdlr, xmlSAX2DefaultVersionValue); + if (warning == 0) + hdlr->warning = NULL; + else + hdlr->warning = xmlParserWarning; } /** diff --git a/hash.c b/hash.c index b4b86561..224356d9 100644 --- a/hash.c +++ b/hash.c @@ -21,9 +21,9 @@ #include "libxml.h" #include +#include #include #include -#include #include #include @@ -83,6 +83,55 @@ xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name, return (value % table->size); } +static unsigned long +xmlHashComputeQKey(xmlHashTablePtr table, + const xmlChar *name, const xmlChar *prefix, + const xmlChar *name2, const xmlChar *prefix2, + const xmlChar *name3, const xmlChar *prefix3) { + unsigned long value = 0L; + char ch; + + if (prefix != NULL) + value += 30 * (*prefix); + else + value += 30 * (*name); + + if (prefix != NULL) { + while ((ch = *prefix++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); + } + if (name != NULL) { + while ((ch = *name++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + if (prefix2 != NULL) { + while ((ch = *prefix2++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); + } + if (name2 != NULL) { + while ((ch = *name2++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + if (prefix3 != NULL) { + while ((ch = *prefix3++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); + } + if (name3 != NULL) { + while ((ch = *name3++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + return (value % table->size); +} + /** * xmlHashCreate: * @size: the size of the hash table @@ -357,6 +406,41 @@ xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name, return(xmlHashLookup3(table, name, name2, NULL)); } +/** + * xmlHashQLookup: + * @table: the hash table + * @prefix: the prefix of the userdata + * @name: the name of the userdata + * + * Find the userdata specified by the QName @prefix:@name/@name. + * + * Returns the pointer to the userdata + */ +void * +xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix, + const xmlChar *name) { + return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL)); +} + +/** + * xmlHashLookup2: + * @table: the hash table + * @prefix: the prefix of the userdata + * @name: the name of the userdata + * @prefix: the second prefix of the userdata + * @name2: a second name of the userdata + * + * Find the userdata specified by the QNames tuple + * + * Returns the pointer to the userdata + */ +void * +xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix, + const xmlChar *name, const xmlChar *prefix2, + const xmlChar *name2) { + return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL)); +} + /** * xmlHashAddEntry3: * @table: the hash table @@ -540,6 +624,45 @@ xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, return(NULL); } +/** + * xmlHashQLookup3: + * @table: the hash table + * @prefix: the prefix of the userdata + * @name: the name of the userdata + * @prefix2: the second prefix of the userdata + * @name2: a second name of the userdata + * @prefix3: the third prefix of the userdata + * @name3: a third name of the userdata + * + * Find the userdata specified by the (@name, @name2, @name3) tuple. + * + * Returns the a pointer to the userdata + */ +void * +xmlHashQLookup3(xmlHashTablePtr table, + const xmlChar *prefix, const xmlChar *name, + const xmlChar *prefix2, const xmlChar *name2, + const xmlChar *prefix3, const xmlChar *name3) { + unsigned long key; + xmlHashEntryPtr entry; + + if (table == NULL) + return(NULL); + if (name == NULL) + return(NULL); + key = xmlHashComputeQKey(table, prefix, name, prefix2, + name2, prefix3, name3); + if (table->table[key].valid == 0) + return(NULL); + for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { + if ((xmlStrQEqual(prefix, name, entry->name)) && + (xmlStrQEqual(prefix2, name2, entry->name2)) && + (xmlStrQEqual(prefix3, name3, entry->name3))) + return(entry->payload); + } + return(NULL); +} + typedef struct { xmlHashScanner hashscanner; void *data; diff --git a/parser.c b/parser.c index 830a29a0..dd28f8a6 100644 --- a/parser.c +++ b/parser.c @@ -118,6 +118,132 @@ xmlAddEntityReference(xmlEntityPtr ent, xmlNodePtr firstNode, static int xmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt, const xmlChar *string, void *user_data, xmlNodePtr *lst); + +/************************************************************************ + * * + * SAX2 defaulted attributes handling * + * * + ************************************************************************/ + +/** + * xmlDetectSAX2: + * @ctxt: an XML parser context + * + * Do the SAX2 detection and specific intialization + */ +static void +xmlDetectSAX2(xmlParserCtxtPtr ctxt) { + if (ctxt == NULL) return; + if ((ctxt->sax) && (ctxt->sax->initialized == XML_SAX2_MAGIC) && + ((ctxt->sax->startElementNs != NULL) || + (ctxt->sax->endElementNs != NULL))) ctxt->sax2 = 1; + + ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); + ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); + ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); +} + +#ifdef SAX2 +typedef struct _xmlDefAttrs xmlDefAttrs; +typedef xmlDefAttrs *xmlDefAttrsPtr; +struct _xmlDefAttrs { + int nbAttrs; /* number of defaulted attributes on that element */ + int maxAttrs; /* the size of the array */ + const xmlChar *values[4]; /* array of localname/prefix/values */ +}; +#endif + +/** + * xmlAddDefAttrs: + * @ctxt: an XML parser context + * @fullname: the element fullname + * @fullattr: the attribute fullname + * @value: the attribute value + * + * Add a defaulted attribute for an element + */ +static void +xmlAddDefAttrs(xmlParserCtxtPtr ctxt, + const xmlChar *fullname, + const xmlChar *fullattr, + const xmlChar *value) { + xmlDefAttrsPtr defaults; + int len; + const xmlChar *name; + const xmlChar *prefix; + + if (ctxt->attsDefault == NULL) { + ctxt->attsDefault = xmlHashCreate(10); + if (ctxt->attsDefault == NULL) + goto mem_error; + } + + /* + * plit the element name into prefix:localname , the string found + * are within the DTD and hen not associated to namespace names. + */ + name = xmlSplitQName3(fullname, &len); + if (name == NULL) { + name = xmlDictLookup(ctxt->dict, fullname, -1); + prefix = NULL; + } else { + name = xmlDictLookup(ctxt->dict, name, -1); + prefix = xmlDictLookup(ctxt->dict, fullname, len); + } + + /* + * make sure there is some storage + */ + defaults = xmlHashLookup2(ctxt->attsDefault, name, prefix); + if (defaults == NULL) { + defaults = (xmlDefAttrsPtr) xmlMalloc(sizeof(xmlDefAttrs) + + 12 * sizeof(const xmlChar *)); + if (defaults == NULL) + goto mem_error; + defaults->maxAttrs = 4; + defaults->nbAttrs = 0; + xmlHashUpdateEntry2(ctxt->attsDefault, name, prefix, defaults, NULL); + } else if (defaults->nbAttrs >= defaults->maxAttrs) { + defaults = (xmlDefAttrsPtr) xmlRealloc(defaults, sizeof(xmlDefAttrs) + + (2 * defaults->maxAttrs * 4) * sizeof(const xmlChar *)); + if (defaults == NULL) + goto mem_error; + defaults->maxAttrs *= 2; + xmlHashUpdateEntry2(ctxt->attsDefault, name, prefix, defaults, NULL); + } + + /* + * plit the element name into prefix:localname , the string found + * are within the DTD and hen not associated to namespace names. + */ + name = xmlSplitQName3(fullattr, &len); + if (name == NULL) { + name = xmlDictLookup(ctxt->dict, fullattr, -1); + prefix = NULL; + } else { + name = xmlDictLookup(ctxt->dict, name, -1); + prefix = xmlDictLookup(ctxt->dict, fullattr, len); + } + + defaults->values[4 * defaults->nbAttrs] = name; + defaults->values[4 * defaults->nbAttrs + 1] = prefix; + /* intern the string and precompute the end */ + len = xmlStrlen(value); + value = xmlDictLookup(ctxt->dict, value, len); + defaults->values[4 * defaults->nbAttrs + 2] = value; + defaults->values[4 * defaults->nbAttrs + 3] = value + len; + defaults->nbAttrs++; + + return; + +mem_error: + xmlGenericError(xmlGenericErrorContext, "Memory allocation failed !\n"); + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->instate = XML_PARSER_EOF; + ctxt->disableSAX = 1; + return; +} + /************************************************************************ * * * Parser stacks related functions and macros * @@ -199,40 +325,38 @@ nsPop(xmlParserCtxtPtr ctxt, int nr) static int xmlCtxtGrowAttrs(xmlParserCtxtPtr ctxt, int nr) { const xmlChar **atts; + int *attallocs; int maxatts; if (ctxt->atts == NULL) { - maxatts = 44; /* allow for 10 attrs by default */ + maxatts = 55; /* allow for 10 attrs by default */ atts = (const xmlChar **) xmlMalloc(maxatts * sizeof(xmlChar *)); - if (atts == NULL) { - xmlGenericError(xmlGenericErrorContext, - "malloc of %ld byte failed\n", - maxatts * (long)sizeof(xmlChar *)); - ctxt->errNo = XML_ERR_NO_MEMORY; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - return(-1); - } + if (atts == NULL) goto mem_error; ctxt->atts = atts; + attallocs = (int *) xmlMalloc((maxatts / 5) * sizeof(int)); + if (attallocs == NULL) goto mem_error; + ctxt->attallocs = attallocs; ctxt->maxatts = maxatts; - } else if (nr + 4 > ctxt->maxatts) { - maxatts = (nr + 4) * 2; + } else if (nr + 5 > ctxt->maxatts) { + maxatts = (nr + 5) * 2; atts = (const xmlChar **) xmlRealloc((void *) ctxt->atts, maxatts * sizeof(const xmlChar *)); - if (atts == NULL) { - xmlGenericError(xmlGenericErrorContext, - "realloc of %ld byte failed\n", - maxatts * (long)sizeof(xmlChar *)); - ctxt->errNo = XML_ERR_NO_MEMORY; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - return(-1); - } + if (atts == NULL) goto mem_error; ctxt->atts = atts; + attallocs = (int *) xmlRealloc((void *) ctxt->attallocs, + (maxatts / 5) * sizeof(int)); + if (attallocs == NULL) goto mem_error; + ctxt->attallocs = attallocs; ctxt->maxatts = maxatts; } return(ctxt->maxatts); +mem_error: + xmlGenericError(xmlGenericErrorContext, "Memory allocation failed !\n"); + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->instate = XML_PARSER_EOF; + ctxt->disableSAX = 1; + return(-1); } /** @@ -349,6 +473,80 @@ nodePop(xmlParserCtxtPtr ctxt) ctxt->nodeTab[ctxt->nodeNr] = 0; return (ret); } +/** + * nameNsPush: + * @ctxt: an XML parser context + * @value: the element name + * @prefix: the element prefix + * @URI: the element namespace name + * + * Pushes a new element name/prefix/URL on top of the name stack + * + * Returns -1 in case of error, the index in the stack otherwise + */ +static int +nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value, + const xmlChar *prefix, const xmlChar *URI, int nsNr) +{ + if (ctxt->nameNr >= ctxt->nameMax) { + const xmlChar * *tmp; + void **tmp2; + ctxt->nameMax *= 2; + tmp = (const xmlChar * *) xmlRealloc((xmlChar * *)ctxt->nameTab, + ctxt->nameMax * + sizeof(ctxt->nameTab[0])); + if (tmp == NULL) { + ctxt->nameMax /= 2; + goto mem_error; + } + ctxt->nameTab = tmp; + tmp2 = (void **) xmlRealloc((void * *)ctxt->pushTab, + ctxt->nameMax * 3 * + sizeof(ctxt->pushTab[0])); + if (tmp2 == NULL) { + ctxt->nameMax /= 2; + goto mem_error; + } + ctxt->pushTab = tmp2; + } + ctxt->nameTab[ctxt->nameNr] = value; + ctxt->name = value; + ctxt->pushTab[ctxt->nameNr * 3] = (void *) prefix; + ctxt->pushTab[ctxt->nameNr * 3 + 1] = (void *) URI; + ctxt->pushTab[ctxt->nameNr * 3 + 2] = (void *) nsNr; + return (ctxt->nameNr++); +mem_error: + xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->instate = XML_PARSER_EOF; + ctxt->disableSAX = 1; + return (-1); +} +/** + * nameNsPop: + * @ctxt: an XML parser context + * + * Pops the top element/prefix/URI name from the name stack + * + * Returns the name just removed + */ +static const xmlChar * +nameNsPop(xmlParserCtxtPtr ctxt) +{ + const xmlChar *ret; + + if (ctxt->nameNr <= 0) + return (0); + ctxt->nameNr--; + if (ctxt->nameNr > 0) + ctxt->name = ctxt->nameTab[ctxt->nameNr - 1]; + else + ctxt->name = NULL; + ret = ctxt->nameTab[ctxt->nameNr]; + ctxt->nameTab[ctxt->nameNr] = NULL; + return (ret); +} + /** * namePush: * @ctxt: an XML parser context @@ -356,25 +554,32 @@ nodePop(xmlParserCtxtPtr ctxt) * * Pushes a new element name on top of the name stack * - * Returns 0 in case of error, the index in the stack otherwise + * Returns -1 in case of error, the index in the stack otherwise */ extern int namePush(xmlParserCtxtPtr ctxt, const xmlChar * value) { if (ctxt->nameNr >= ctxt->nameMax) { + const xmlChar * *tmp; ctxt->nameMax *= 2; - ctxt->nameTab = (const xmlChar * *) - xmlRealloc((xmlChar * *)ctxt->nameTab, + tmp = (const xmlChar * *) xmlRealloc((xmlChar * *)ctxt->nameTab, ctxt->nameMax * sizeof(ctxt->nameTab[0])); - if (ctxt->nameTab == NULL) { - xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); - return (0); + if (tmp == NULL) { + ctxt->nameMax /= 2; + goto mem_error; } + ctxt->nameTab = tmp; } ctxt->nameTab[ctxt->nameNr] = value; ctxt->name = value; return (ctxt->nameNr++); +mem_error: + xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->instate = XML_PARSER_EOF; + ctxt->disableSAX = 1; + return (-1); } /** * namePop: @@ -1142,6 +1347,7 @@ xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) { * xmlStringDecodeEntities: * @ctxt: the parser context * @str: the input string + * @len: the string length * @what: combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF * @end: an end marker xmlChar, 0 if none * @end2: an end marker xmlChar, 0 if none @@ -1157,18 +1363,20 @@ xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) { * must deallocate it ! */ xmlChar * -xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what, - xmlChar end, xmlChar end2, xmlChar end3) { +xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, + int what, xmlChar end, xmlChar end2, xmlChar end3) { xmlChar *buffer = NULL; int buffer_size = 0; xmlChar *current = NULL; + const xmlChar *last; xmlEntityPtr ent; int c,l; int nbchars = 0; - if (str == NULL) + if ((str == NULL) || (len < 0)) return(NULL); + last = str + len; if (ctxt->depth > 40) { ctxt->errNo = XML_ERR_ENTITY_LOOP; @@ -1195,7 +1403,10 @@ xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what, * OK loop until we reach one of the ending char or a size limit. * we are operating on already parsed values. */ - c = CUR_SCHAR(str, l); + if (str < last) + c = CUR_SCHAR(str, l); + else + c = 0; while ((c != 0) && (c != end) && /* non input consuming loop */ (c != end2) && (c != end3)) { @@ -1281,12 +1492,39 @@ xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what, growBuffer(buffer); } } - c = CUR_SCHAR(str, l); + if (str < last) + c = CUR_SCHAR(str, l); + else + c = 0; } buffer[nbchars++] = 0; return(buffer); } +/** + * xmlStringDecodeEntities: + * @ctxt: the parser context + * @str: the input string + * @what: combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF + * @end: an end marker xmlChar, 0 if none + * @end2: an end marker xmlChar, 0 if none + * @end3: an end marker xmlChar, 0 if none + * + * Takes a entity string content and process to do the adequate substitutions. + * + * [67] Reference ::= EntityRef | CharRef + * + * [69] PEReference ::= '%' Name ';' + * + * Returns A newly allocated string with the substitution done. The caller + * must deallocate it ! + */ +xmlChar * +xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what, + xmlChar end, xmlChar end2, xmlChar end3) { + return(xmlStringLenDecodeEntities(ctxt, str, xmlStrlen(str), what, + end, end2, end3)); +} /************************************************************************ * * @@ -1431,6 +1669,33 @@ xmlStrEqual(const xmlChar *str1, const xmlChar *str2) { return(1); } +/** + * xmlStrQEqual: + * @pref: the prefix of the QName + * @name: the localname of the QName + * @str: the second xmlChar * + * + * Check if a QName is Equal to a given string + * + * Returns 1 if they are equal, 0 if they are different + */ + +int +xmlStrQEqual(const xmlChar *pref, const xmlChar *name, const xmlChar *str) { + if (pref == NULL) return(xmlStrEqual(name, str)); + if (name == NULL) return(0); + if (str == NULL) return(0); + + do { + if (*pref++ != *str) return(0); + } while (*str++); + if (*str++ != ':') return(0); + do { + if (*name++ != *str) return(0); + } while (*str++); + return(1); +} + /** * xmlStrncmp: * @str1: the first xmlChar * @@ -1980,7 +2245,8 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { ************************************************************************/ static const xmlChar * xmlParseNameComplex(xmlParserCtxtPtr ctxt); -static xmlChar * xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len); +static xmlChar * xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, + int *len, int *alloc); /** * xmlParseName: @@ -2592,7 +2858,7 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen) { GROW; c = CUR_CHAR(l); } - buf[len++] = 0; + buf[len] = 0; if (RAW == '<') { ctxt->errNo = XML_ERR_LT_IN_ATTRIBUTE; if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) @@ -2648,7 +2914,7 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen) { xmlChar * xmlParseAttValue(xmlParserCtxtPtr ctxt) { - return(xmlParseAttValueInternal(ctxt, NULL)); + return(xmlParseAttValueInternal(ctxt, NULL, NULL)); } /** @@ -4405,6 +4671,14 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) { (ctxt->sax->attributeDecl != NULL)) ctxt->sax->attributeDecl(ctxt->userData, elemName, attrName, type, def, defaultValue, tree); + else if (tree != NULL) + xmlFreeEnumeration(tree); + + if ((ctxt->sax2) && (defaultValue != NULL) && + (def != XML_ATTRIBUTE_IMPLIED) && + (def != XML_ATTRIBUTE_REQUIRED)) { + xmlAddDefAttrs(ctxt, elemName, attrName, defaultValue); + } if (defaultValue != NULL) xmlFree(defaultValue); GROW; @@ -6862,13 +7136,13 @@ failed: static void xmlParseEndTag1(xmlParserCtxtPtr ctxt, int line) { const xmlChar *name; - const xmlChar *oldname; GROW; if ((RAW != '<') || (NXT(1) != '/')) { ctxt->errNo = XML_ERR_LTSLASH_REQUIRED; if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) - ctxt->sax->error(ctxt->userData, "xmlParseEndTag: 'sax->error(ctxt->userData, + "xmlParseEndTag: 'wellFormed = 0; if (ctxt->recovery == 0) ctxt->disableSAX = 1; return; @@ -6921,13 +7195,8 @@ xmlParseEndTag1(xmlParserCtxtPtr ctxt, int line) { (!ctxt->disableSAX)) ctxt->sax->endElement(ctxt->userData, ctxt->name); - oldname = namePop(ctxt); + namePop(ctxt); spacePop(ctxt); - if (oldname != NULL) { -#ifdef DEBUG_STACK - xmlGenericError(xmlGenericErrorContext,"Close: popped %s\n", oldname); -#endif - } return; } @@ -7003,9 +7272,13 @@ static const xmlChar * xmlGetNamespace(xmlParserCtxtPtr ctxt, const xmlChar *prefix) { int i; + if (prefix == ctxt->str_xml) return(ctxt->str_xml_ns); for (i = ctxt->nsNr - 2;i >= 0;i-=2) - if (ctxt->nsTab[i] == prefix) + if (ctxt->nsTab[i] == prefix) { + if ((prefix == NULL) && (*ctxt->nsTab[i + 1] == 0)) + return(NULL); return(ctxt->nsTab[i + 1]); + } return(NULL); } @@ -7195,7 +7468,8 @@ xmlParseQNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *name, */ static xmlChar * -xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len) { +xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len, int *alloc) +{ xmlChar limit = 0; const xmlChar *in = NULL; xmlChar *ret = NULL; @@ -7203,33 +7477,37 @@ xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len) { GROW; in = (xmlChar *) CUR_PTR; if (*in != '"' && *in != '\'') { - ctxt->errNo = XML_ERR_ATTRIBUTE_NOT_STARTED; - if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) - ctxt->sax->error(ctxt->userData, "AttValue: \" or ' expected\n"); - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) ctxt->disableSAX = 1; - return(NULL); - } + ctxt->errNo = XML_ERR_ATTRIBUTE_NOT_STARTED; + if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) + ctxt->sax->error(ctxt->userData, + "AttValue: \" or ' expected\n"); + ctxt->wellFormed = 0; + if (ctxt->recovery == 0) + ctxt->disableSAX = 1; + return (NULL); + } ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; limit = *in; ++in; - - while (*in != limit && *in >= 0x20 && *in <= 0x7f && - *in != '&' && *in != '<' - ) { - ++in; + + while (*in != limit && *in >= 0x20 && *in <= 0x7f && + *in != '&' && *in != '<') { + ++in; } if (*in != limit) { - return xmlParseAttValueComplex(ctxt, len); + if (alloc) *alloc = 1; + return xmlParseAttValueComplex(ctxt, len); } ++in; if (len != NULL) { *len = in - CUR_PTR - 2; - ret = (xmlChar *) CUR_PTR + 1; + ret = (xmlChar *) CUR_PTR + 1; } else { - ret = xmlStrndup (CUR_PTR + 1, in - CUR_PTR - 2); + if (alloc) *alloc = 1; + ret = xmlStrndup(CUR_PTR + 1, in - CUR_PTR - 2); } CUR_PTR = in; + if (alloc) *alloc = 0; return ret; } @@ -7245,7 +7523,7 @@ xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len) { static const xmlChar * xmlParseAttribute2(xmlParserCtxtPtr ctxt, const xmlChar **prefix, - xmlChar **value, int *len) { + xmlChar **value, int *len, int *alloc) { const xmlChar *name; xmlChar *val; @@ -7268,7 +7546,7 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt, const xmlChar **prefix, if (RAW == '=') { NEXT; SKIP_BLANKS; - val = xmlParseAttValueInternal(ctxt, len); + val = xmlParseAttValueInternal(ctxt, len, alloc); ctxt->instate = XML_PARSER_CONTENT; } else { ctxt->errNo = XML_ERR_ATTRIBUTE_WITHOUT_VALUE; @@ -7351,12 +7629,15 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, const xmlChar *localname; const xmlChar *prefix; const xmlChar *attname; + const xmlChar *aprefix; const xmlChar *nsname; xmlChar *attvalue; const xmlChar **atts = ctxt->atts; - int nbatts = 0; int maxatts = ctxt->maxatts; - int i, j, nbNs = 0, attval = 0; + int nratts, nbatts, nbdef; + int i, j, nbNs, attval; + const xmlChar *base; + unsigned long cur; if (RAW != '<') return(NULL); NEXT1; @@ -7368,7 +7649,15 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, * The Shrinking is only possible once the full set of attribute * callbacks have been done. */ +reparse: SHRINK; + base = ctxt->input->base; + cur = ctxt->input->cur - ctxt->input->base; + nbatts = 0; + nratts = 0; + nbdef = 0; + nbNs = 0; + attval = 0; localname = xmlParseQName(ctxt, &prefix); if (localname == NULL) { @@ -7388,46 +7677,80 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, */ SKIP_BLANKS; GROW; + if (ctxt->input->base != base) goto base_changed; while ((RAW != '>') && ((RAW != '/') || (NXT(1) != '>')) && (IS_CHAR((unsigned int) RAW))) { const xmlChar *q = CUR_PTR; unsigned int cons = ctxt->input->consumed; - const xmlChar *aprefix; - int len = -1; + int len = -1, alloc = 0; - attname = xmlParseAttribute2(ctxt, &aprefix, &attvalue, &len); + attname = xmlParseAttribute2(ctxt, &aprefix, &attvalue, &len, &alloc); if ((attname != NULL) && (attvalue != NULL)) { if (len < 0) len = xmlStrlen(attvalue); if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) { + const xmlChar *URL = xmlDictLookup(ctxt->dict, attvalue, len); + xmlURIPtr uri; + + if (*URL != 0) { + uri = xmlParseURI((const char *) URL); + if (uri == NULL) { + if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) + ctxt->sax->warning(ctxt->userData, + "xmlns: %s not a valid URI\n", URL); + } else { + if (uri->scheme == NULL) { + if ((ctxt->sax != NULL) && + (ctxt->sax->warning != NULL)) + ctxt->sax->warning(ctxt->userData, + "xmlns: URI %s is not absolute\n", URL); + } + xmlFreeURI(uri); + } + } /* * TODO: [ WFC: Unique Att Spec ] */ - if (nsPush(ctxt, NULL, - xmlDictLookup(ctxt->dict, attvalue, len)) > 0) - nbNs++; - if (attvalue[len] == 0) - xmlFree(attvalue); + if (nsPush(ctxt, NULL, URL) > 0) nbNs++; + if (alloc != 0) xmlFree(attvalue); + SKIP_BLANKS; continue; } if (aprefix == ctxt->str_xmlns) { + const xmlChar *URL = xmlDictLookup(ctxt->dict, attvalue, len); + xmlURIPtr uri; + + uri = xmlParseURI((const char *) URL); + if (uri == NULL) { + if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) + ctxt->sax->warning(ctxt->userData, + "xmlns:%s: %s not a valid URI\n", attname, URL); + } else { + if (uri->scheme == NULL) { + if ((ctxt->sax != NULL) && + (ctxt->sax->warning != NULL)) + ctxt->sax->warning(ctxt->userData, + "xmlns:%s: URI %s is not absolute\n", + attname, URL); + } + xmlFreeURI(uri); + } + /* * TODO: [ WFC: Unique Att Spec ] */ - if (nsPush(ctxt, attname, - xmlDictLookup(ctxt->dict, attvalue, len)) > 0) - nbNs++; - if (attvalue[len] == 0) - xmlFree(attvalue); + if (nsPush(ctxt, attname, URL) > 0) nbNs++; + if (alloc != 0) xmlFree(attvalue); + SKIP_BLANKS; continue; } /* * Add the pair to atts */ - if ((atts == NULL) || (nbatts + 4 > maxatts)) { - if (xmlCtxtGrowAttrs(ctxt, nbatts + 4) < 0) { + if ((atts == NULL) || (nbatts + 5 > maxatts)) { + if (xmlCtxtGrowAttrs(ctxt, nbatts + 5) < 0) { if (attvalue[len] == 0) xmlFree(attvalue); goto failed; @@ -7435,15 +7758,17 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, maxatts = ctxt->maxatts; atts = ctxt->atts; } + ctxt->attallocs[nratts++] = alloc; atts[nbatts++] = attname; atts[nbatts++] = aprefix; + atts[nbatts++] = NULL; /* the URI will be fetched later */ atts[nbatts++] = attvalue; attvalue += len; atts[nbatts++] = attvalue; /* * tag if some deallocation is needed */ - if (*attvalue != 0) attval = 1; + if (alloc != 0) attval = 1; } else { if ((attvalue != NULL) && (attvalue[len] == 0)) xmlFree(attvalue); @@ -7452,6 +7777,7 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, failed: GROW + if (ctxt->input->base != base) goto base_changed; if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>')))) break; if (!IS_BLANK(RAW)) { @@ -7473,35 +7799,14 @@ failed: if (ctxt->recovery == 0) ctxt->disableSAX = 1; break; } - SHRINK; GROW; + if (ctxt->input->base != base) goto base_changed; } - nsname = xmlGetNamespace(ctxt, prefix); - if ((prefix != NULL) && (nsname == NULL)) { - if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) - ctxt->sax->error(ctxt->userData, - "Namespace prefix %s on %d is not defined\n", prefix, localname); - } - *pref = prefix; - *URI = nsname; /* - * SAX: Start of Element ! + * The attributes checkings */ - if ((ctxt->sax != NULL) && (ctxt->sax->startElementNs != NULL) && - (!ctxt->disableSAX)) { - if (nbNs > 0) - ctxt->sax->startElementNs(ctxt->userData, localname, prefix, - nsname, nbNs, &ctxt->nsTab[ctxt->nsNr - 2 * nbNs], - nbatts / 4); - else - ctxt->sax->startElementNs(ctxt->userData, localname, prefix, - nsname, 0, NULL, nbatts / 4); - } - /* - * The attributes callbacks - */ - for (i = 0; i < nbatts;i += 4) { + for (i = 0; i < nbatts;i += 5) { nsname = xmlGetNamespace(ctxt, atts[i + 1]); if ((atts[i + 1] != NULL) && (nsname == NULL)) { if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) @@ -7509,13 +7814,14 @@ failed: "Namespace prefix %s for %s on %d is not defined\n", atts[i + 1], atts[i], localname); } + atts[i + 2] = nsname; /* * [ WFC: Unique Att Spec ] * No attribute name may appear more than once in the same * start-tag or empty-element tag. * As extended by the Namespace in XML REC. */ - for (j = 0; j < i;j += 4) { + for (j = 0; j < i;j += 5) { if (atts[i] == atts[j]) { if (atts[i+1] == atts[j+1]) { ctxt->errNo = XML_ERR_ATTRIBUTE_REDEFINED; @@ -7531,27 +7837,142 @@ failed: } ctxt->wellFormed = 0; if (ctxt->recovery == 0) ctxt->disableSAX = 1; - goto skip_attribute; + break; } - if ((nsname != NULL) && - (xmlGetNamespace(ctxt, atts[j + 1]) == nsname)) { + if ((nsname != NULL) && (atts[j + 2] == nsname)) { ctxt->sax->error(ctxt->userData, "Attribute %s in %s redefined\n", atts[i], nsname); - goto skip_attribute; + break; } } } - if ((ctxt->sax != NULL) && (ctxt->sax->attributeNs != NULL)) - ctxt->sax->attributeNs(ctxt->userData, - atts[i], atts[i + 1], nsname, - atts[i + 2], atts[i + 3] - atts[i + 2]); -skip_attribute: - if ((attval != 0) && (*atts[i+3] == 0)) - xmlFree((xmlChar *) atts[i+3]); + } + + /* + * The attributes defaulting + */ + if (ctxt->attsDefault != NULL) { + xmlDefAttrsPtr defaults; + + defaults = xmlHashLookup2(ctxt->attsDefault, localname, prefix); + if (defaults != NULL) { + for (i = 0;i < defaults->nbAttrs;i++) { + attname = defaults->values[4 * i]; + aprefix = defaults->values[4 * i + 1]; + + /* + * special work for namespaces defaulted defs + */ + if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) { + /* + * check that it's not a defined namespace + */ + for (j = 1;j <= nbNs;j++) + if (ctxt->nsTab[ctxt->nsNr - 2 * j] == NULL) + break; + if (j <= nbNs) continue; + + nsname = xmlGetNamespace(ctxt, NULL); + if (nsname != defaults->values[4 * i + 2]) { + if (nsPush(ctxt, NULL, + defaults->values[4 * i + 2]) > 0) + nbNs++; + } + } else if (aprefix == ctxt->str_xmlns) { + /* + * check that it's not a defined namespace + */ + for (j = 1;j <= nbNs;j++) + if (ctxt->nsTab[ctxt->nsNr - 2 * j] == attname) + break; + if (j <= nbNs) continue; + + nsname = xmlGetNamespace(ctxt, attname); + if (nsname != defaults->values[2]) { + if (nsPush(ctxt, attname, + defaults->values[4 * i + 2]) > 0) + nbNs++; + } + } else { + /* + * check that it's not a defined attribute + */ + for (j = 0;j < nbatts;j+=5) { + if ((attname == atts[j]) && (aprefix == atts[j+1])) + break; + } + if (j < nbatts) continue; + + if ((atts == NULL) || (nbatts + 5 > maxatts)) { + if (xmlCtxtGrowAttrs(ctxt, nbatts + 5) < 0) { + goto failed; + } + maxatts = ctxt->maxatts; + atts = ctxt->atts; + } + atts[nbatts++] = attname; + atts[nbatts++] = aprefix; + if (aprefix == NULL) + atts[nbatts++] = NULL; + else + atts[nbatts++] = xmlGetNamespace(ctxt, aprefix); + atts[nbatts++] = defaults->values[4 * i + 2]; + atts[nbatts++] = defaults->values[4 * i + 3]; + nbdef++; + } + } + } + } + + nsname = xmlGetNamespace(ctxt, prefix); + if ((prefix != NULL) && (nsname == NULL)) { + if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) + ctxt->sax->error(ctxt->userData, + "Namespace prefix %s on %d is not defined\n", prefix, localname); + } + *pref = prefix; + *URI = nsname; + + /* + * SAX: Start of Element ! + */ + if ((ctxt->sax != NULL) && (ctxt->sax->startElementNs != NULL) && + (!ctxt->disableSAX)) { + if (nbNs > 0) + ctxt->sax->startElementNs(ctxt->userData, localname, prefix, + nsname, nbNs, &ctxt->nsTab[ctxt->nsNr - 2 * nbNs], + nbatts / 5, nbdef, atts); + else + ctxt->sax->startElementNs(ctxt->userData, localname, prefix, + nsname, 0, NULL, nbatts / 5, nbdef, atts); + } + + /* + * Free up attribute allocated strings if needed + */ + if (attval != 0) { + for (i = 3,j = 0; j < nratts;i += 5,j++) + if ((ctxt->attallocs[j] != 0) && (atts[i] != NULL)) + xmlFree((xmlChar *) atts[i]); } return(localname); + +base_changed: + /* + * the attribute strings are valid iif the base didn't changed + */ + if (attval != 0) { + for (i = 3,j = 0; j < nratts;i += 5,j++) + if ((ctxt->attallocs[j] != 0) && (atts[i] != NULL)) + xmlFree((xmlChar *) atts[i]); + } + ctxt->input->cur = ctxt->input->base + cur; + if (ctxt->wellFormed == 1) { + goto reparse; + } + return(NULL); } /** @@ -7578,7 +7999,8 @@ xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlChar *prefix, if ((RAW != '<') || (NXT(1) != '/')) { ctxt->errNo = XML_ERR_LTSLASH_REQUIRED; if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) - ctxt->sax->error(ctxt->userData, "xmlParseEndTag: 'sax->error(ctxt->userData, + "xmlParseEndTag: 'wellFormed = 0; if (ctxt->recovery == 0) ctxt->disableSAX = 1; return; @@ -7631,7 +8053,6 @@ xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlChar *prefix, (!ctxt->disableSAX)) ctxt->sax->endElementNs(ctxt->userData, ctxt->name, prefix, URI); - namePop(ctxt); spacePop(ctxt); if (nsNr != 0) nsPop(ctxt, nsNr); @@ -7985,9 +8406,10 @@ xmlParseElement(xmlParserCtxtPtr ctxt) { /* * parse the end of tag: 'sax2) + if (ctxt->sax2) { xmlParseEndTag2(ctxt, prefix, URI, line, ctxt->nsNr - nsNr); - else + namePop(ctxt); + } else xmlParseEndTag1(ctxt, line); /* @@ -8574,13 +8996,7 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) { /* * SAX: detecting the level. */ - if ((ctxt->sax) && (ctxt->sax->initialized == XML_SAX2_MAGIC) && - ((ctxt->sax->startElementNs != NULL) || - (ctxt->sax->endElementNs != NULL) || - (ctxt->sax->attributeNs != NULL))) ctxt->sax2 = 1; - - ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); - ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); + xmlDetectSAX2(ctxt); /* * SAX: beginning of the document processing. @@ -9215,7 +9631,10 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { } break; case XML_PARSER_START_TAG: { - const xmlChar *name, *oldname; + const xmlChar *name; + const xmlChar *prefix; + const xmlChar *URI; + int nsNr = ctxt->nsNr; if ((avail < 2) && (ctxt->inputNr == 1)) goto done; @@ -9228,10 +9647,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { ctxt->wellFormed = 0; if (ctxt->recovery == 0) ctxt->disableSAX = 1; ctxt->instate = XML_PARSER_EOF; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering EOF\n"); -#endif if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) ctxt->sax->endDocument(ctxt->userData); goto done; @@ -9248,20 +9663,17 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { spacePush(ctxt, -1); else spacePush(ctxt, *ctxt->space); - name = xmlParseStartTag(ctxt); + if (ctxt->sax2) + name = xmlParseStartTag2(ctxt, &prefix, &URI); + else + name = xmlParseStartTag(ctxt); if (name == NULL) { spacePop(ctxt); ctxt->instate = XML_PARSER_EOF; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering EOF\n"); -#endif if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) ctxt->sax->endDocument(ctxt->userData); goto done; } - namePush(ctxt, name); - /* * [ VC: Root Element Type ] * The Name in the document type declaration must match @@ -9276,29 +9688,24 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { */ if ((RAW == '/') && (NXT(1) == '>')) { SKIP(2); - if ((ctxt->sax != NULL) && - (ctxt->sax->endElement != NULL) && (!ctxt->disableSAX)) - ctxt->sax->endElement(ctxt->userData, name); - oldname = namePop(ctxt); - spacePop(ctxt); -#ifdef DEBUG_STACK - if (oldname != NULL) { - xmlGenericError(xmlGenericErrorContext, - "Close: popped %s\n", oldname); + + if (ctxt->sax2) { + if ((ctxt->sax != NULL) && + (ctxt->sax->endElementNs != NULL) && + (!ctxt->disableSAX)) + ctxt->sax->endElementNs(ctxt->userData, name, + prefix, URI); + } else { + if ((ctxt->sax != NULL) && + (ctxt->sax->endElement != NULL) && + (!ctxt->disableSAX)) + ctxt->sax->endElement(ctxt->userData, name); } -#endif - if (ctxt->name == NULL) { + spacePop(ctxt); + if (ctxt->nameNr == 0) { ctxt->instate = XML_PARSER_EPILOG; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering EPILOG\n"); -#endif } else { ctxt->instate = XML_PARSER_CONTENT; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering CONTENT\n"); -#endif } break; } @@ -9313,24 +9720,15 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { ctxt->wellFormed = 0; if (ctxt->recovery == 0) ctxt->disableSAX = 1; - /* - * end of parsing of this node. - */ nodePop(ctxt); - oldname = namePop(ctxt); spacePop(ctxt); -#ifdef DEBUG_STACK - if (oldname != NULL) { - xmlGenericError(xmlGenericErrorContext, - "Close: popped %s\n", oldname); - } -#endif } + if (ctxt->sax2) + nameNsPush(ctxt, name, prefix, URI, ctxt->nsNr - nsNr); + else + namePush(ctxt, name); + ctxt->instate = XML_PARSER_CONTENT; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering CONTENT\n"); -#endif break; } case XML_PARSER_CONTENT: { @@ -9345,26 +9743,14 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { cons = ctxt->input->consumed; if ((cur == '<') && (next == '/')) { ctxt->instate = XML_PARSER_END_TAG; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering END_TAG\n"); -#endif break; } else if ((cur == '<') && (next == '?')) { if ((!terminate) && (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) goto done; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: Parsing PI\n"); -#endif xmlParsePI(ctxt); } else if ((cur == '<') && (next != '!')) { ctxt->instate = XML_PARSER_START_TAG; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering START_TAG\n"); -#endif break; } else if ((cur == '<') && (next == '!') && (ctxt->input->cur[2] == '-') && @@ -9372,10 +9758,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { if ((!terminate) && (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0)) goto done; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: Parsing Comment\n"); -#endif xmlParseComment(ctxt); ctxt->instate = XML_PARSER_CONTENT; } else if ((cur == '<') && (ctxt->input->cur[1] == '!') && @@ -9388,10 +9770,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { (ctxt->input->cur[8] == '[')) { SKIP(9); ctxt->instate = XML_PARSER_CDATA_SECTION; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering CDATA_SECTION\n"); -#endif break; } else if ((cur == '<') && (next == '!') && (avail < 9)) { @@ -9400,10 +9778,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { if ((!terminate) && (xmlParseLookupSequence(ctxt, ';', 0, 0) < 0)) goto done; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: Parsing Reference\n"); -#endif xmlParseReference(ctxt); } else { /* TODO Avoid the extra copy, handle directly !!! */ @@ -9432,10 +9806,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { } } ctxt->checkIndex = 0; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: Parsing char data\n"); -#endif xmlParseCharData(ctxt, 0); } /* @@ -9466,19 +9836,18 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { goto done; } } - xmlParseEndTag(ctxt); - if (ctxt->name == NULL) { + if (ctxt->sax2) { + xmlParseEndTag2(ctxt, + (void *) ctxt->pushTab[ctxt->nameNr * 3 - 3], + (void *) ctxt->pushTab[ctxt->nameNr * 3 - 2], 0, + (int) (long) ctxt->pushTab[ctxt->nameNr * 3 - 1]); + nameNsPop(ctxt); + } else + xmlParseEndTag1(ctxt, 0); + if (ctxt->nameNr == 0) { ctxt->instate = XML_PARSER_EPILOG; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering EPILOG\n"); -#endif } else { ctxt->instate = XML_PARSER_CONTENT; -#ifdef DEBUG_PUSH - xmlGenericError(xmlGenericErrorContext, - "PP: entering CONTENT\n"); -#endif } break; case XML_PARSER_CDATA_SECTION: { @@ -10021,6 +10390,14 @@ xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data, xmlFreeParserInputBuffer(buf); return(NULL); } + ctxt->pushTab = (void **) xmlMalloc(ctxt->nameMax * 3 * sizeof(xmlChar *)); + if (ctxt->pushTab == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlCreatePushParserCtxt: out of memory\n"); + xmlFreeParserInputBuffer(buf); + xmlFreeParserCtxt(ctxt); + return(NULL); + } if (sax != NULL) { if (ctxt->sax != &xmlDefaultSAXHandler) xmlFree(ctxt->sax); @@ -10036,6 +10413,7 @@ xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data, if (user_data != NULL) ctxt->userData = user_data; } + xmlDetectSAX2(ctxt); if (filename == NULL) { ctxt->directory = NULL; } else { @@ -10081,6 +10459,7 @@ xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data, if (enc != XML_CHAR_ENCODING_NONE) { xmlSwitchEncoding(ctxt, enc); } + xmlDetectSAX2(ctxt); return(ctxt); } @@ -10128,6 +10507,7 @@ xmlCreateIOParserCtxt(xmlSAXHandlerPtr sax, void *user_data, if (user_data != NULL) ctxt->userData = user_data; } + xmlDetectSAX2(ctxt); inputStream = xmlNewIOInputStream(ctxt, buf, enc); if (inputStream == NULL) { @@ -10182,6 +10562,7 @@ xmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input, ctxt->sax = sax; ctxt->userData = NULL; } + xmlDetectSAX2(ctxt); /* * generate a parser input from the I/O handler @@ -10293,6 +10674,7 @@ xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID, ctxt->sax = sax; ctxt->userData = ctxt; } + xmlDetectSAX2(ctxt); /* * Ask the Entity resolver to load the damn thing @@ -10422,6 +10804,7 @@ xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, const xmlChar *URL, ctxt->_private = ctx->_private; oldsax = ctxt->sax; ctxt->sax = ctx->sax; + xmlDetectSAX2(ctxt); newDoc = xmlNewDoc(BAD_CAST "1.0"); if (newDoc == NULL) { xmlFreeParserCtxt(ctxt); @@ -10627,6 +11010,7 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, if (user_data != NULL) ctxt->userData = user_data; } + xmlDetectSAX2(ctxt); newDoc = xmlNewDoc(BAD_CAST "1.0"); if (newDoc == NULL) { ctxt->node_seq.maximum = 0; @@ -10861,6 +11245,8 @@ xmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt, oldsax = ctxt->sax; ctxt->sax = oldctxt->sax; + xmlDetectSAX2(ctxt); + ctxt->_private = oldctxt->_private; if (oldctxt->myDoc == NULL) { newDoc = xmlNewDoc(BAD_CAST "1.0"); @@ -11019,6 +11405,7 @@ xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax, if (user_data != NULL) ctxt->userData = user_data; } + xmlDetectSAX2(ctxt); newDoc = xmlNewDoc(BAD_CAST "1.0"); if (newDoc == NULL) { xmlFreeParserCtxt(ctxt); @@ -11053,6 +11440,7 @@ xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax, */ ctxt->validate = 0; ctxt->loadsubset = 0; + xmlDetectSAX2(ctxt); if ( doc != NULL ){ content = doc->children; @@ -11153,6 +11541,7 @@ xmlSAXParseEntity(xmlSAXHandlerPtr sax, const char *filename) { ctxt->sax = sax; ctxt->userData = NULL; } + xmlDetectSAX2(ctxt); xmlParseExtParsedEnt(ctxt); @@ -11244,6 +11633,7 @@ xmlCreateEntityParserCtxt(const xmlChar *URL, const xmlChar *ID, ctxt->directory = directory; xmlFree(uri); } + xmlDetectSAX2(ctxt); return(ctxt); } @@ -11332,6 +11722,7 @@ xmlSAXParseFileWithData(xmlSAXHandlerPtr sax, const char *filename, xmlFree(ctxt->sax); ctxt->sax = sax; } + xmlDetectSAX2(ctxt); if (data!=NULL) { ctxt->_private=data; } @@ -11488,6 +11879,8 @@ xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data, if (ctxt->sax != &xmlDefaultSAXHandler) xmlFree(ctxt->sax); ctxt->sax = sax; + xmlDetectSAX2(ctxt); + if (user_data != NULL) ctxt->userData = user_data; @@ -11593,6 +11986,7 @@ xmlSAXParseMemoryWithData(xmlSAXHandlerPtr sax, const char *buffer, xmlFree(ctxt->sax); ctxt->sax = sax; } + xmlDetectSAX2(ctxt); if (data!=NULL) { ctxt->_private=data; } @@ -11686,6 +12080,7 @@ int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data, if (ctxt == NULL) return -1; oldsax = ctxt->sax; ctxt->sax = sax; + xmlDetectSAX2(ctxt); if (user_data != NULL) ctxt->userData = user_data; @@ -11751,6 +12146,7 @@ xmlSAXParseDoc(xmlSAXHandlerPtr sax, xmlChar *cur, int recovery) { ctxt->sax = sax; ctxt->userData = NULL; } + xmlDetectSAX2(ctxt); xmlParseDocument(ctxt); if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc; diff --git a/parserInternals.c b/parserInternals.c index 5328b238..7b5a06f4 100644 --- a/parserInternals.c +++ b/parserInternals.c @@ -2374,6 +2374,10 @@ xmlFreeParserCtxt(xmlParserCtxtPtr ctxt) if (ctxt->atts != NULL) xmlFree((xmlChar * *)ctxt->atts); if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); if (ctxt->nsTab != NULL) xmlFree(ctxt->nsTab); + if (ctxt->pushTab != NULL) xmlFree(ctxt->pushTab); + if (ctxt->attallocs != NULL) xmlFree(ctxt->attallocs); + if (ctxt->attsDefault != NULL) + xmlHashFree(ctxt->attsDefault, (xmlHashDeallocator) xmlFree); #ifdef LIBXML_CATALOG_ENABLED if (ctxt->catalogs != NULL) diff --git a/result/p3p.sax b/result/p3p.sax index 0dcd715a..e2eb506e 100644 --- a/result/p3p.sax +++ b/result/p3p.sax @@ -1,6 +1,6 @@ SAX.setDocumentLocator() SAX.startDocument() -SAX.startElement(RDF:RDF, xmlns:p3p='http//www.w3.org/TR/1998/WD-P3P10-syntax#proposal.DTD', xmlns:RDF='http://www.w3.org/TR/WD-rdf-syntax#') +SAX.startElement(RDF:RDF, xmlns:p3p='http://www.w3.org/TR/1998/WD-P3P10-syntax#proposal.DTD', xmlns:RDF='http://www.w3.org/TR/WD-rdf-syntax#') SAX.characters( , 1) SAX.startElement(PROP, realm='http://www.CoolCatalog.com/catalogue/', entity='CoolCatalog', agreeID='94df1293a3e519bb', assurance='http://www.TrustUs.org')