| Index: third_party/libxml/dict.c
 | 
| diff --git a/third_party/libxml/dict.c b/third_party/libxml/dict.c
 | 
| index c071887f6f644286262c161b6776e875cb2d2a71..3eff2315e94112089cf487707a02f409740031fe 100644
 | 
| --- a/third_party/libxml/dict.c
 | 
| +++ b/third_party/libxml/dict.c
 | 
| @@ -20,18 +20,48 @@
 | 
|  #include "libxml.h"
 | 
|  
 | 
|  #include <string.h>
 | 
| +#ifdef HAVE_STDINT_H
 | 
| +#include <stdint.h>
 | 
| +#else
 | 
| +#ifdef HAVE_INTTYPES_H
 | 
| +#include <inttypes.h>
 | 
| +#elif defined(WIN32)
 | 
| +typedef unsigned __int32 uint32_t;
 | 
| +#endif
 | 
| +#endif
 | 
|  #include <libxml/tree.h>
 | 
|  #include <libxml/dict.h>
 | 
|  #include <libxml/xmlmemory.h>
 | 
|  #include <libxml/xmlerror.h>
 | 
|  #include <libxml/globals.h>
 | 
|  
 | 
| -#define MAX_HASH_LEN 4
 | 
| +/* #define DEBUG_GROW */
 | 
| +/* #define DICT_DEBUG_PATTERNS */
 | 
| +
 | 
| +#define MAX_HASH_LEN 3
 | 
|  #define MIN_DICT_SIZE 128
 | 
|  #define MAX_DICT_HASH 8 * 2048
 | 
| -
 | 
| -/* #define ALLOW_REMOVAL */
 | 
| -/* #define DEBUG_GROW */
 | 
| +#define WITH_BIG_KEY
 | 
| +
 | 
| +#ifdef WITH_BIG_KEY
 | 
| +#define xmlDictComputeKey(dict, name, len)			\
 | 
| +    (((dict)->size == MIN_DICT_SIZE) ?				\
 | 
| +     xmlDictComputeFastKey(name, len) :				\
 | 
| +     xmlDictComputeBigKey(name, len))
 | 
| +
 | 
| +#define xmlDictComputeQKey(dict, prefix, plen, name, len)	\
 | 
| +    (((prefix) == NULL) ?					\
 | 
| +      (xmlDictComputeKey(dict, name, len)) :			\
 | 
| +      (((dict)->size == MIN_DICT_SIZE) ?			\
 | 
| +       xmlDictComputeFastQKey(prefix, plen, name, len) :	\
 | 
| +       xmlDictComputeBigQKey(prefix, plen, name, len)))
 | 
| +
 | 
| +#else /* !WITH_BIG_KEY */
 | 
| +#define xmlDictComputeKey(dict, name, len)			\
 | 
| +        xmlDictComputeFastKey(name, len)
 | 
| +#define xmlDictComputeQKey(dict, prefix, plen, name, len)	\
 | 
| +        xmlDictComputeFastQKey(prefix, plen, name, len)
 | 
| +#endif /* WITH_BIG_KEY */
 | 
|  
 | 
|  /*
 | 
|   * An entry in the dictionnary
 | 
| @@ -43,6 +73,7 @@ struct _xmlDictEntry {
 | 
|      const xmlChar *name;
 | 
|      int len;
 | 
|      int valid;
 | 
| +    unsigned long okey;
 | 
|  };
 | 
|  
 | 
|  typedef struct _xmlDictStrings xmlDictStrings;
 | 
| @@ -129,6 +160,9 @@ xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
 | 
|      const xmlChar *ret;
 | 
|      int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
 | 
|  
 | 
| +#ifdef DICT_DEBUG_PATTERNS
 | 
| +    fprintf(stderr, "-");
 | 
| +#endif
 | 
|      pool = dict->strings;
 | 
|      while (pool != NULL) {
 | 
|  	if (pool->end - pool->free > namelen)
 | 
| @@ -153,12 +187,16 @@ xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
 | 
|  	pool->end = &pool->array[size];
 | 
|  	pool->next = dict->strings;
 | 
|  	dict->strings = pool;
 | 
| +#ifdef DICT_DEBUG_PATTERNS
 | 
| +        fprintf(stderr, "+");
 | 
| +#endif
 | 
|      }
 | 
|  found_pool:
 | 
|      ret = pool->free;
 | 
|      memcpy(pool->free, name, namelen);
 | 
|      pool->free += namelen;
 | 
|      *(pool->free++) = 0;
 | 
| +    pool->nbStrings++;
 | 
|      return(ret);
 | 
|  }
 | 
|  
 | 
| @@ -166,6 +204,7 @@ found_pool:
 | 
|   * xmlDictAddQString:
 | 
|   * @dict: the dictionnary
 | 
|   * @prefix: the prefix of the userdata
 | 
| + * @plen: the prefix length
 | 
|   * @name: the name of the userdata
 | 
|   * @len: the length of the name, if -1 it is recomputed
 | 
|   *
 | 
| @@ -174,20 +213,21 @@ found_pool:
 | 
|   * Returns the pointer of the local string, or NULL in case of error.
 | 
|   */
 | 
|  static const xmlChar *
 | 
| -xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix,
 | 
| +xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen,
 | 
|                   const xmlChar *name, int namelen)
 | 
|  {
 | 
|      xmlDictStringsPtr pool;
 | 
|      const xmlChar *ret;
 | 
|      int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
 | 
| -    int plen;
 | 
|  
 | 
|      if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
 | 
| -    plen = xmlStrlen(prefix);
 | 
|  
 | 
| +#ifdef DICT_DEBUG_PATTERNS
 | 
| +    fprintf(stderr, "=");
 | 
| +#endif
 | 
|      pool = dict->strings;
 | 
|      while (pool != NULL) {
 | 
| -	if (pool->end - pool->free > namelen)
 | 
| +	if (pool->end - pool->free > namelen + plen + 1)
 | 
|  	    goto found_pool;
 | 
|  	if (pool->size > size) size = pool->size;
 | 
|  	pool = pool->next;
 | 
| @@ -198,8 +238,8 @@ xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix,
 | 
|      if (pool == NULL) {
 | 
|          if (size == 0) size = 1000;
 | 
|  	else size *= 4; /* exponential growth */
 | 
| -        if (size < 4 * namelen) 
 | 
| -	    size = 4 * namelen; /* just in case ! */
 | 
| +        if (size < 4 * (namelen + plen + 1))
 | 
| +	    size = 4 * (namelen + plen + 1); /* just in case ! */
 | 
|  	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
 | 
|  	if (pool == NULL)
 | 
|  	    return(NULL);
 | 
| @@ -209,27 +249,106 @@ xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix,
 | 
|  	pool->end = &pool->array[size];
 | 
|  	pool->next = dict->strings;
 | 
|  	dict->strings = pool;
 | 
| +#ifdef DICT_DEBUG_PATTERNS
 | 
| +        fprintf(stderr, "+");
 | 
| +#endif
 | 
|      }
 | 
|  found_pool:
 | 
|      ret = pool->free;
 | 
|      memcpy(pool->free, prefix, plen);
 | 
|      pool->free += plen;
 | 
|      *(pool->free++) = ':';
 | 
| -    namelen -= plen + 1;
 | 
|      memcpy(pool->free, name, namelen);
 | 
|      pool->free += namelen;
 | 
|      *(pool->free++) = 0;
 | 
| +    pool->nbStrings++;
 | 
|      return(ret);
 | 
|  }
 | 
|  
 | 
| +#ifdef WITH_BIG_KEY
 | 
| +/*
 | 
| + * xmlDictComputeBigKey:
 | 
| + *
 | 
| + * Calculate a hash key using a good hash function that works well for
 | 
| + * larger hash table sizes.
 | 
| + *
 | 
| + * Hash function by "One-at-a-Time Hash" see
 | 
| + * http://burtleburtle.net/bob/hash/doobs.html
 | 
| + */
 | 
| +
 | 
| +static uint32_t
 | 
| +xmlDictComputeBigKey(const xmlChar* data, int namelen) {
 | 
| +    uint32_t hash;
 | 
| +    int i;
 | 
| +
 | 
| +    if (namelen <= 0 || data == NULL) return(0);
 | 
| +
 | 
| +    hash = 0;
 | 
| +
 | 
| +    for (i = 0;i < namelen; i++) {
 | 
| +        hash += data[i];
 | 
| +	hash += (hash << 10);
 | 
| +	hash ^= (hash >> 6);
 | 
| +    }
 | 
| +    hash += (hash << 3);
 | 
| +    hash ^= (hash >> 11);
 | 
| +    hash += (hash << 15);
 | 
| +
 | 
| +    return hash;
 | 
| +}
 | 
| +
 | 
| +/*
 | 
| + * xmlDictComputeBigQKey:
 | 
| + *
 | 
| + * Calculate a hash key for two strings using a good hash function
 | 
| + * that works well for larger hash table sizes.
 | 
| + *
 | 
| + * Hash function by "One-at-a-Time Hash" see
 | 
| + * http://burtleburtle.net/bob/hash/doobs.html
 | 
| + *
 | 
| + * Neither of the two strings must be NULL.
 | 
| + */
 | 
| +static unsigned long
 | 
| +xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
 | 
| +                      const xmlChar *name, int len)
 | 
| +{
 | 
| +    uint32_t hash;
 | 
| +    int i;
 | 
| +
 | 
| +    hash = 0;
 | 
| +
 | 
| +    for (i = 0;i < plen; i++) {
 | 
| +        hash += prefix[i];
 | 
| +	hash += (hash << 10);
 | 
| +	hash ^= (hash >> 6);
 | 
| +    }
 | 
| +    hash += ':';
 | 
| +    hash += (hash << 10);
 | 
| +    hash ^= (hash >> 6);
 | 
| +
 | 
| +    for (i = 0;i < len; i++) {
 | 
| +        hash += name[i];
 | 
| +	hash += (hash << 10);
 | 
| +	hash ^= (hash >> 6);
 | 
| +    }
 | 
| +    hash += (hash << 3);
 | 
| +    hash ^= (hash >> 11);
 | 
| +    hash += (hash << 15);
 | 
| +
 | 
| +    return hash;
 | 
| +}
 | 
| +#endif /* WITH_BIG_KEY */
 | 
| +
 | 
|  /*
 | 
| - * xmlDictComputeKey:
 | 
| - * Calculate the hash key
 | 
| + * xmlDictComputeFastKey:
 | 
| + *
 | 
| + * Calculate a hash key using a fast hash function that works well
 | 
| + * for low hash table fill.
 | 
|   */
 | 
|  static unsigned long
 | 
| -xmlDictComputeKey(const xmlChar *name, int namelen) {
 | 
| +xmlDictComputeFastKey(const xmlChar *name, int namelen) {
 | 
|      unsigned long value = 0L;
 | 
| -    
 | 
| +
 | 
|      if (name == NULL) return(0);
 | 
|      value = *name;
 | 
|      value <<= 5;
 | 
| @@ -253,24 +372,24 @@ xmlDictComputeKey(const xmlChar *name, int namelen) {
 | 
|  }
 | 
|  
 | 
|  /*
 | 
| - * xmlDictComputeQKey:
 | 
| - * Calculate the hash key
 | 
| + * xmlDictComputeFastQKey:
 | 
| + *
 | 
| + * Calculate a hash key for two strings using a fast hash function
 | 
| + * that works well for low hash table fill.
 | 
| + *
 | 
| + * Neither of the two strings must be NULL.
 | 
|   */
 | 
|  static unsigned long
 | 
| -xmlDictComputeQKey(const xmlChar *prefix, const xmlChar *name, int len)
 | 
| +xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
 | 
| +                       const xmlChar *name, int len)
 | 
|  {
 | 
|      unsigned long value = 0L;
 | 
| -    int plen;
 | 
| -    
 | 
| -    if (prefix == NULL)
 | 
| -        return(xmlDictComputeKey(name, len));
 | 
|  
 | 
| -    plen = xmlStrlen(prefix);
 | 
|      if (plen == 0)
 | 
|  	value += 30 * (unsigned long) ':';
 | 
|      else
 | 
|  	value += 30 * (*prefix);
 | 
| -    
 | 
| +
 | 
|      if (len > 10) {
 | 
|          value += name[len - (plen + 1 + 1)];
 | 
|          len = 10;
 | 
| @@ -325,7 +444,11 @@ xmlDictCreate(void) {
 | 
|      if (!xmlDictInitialized)
 | 
|          if (!xmlInitializeDict())
 | 
|              return(NULL);
 | 
| - 
 | 
| +
 | 
| +#ifdef DICT_DEBUG_PATTERNS
 | 
| +    fprintf(stderr, "C");
 | 
| +#endif
 | 
| +
 | 
|      dict = xmlMalloc(sizeof(xmlDict));
 | 
|      if (dict) {
 | 
|          dict->ref_counter = 1;
 | 
| @@ -358,8 +481,11 @@ xmlDictCreate(void) {
 | 
|  xmlDictPtr
 | 
|  xmlDictCreateSub(xmlDictPtr sub) {
 | 
|      xmlDictPtr dict = xmlDictCreate();
 | 
| -  
 | 
| +
 | 
|      if ((dict != NULL) && (sub != NULL)) {
 | 
| +#ifdef DICT_DEBUG_PATTERNS
 | 
| +        fprintf(stderr, "R");
 | 
| +#endif
 | 
|          dict->subdict = sub;
 | 
|  	xmlDictReference(dict->subdict);
 | 
|      }
 | 
| @@ -398,14 +524,16 @@ xmlDictReference(xmlDictPtr dict) {
 | 
|   */
 | 
|  static int
 | 
|  xmlDictGrow(xmlDictPtr dict, int size) {
 | 
| -    unsigned long key;
 | 
| +    unsigned long key, okey;
 | 
|      int oldsize, i;
 | 
|      xmlDictEntryPtr iter, next;
 | 
|      struct _xmlDictEntry *olddict;
 | 
|  #ifdef DEBUG_GROW
 | 
|      unsigned long nbElem = 0;
 | 
|  #endif
 | 
| -  
 | 
| +    int ret = 0;
 | 
| +    int keep_keys = 1;
 | 
| +
 | 
|      if (dict == NULL)
 | 
|  	return(-1);
 | 
|      if (size < 8)
 | 
| @@ -413,11 +541,17 @@ xmlDictGrow(xmlDictPtr dict, int size) {
 | 
|      if (size > 8 * 2048)
 | 
|  	return(-1);
 | 
|  
 | 
| +#ifdef DICT_DEBUG_PATTERNS
 | 
| +    fprintf(stderr, "*");
 | 
| +#endif
 | 
| +
 | 
|      oldsize = dict->size;
 | 
|      olddict = dict->dict;
 | 
|      if (olddict == NULL)
 | 
|          return(-1);
 | 
| -  
 | 
| +    if (oldsize == MIN_DICT_SIZE)
 | 
| +        keep_keys = 0;
 | 
| +
 | 
|      dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
 | 
|      if (dict->dict == NULL) {
 | 
|  	dict->dict = olddict;
 | 
| @@ -427,17 +561,44 @@ xmlDictGrow(xmlDictPtr dict, int size) {
 | 
|      dict->size = size;
 | 
|  
 | 
|      /*	If the two loops are merged, there would be situations where
 | 
| -	a new entry needs to allocated and data copied into it from 
 | 
| -	the main dict. So instead, we run through the array twice, first
 | 
| -	copying all the elements in the main array (where we can't get
 | 
| -	conflicts) and then the rest, so we only free (and don't allocate)
 | 
| +	a new entry needs to allocated and data copied into it from
 | 
| +	the main dict. It is nicer to run through the array twice, first
 | 
| +	copying all the elements in the main array (less probability of
 | 
| +	allocate) and then the rest, so we only free in the second loop.
 | 
|      */
 | 
|      for (i = 0; i < oldsize; i++) {
 | 
| -	if (olddict[i].valid == 0) 
 | 
| +	if (olddict[i].valid == 0)
 | 
|  	    continue;
 | 
| -	key = xmlDictComputeKey(olddict[i].name, olddict[i].len) % dict->size;
 | 
| -	memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
 | 
| -	dict->dict[key].next = NULL;
 | 
| +
 | 
| +	if (keep_keys)
 | 
| +	    okey = olddict[i].okey;
 | 
| +	else
 | 
| +	    okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
 | 
| +	key = okey % dict->size;
 | 
| +
 | 
| +	if (dict->dict[key].valid == 0) {
 | 
| +	    memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
 | 
| +	    dict->dict[key].next = NULL;
 | 
| +	    dict->dict[key].okey = okey;
 | 
| +	} else {
 | 
| +	    xmlDictEntryPtr entry;
 | 
| +
 | 
| +	    entry = xmlMalloc(sizeof(xmlDictEntry));
 | 
| +	    if (entry != NULL) {
 | 
| +		entry->name = olddict[i].name;
 | 
| +		entry->len = olddict[i].len;
 | 
| +		entry->okey = okey;
 | 
| +		entry->next = dict->dict[key].next;
 | 
| +		entry->valid = 1;
 | 
| +		dict->dict[key].next = entry;
 | 
| +	    } else {
 | 
| +	        /*
 | 
| +		 * we don't have much ways to alert from herei
 | 
| +		 * result is loosing an entry and unicity garantee
 | 
| +		 */
 | 
| +	        ret = -1;
 | 
| +	    }
 | 
| +	}
 | 
|  #ifdef DEBUG_GROW
 | 
|  	nbElem++;
 | 
|  #endif
 | 
| @@ -452,15 +613,21 @@ xmlDictGrow(xmlDictPtr dict, int size) {
 | 
|  	     * put back the entry in the new dict
 | 
|  	     */
 | 
|  
 | 
| -	    key = xmlDictComputeKey(iter->name, iter->len) % dict->size;
 | 
| +	    if (keep_keys)
 | 
| +		okey = iter->okey;
 | 
| +	    else
 | 
| +		okey = xmlDictComputeKey(dict, iter->name, iter->len);
 | 
| +	    key = okey % dict->size;
 | 
|  	    if (dict->dict[key].valid == 0) {
 | 
|  		memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
 | 
|  		dict->dict[key].next = NULL;
 | 
|  		dict->dict[key].valid = 1;
 | 
| +		dict->dict[key].okey = okey;
 | 
|  		xmlFree(iter);
 | 
|  	    } else {
 | 
| -	    	iter->next = dict->dict[key].next;
 | 
| -	    	dict->dict[key].next = iter;
 | 
| +		iter->next = dict->dict[key].next;
 | 
| +		iter->okey = okey;
 | 
| +		dict->dict[key].next = iter;
 | 
|  	    }
 | 
|  
 | 
|  #ifdef DEBUG_GROW
 | 
| @@ -478,7 +645,7 @@ xmlDictGrow(xmlDictPtr dict, int size) {
 | 
|  	    "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
 | 
|  #endif
 | 
|  
 | 
| -    return(0);
 | 
| +    return(ret);
 | 
|  }
 | 
|  
 | 
|  /**
 | 
| @@ -531,7 +698,6 @@ xmlDictFree(xmlDictPtr dict) {
 | 
|  		inside_dict = 0;
 | 
|  		iter = next;
 | 
|  	    }
 | 
| -	    inside_dict = 0;
 | 
|  	}
 | 
|  	xmlFree(dict->dict);
 | 
|      }
 | 
| @@ -565,12 +731,12 @@ xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
 | 
|  	return(NULL);
 | 
|  
 | 
|      if (len < 0)
 | 
| -        len = xmlStrlen(name);
 | 
| +        len = strlen((const char *) name);
 | 
|  
 | 
|      /*
 | 
|       * Check for duplicate and insertion location.
 | 
|       */
 | 
| -    okey = xmlDictComputeKey(name, len);
 | 
| +    okey = xmlDictComputeKey(dict, name, len);
 | 
|      key = okey % dict->size;
 | 
|      if (dict->dict[key].valid == 0) {
 | 
|  	insert = NULL;
 | 
| @@ -578,55 +744,66 @@ xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
 | 
|  	for (insert = &(dict->dict[key]); insert->next != NULL;
 | 
|  	     insert = insert->next) {
 | 
|  #ifdef __GNUC__
 | 
| -	    if (insert->len == len) {
 | 
| +	    if ((insert->okey == okey) && (insert->len == len)) {
 | 
|  		if (!memcmp(insert->name, name, len))
 | 
|  		    return(insert->name);
 | 
|  	    }
 | 
|  #else
 | 
| -	    if ((insert->len == len) &&
 | 
| +	    if ((insert->okey == okey) && (insert->len == len) &&
 | 
|  	        (!xmlStrncmp(insert->name, name, len)))
 | 
|  		return(insert->name);
 | 
|  #endif
 | 
|  	    nbi++;
 | 
|  	}
 | 
|  #ifdef __GNUC__
 | 
| -	if (insert->len == len) {
 | 
| +	if ((insert->okey == okey) && (insert->len == len)) {
 | 
|  	    if (!memcmp(insert->name, name, len))
 | 
|  		return(insert->name);
 | 
|  	}
 | 
|  #else
 | 
| -	if ((insert->len == len) &&
 | 
| +	if ((insert->okey == okey) && (insert->len == len) &&
 | 
|  	    (!xmlStrncmp(insert->name, name, len)))
 | 
|  	    return(insert->name);
 | 
|  #endif
 | 
|      }
 | 
|  
 | 
|      if (dict->subdict) {
 | 
| -	key = okey % dict->subdict->size;
 | 
| +        unsigned long skey;
 | 
| +
 | 
| +        /* we cannot always reuse the same okey for the subdict */
 | 
| +        if (((dict->size == MIN_DICT_SIZE) &&
 | 
| +	     (dict->subdict->size != MIN_DICT_SIZE)) ||
 | 
| +            ((dict->size != MIN_DICT_SIZE) &&
 | 
| +	     (dict->subdict->size == MIN_DICT_SIZE)))
 | 
| +	    skey = xmlDictComputeKey(dict->subdict, name, len);
 | 
| +	else
 | 
| +	    skey = okey;
 | 
| +
 | 
| +	key = skey % dict->subdict->size;
 | 
|  	if (dict->subdict->dict[key].valid != 0) {
 | 
|  	    xmlDictEntryPtr tmp;
 | 
|  
 | 
|  	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
 | 
|  		 tmp = tmp->next) {
 | 
|  #ifdef __GNUC__
 | 
| -		if (tmp->len == len) {
 | 
| +		if ((tmp->okey == skey) && (tmp->len == len)) {
 | 
|  		    if (!memcmp(tmp->name, name, len))
 | 
|  			return(tmp->name);
 | 
|  		}
 | 
|  #else
 | 
| -		if ((tmp->len == len) &&
 | 
| +		if ((tmp->okey == skey) && (tmp->len == len) &&
 | 
|  		    (!xmlStrncmp(tmp->name, name, len)))
 | 
|  		    return(tmp->name);
 | 
|  #endif
 | 
|  		nbi++;
 | 
|  	    }
 | 
|  #ifdef __GNUC__
 | 
| -	    if (tmp->len == len) {
 | 
| +	    if ((tmp->okey == skey) && (tmp->len == len)) {
 | 
|  		if (!memcmp(tmp->name, name, len))
 | 
|  		    return(tmp->name);
 | 
|  	    }
 | 
|  #else
 | 
| -	    if ((tmp->len == len) &&
 | 
| +	    if ((tmp->okey == skey) && (tmp->len == len) &&
 | 
|  		(!xmlStrncmp(tmp->name, name, len)))
 | 
|  		return(tmp->name);
 | 
|  #endif
 | 
| @@ -648,6 +825,7 @@ xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
 | 
|      entry->len = len;
 | 
|      entry->next = NULL;
 | 
|      entry->valid = 1;
 | 
| +    entry->okey = okey;
 | 
|  
 | 
|  
 | 
|      if (insert != NULL) 
 | 
| @@ -656,8 +834,10 @@ xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
 | 
|      dict->nbElems++;
 | 
|  
 | 
|      if ((nbi > MAX_HASH_LEN) &&
 | 
| -        (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
 | 
| -	xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
 | 
| +        (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
 | 
| +	if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
 | 
| +	    return(NULL);
 | 
| +    }
 | 
|      /* Note that entry may have been freed at this point by xmlDictGrow */
 | 
|  
 | 
|      return(ret);
 | 
| @@ -682,12 +862,12 @@ xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
 | 
|  	return(NULL);
 | 
|  
 | 
|      if (len < 0)
 | 
| -        len = xmlStrlen(name);
 | 
| +        len = strlen((const char *) name);
 | 
|  
 | 
|      /*
 | 
|       * Check for duplicate and insertion location.
 | 
|       */
 | 
| -    okey = xmlDictComputeKey(name, len);
 | 
| +    okey = xmlDictComputeKey(dict, name, len);
 | 
|      key = okey % dict->size;
 | 
|      if (dict->dict[key].valid == 0) {
 | 
|  	insert = NULL;
 | 
| @@ -695,60 +875,70 @@ xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
 | 
|  	for (insert = &(dict->dict[key]); insert->next != NULL;
 | 
|  	     insert = insert->next) {
 | 
|  #ifdef __GNUC__
 | 
| -	    if (insert->len == len) {
 | 
| +	    if ((insert->okey == okey) && (insert->len == len)) {
 | 
|  		if (!memcmp(insert->name, name, len))
 | 
|  		    return(insert->name);
 | 
|  	    }
 | 
|  #else
 | 
| -	    if ((insert->len == len) &&
 | 
| +	    if ((insert->okey == okey) && (insert->len == len) &&
 | 
|  	        (!xmlStrncmp(insert->name, name, len)))
 | 
|  		return(insert->name);
 | 
|  #endif
 | 
|  	    nbi++;
 | 
|  	}
 | 
|  #ifdef __GNUC__
 | 
| -	if (insert->len == len) {
 | 
| +	if ((insert->okey == okey) && (insert->len == len)) {
 | 
|  	    if (!memcmp(insert->name, name, len))
 | 
|  		return(insert->name);
 | 
|  	}
 | 
|  #else
 | 
| -	if ((insert->len == len) &&
 | 
| +	if ((insert->okey == okey) && (insert->len == len) &&
 | 
|  	    (!xmlStrncmp(insert->name, name, len)))
 | 
|  	    return(insert->name);
 | 
|  #endif
 | 
|      }
 | 
|  
 | 
|      if (dict->subdict) {
 | 
| -	key = okey % dict->subdict->size;
 | 
| +        unsigned long skey;
 | 
| +
 | 
| +        /* we cannot always reuse the same okey for the subdict */
 | 
| +        if (((dict->size == MIN_DICT_SIZE) &&
 | 
| +	     (dict->subdict->size != MIN_DICT_SIZE)) ||
 | 
| +            ((dict->size != MIN_DICT_SIZE) &&
 | 
| +	     (dict->subdict->size == MIN_DICT_SIZE)))
 | 
| +	    skey = xmlDictComputeKey(dict->subdict, name, len);
 | 
| +	else
 | 
| +	    skey = okey;
 | 
| +
 | 
| +	key = skey % dict->subdict->size;
 | 
|  	if (dict->subdict->dict[key].valid != 0) {
 | 
|  	    xmlDictEntryPtr tmp;
 | 
|  
 | 
|  	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
 | 
|  		 tmp = tmp->next) {
 | 
|  #ifdef __GNUC__
 | 
| -		if (tmp->len == len) {
 | 
| +		if ((tmp->okey == skey) && (tmp->len == len)) {
 | 
|  		    if (!memcmp(tmp->name, name, len))
 | 
|  			return(tmp->name);
 | 
|  		}
 | 
|  #else
 | 
| -		if ((tmp->len == len) &&
 | 
| +		if ((tmp->okey == skey) && (tmp->len == len) &&
 | 
|  		    (!xmlStrncmp(tmp->name, name, len)))
 | 
|  		    return(tmp->name);
 | 
|  #endif
 | 
|  		nbi++;
 | 
|  	    }
 | 
|  #ifdef __GNUC__
 | 
| -	    if (tmp->len == len) {
 | 
| +	    if ((tmp->okey == skey) && (tmp->len == len)) {
 | 
|  		if (!memcmp(tmp->name, name, len))
 | 
|  		    return(tmp->name);
 | 
|  	    }
 | 
|  #else
 | 
| -	    if ((tmp->len == len) &&
 | 
| +	    if ((tmp->okey == skey) && (tmp->len == len) &&
 | 
|  		(!xmlStrncmp(tmp->name, name, len)))
 | 
|  		return(tmp->name);
 | 
|  #endif
 | 
|  	}
 | 
| -	key = okey % dict->size;
 | 
|      }
 | 
|  
 | 
|      /* not found */
 | 
| @@ -758,7 +948,7 @@ xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
 | 
|  /**
 | 
|   * xmlDictQLookup:
 | 
|   * @dict: the dictionnary
 | 
| - * @prefix: the prefix 
 | 
| + * @prefix: the prefix
 | 
|   * @name: the name
 | 
|   *
 | 
|   * Add the QName @prefix:@name to the hash @dict if not present.
 | 
| @@ -771,54 +961,67 @@ xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
 | 
|      xmlDictEntryPtr entry;
 | 
|      xmlDictEntryPtr insert;
 | 
|      const xmlChar *ret;
 | 
| -    int len;
 | 
| +    int len, plen, l;
 | 
|  
 | 
|      if ((dict == NULL) || (name == NULL))
 | 
|  	return(NULL);
 | 
| +    if (prefix == NULL)
 | 
| +        return(xmlDictLookup(dict, name, -1));
 | 
|  
 | 
| -    len = xmlStrlen(name);
 | 
| -    if (prefix != NULL)
 | 
| -        len += 1 + xmlStrlen(prefix);
 | 
| +    l = len = strlen((const char *) name);
 | 
| +    plen = strlen((const char *) prefix);
 | 
| +    len += 1 + plen;
 | 
|  
 | 
|      /*
 | 
|       * Check for duplicate and insertion location.
 | 
|       */
 | 
| -    okey = xmlDictComputeQKey(prefix, name, len);
 | 
| +    okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
 | 
|      key = okey % dict->size;
 | 
|      if (dict->dict[key].valid == 0) {
 | 
|  	insert = NULL;
 | 
|      } else {
 | 
|  	for (insert = &(dict->dict[key]); insert->next != NULL;
 | 
|  	     insert = insert->next) {
 | 
| -	    if ((insert->len == len) &&
 | 
| +	    if ((insert->okey == okey) && (insert->len == len) &&
 | 
|  	        (xmlStrQEqual(prefix, name, insert->name)))
 | 
|  		return(insert->name);
 | 
|  	    nbi++;
 | 
|  	}
 | 
| -	if ((insert->len == len) &&
 | 
| +	if ((insert->okey == okey) && (insert->len == len) &&
 | 
|  	    (xmlStrQEqual(prefix, name, insert->name)))
 | 
|  	    return(insert->name);
 | 
|      }
 | 
|  
 | 
|      if (dict->subdict) {
 | 
| -	key = okey % dict->subdict->size;
 | 
| +        unsigned long skey;
 | 
| +
 | 
| +        /* we cannot always reuse the same okey for the subdict */
 | 
| +        if (((dict->size == MIN_DICT_SIZE) &&
 | 
| +	     (dict->subdict->size != MIN_DICT_SIZE)) ||
 | 
| +            ((dict->size != MIN_DICT_SIZE) &&
 | 
| +	     (dict->subdict->size == MIN_DICT_SIZE)))
 | 
| +	    skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
 | 
| +	else
 | 
| +	    skey = okey;
 | 
| +
 | 
| +	key = skey % dict->subdict->size;
 | 
|  	if (dict->subdict->dict[key].valid != 0) {
 | 
|  	    xmlDictEntryPtr tmp;
 | 
|  	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
 | 
|  		 tmp = tmp->next) {
 | 
| -		if ((tmp->len == len) &&
 | 
| +		if ((tmp->okey == skey) && (tmp->len == len) &&
 | 
|  		    (xmlStrQEqual(prefix, name, tmp->name)))
 | 
|  		    return(tmp->name);
 | 
|  		nbi++;
 | 
|  	    }
 | 
| -	    if ((tmp->len == len) &&
 | 
| +	    if ((tmp->okey == skey) && (tmp->len == len) &&
 | 
|  		(xmlStrQEqual(prefix, name, tmp->name)))
 | 
|  		return(tmp->name);
 | 
|  	}
 | 
|  	key = okey % dict->size;
 | 
|      }
 | 
|  
 | 
| -    ret = xmlDictAddQString(dict, prefix, name, len);
 | 
| +    ret = xmlDictAddQString(dict, prefix, plen, name, l);
 | 
|      if (ret == NULL)
 | 
|          return(NULL);
 | 
|      if (insert == NULL) {
 | 
| @@ -832,6 +1035,7 @@ xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
 | 
|      entry->len = len;
 | 
|      entry->next = NULL;
 | 
|      entry->valid = 1;
 | 
| +    entry->okey = okey;
 | 
|  
 | 
|      if (insert != NULL) 
 | 
|  	insert->next = entry;
 | 
| 
 |