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')