@@ -8912,6 +8912,35 @@ xmlAttrHashInsert(xmlParserCtxtPtr ctxt, unsigned size, const xmlChar *name,
89128912 return (INT_MAX );
89138913}
89148914
8915+ static int
8916+ xmlAttrHashInsertQName (xmlParserCtxtPtr ctxt , unsigned size ,
8917+ const xmlChar * name , const xmlChar * prefix ,
8918+ unsigned hashValue , int aindex ) {
8919+ xmlAttrHashBucket * table = ctxt -> attrHash ;
8920+ xmlAttrHashBucket * bucket ;
8921+ unsigned hindex ;
8922+
8923+ hindex = hashValue & (size - 1 );
8924+ bucket = & table [hindex ];
8925+
8926+ while (bucket -> index >= 0 ) {
8927+ const xmlChar * * atts = & ctxt -> atts [bucket -> index ];
8928+
8929+ if ((name == atts [0 ]) && (prefix == atts [1 ]))
8930+ return (bucket -> index );
8931+
8932+ hindex ++ ;
8933+ bucket ++ ;
8934+ if (hindex >= size ) {
8935+ hindex = 0 ;
8936+ bucket = table ;
8937+ }
8938+ }
8939+
8940+ bucket -> index = aindex ;
8941+
8942+ return (INT_MAX );
8943+ }
89158944/**
89168945 * xmlParseStartTag2:
89178946 * @ctxt: an XML parser context
@@ -8960,6 +8989,8 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref,
89608989 int nratts , nbatts , nbdef ;
89618990 int i , j , nbNs , nbTotalDef , attval , nsIndex , maxAtts ;
89628991 int alloc = 0 ;
8992+ int numNsErr = 0 ;
8993+ int numDupErr = 0 ;
89638994
89648995 if (RAW != '<' ) return (NULL );
89658996 NEXT1 ;
@@ -9338,10 +9369,12 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref,
93389369 if (res < INT_MAX ) {
93399370 if (aprefix == atts [res + 1 ]) {
93409371 xmlErrAttributeDup (ctxt , aprefix , attname );
9372+ numDupErr += 1 ;
93419373 } else {
93429374 xmlNsErr (ctxt , XML_NS_ERR_ATTRIBUTE_REDEFINED ,
93439375 "Namespaced Attribute %s in '%s' redefined\n" ,
93449376 attname , nsuri , NULL );
9377+ numNsErr += 1 ;
93459378 }
93469379 }
93479380 }
@@ -9440,6 +9473,43 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref,
94409473 }
94419474 }
94429475
9476+ /*
9477+ * Using a single hash table for nsUri/localName pairs cannot
9478+ * detect duplicate QNames reliably. The following example will
9479+ * only result in two namespace errors.
9480+ *
9481+ * <doc xmlns:a="a" xmlns:b="a">
9482+ * <elem a:a="" b:a="" b:a=""/>
9483+ * </doc>
9484+ *
9485+ * If we saw more than one namespace error but no duplicate QNames
9486+ * were found, we have to scan for duplicate QNames.
9487+ */
9488+ if ((numDupErr == 0 ) && (numNsErr > 1 )) {
9489+ memset (ctxt -> attrHash , -1 ,
9490+ attrHashSize * sizeof (ctxt -> attrHash [0 ]));
9491+
9492+ for (i = 0 , j = 0 ; j < nratts ; i += 5 , j ++ ) {
9493+ unsigned hashValue , nameHashValue , prefixHashValue ;
9494+ int res ;
9495+
9496+ aprefix = atts [i + 1 ];
9497+ if (aprefix == NULL )
9498+ continue ;
9499+
9500+ attname = atts [i ];
9501+ /* Hash values always have bit 31 set, see dict.c */
9502+ nameHashValue = ctxt -> attallocs [j ] | 0x80000000 ;
9503+ prefixHashValue = xmlDictComputeHash (ctxt -> dict , aprefix );
9504+
9505+ hashValue = xmlDictCombineHash (nameHashValue , prefixHashValue );
9506+ res = xmlAttrHashInsertQName (ctxt , attrHashSize , attname ,
9507+ aprefix , hashValue , i );
9508+ if (res < INT_MAX )
9509+ xmlErrAttributeDup (ctxt , aprefix , attname );
9510+ }
9511+ }
9512+
94439513 /*
94449514 * Reconstruct attribute pointers
94459515 */
@@ -11763,6 +11833,7 @@ xmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input,
1176311833 xmlFreeParserInputBuffer (input );
1176411834 return (NULL );
1176511835 }
11836+ xmlCtxtSetOptions (ctxt , XML_PARSE_DTDLOAD );
1176611837
1176711838 /*
1176811839 * generate a parser input from the I/O handler
@@ -11852,6 +11923,7 @@ xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID,
1185211923 if (ctxt == NULL ) {
1185311924 return (NULL );
1185411925 }
11926+ xmlCtxtSetOptions (ctxt , XML_PARSE_DTDLOAD );
1185511927
1185611928 /*
1185711929 * Canonicalise the system ID
@@ -12143,6 +12215,15 @@ xmlCtxtParseEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr ent) {
1214312215
1214412216 while (list != NULL ) {
1214512217 list -> parent = (xmlNodePtr ) ent ;
12218+
12219+ /*
12220+ * Downstream code like the nginx xslt module can set
12221+ * ctxt->myDoc->extSubset to a separate DTD, so the entity
12222+ * might have a different or a NULL document.
12223+ */
12224+ if (list -> doc != ent -> doc )
12225+ xmlSetTreeDoc (list , ent -> doc );
12226+
1214612227 if (list -> next == NULL )
1214712228 ent -> last = list ;
1214812229 list = list -> next ;
0 commit comments