Home | History | Annotate | Download | only in libxml2
      1 /*
      2  * dict.c: dictionary of reusable strings, just used to avoid allocation
      3  *         and freeing operations.
      4  *
      5  * Copyright (C) 2003-2012 Daniel Veillard.
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     12  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     13  * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
     14  * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
     15  *
     16  * Author: daniel (at) veillard.com
     17  */
     18 
     19 #define IN_LIBXML
     20 #include "libxml.h"
     21 
     22 #ifdef HAVE_STDLIB_H
     23 #include <stdlib.h>
     24 #endif
     25 #ifdef HAVE_TIME_H
     26 #include <time.h>
     27 #endif
     28 
     29 /*
     30  * Following http://www.ocert.org/advisories/ocert-2011-003.html
     31  * it seems that having hash randomization might be a good idea
     32  * when using XML with untrusted data
     33  * Note1: that it works correctly only if compiled with WITH_BIG_KEY
     34  *  which is the default.
     35  * Note2: the fast function used for a small dict won't protect very
     36  *  well but since the attack is based on growing a very big hash
     37  *  list we will use the BigKey algo as soon as the hash size grows
     38  *  over MIN_DICT_SIZE so this actually works
     39  */
     40 #if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME)
     41 #define DICT_RANDOMIZATION
     42 #endif
     43 
     44 #include <string.h>
     45 #ifdef HAVE_STDINT_H
     46 #include <stdint.h>
     47 #else
     48 #ifdef HAVE_INTTYPES_H
     49 #include <inttypes.h>
     50 #elif defined(WIN32)
     51 typedef unsigned __int32 uint32_t;
     52 #endif
     53 #endif
     54 #include <libxml/tree.h>
     55 #include <libxml/dict.h>
     56 #include <libxml/xmlmemory.h>
     57 #include <libxml/xmlerror.h>
     58 #include <libxml/globals.h>
     59 
     60 /* #define DEBUG_GROW */
     61 /* #define DICT_DEBUG_PATTERNS */
     62 
     63 #define MAX_HASH_LEN 3
     64 #define MIN_DICT_SIZE 128
     65 #define MAX_DICT_HASH 8 * 2048
     66 #define WITH_BIG_KEY
     67 
     68 #ifdef WITH_BIG_KEY
     69 #define xmlDictComputeKey(dict, name, len)                              \
     70     (((dict)->size == MIN_DICT_SIZE) ?                                  \
     71      xmlDictComputeFastKey(name, len, (dict)->seed) :                   \
     72      xmlDictComputeBigKey(name, len, (dict)->seed))
     73 
     74 #define xmlDictComputeQKey(dict, prefix, plen, name, len)               \
     75     (((prefix) == NULL) ?                                               \
     76       (xmlDictComputeKey(dict, name, len)) :                             \
     77       (((dict)->size == MIN_DICT_SIZE) ?                                \
     78        xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) :	\
     79        xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
     80 
     81 #else /* !WITH_BIG_KEY */
     82 #define xmlDictComputeKey(dict, name, len)                              \
     83         xmlDictComputeFastKey(name, len, (dict)->seed)
     84 #define xmlDictComputeQKey(dict, prefix, plen, name, len)               \
     85         xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
     86 #endif /* WITH_BIG_KEY */
     87 
     88 /*
     89  * An entry in the dictionnary
     90  */
     91 typedef struct _xmlDictEntry xmlDictEntry;
     92 typedef xmlDictEntry *xmlDictEntryPtr;
     93 struct _xmlDictEntry {
     94     struct _xmlDictEntry *next;
     95     const xmlChar *name;
     96     int len;
     97     int valid;
     98     unsigned long okey;
     99 };
    100 
    101 typedef struct _xmlDictStrings xmlDictStrings;
    102 typedef xmlDictStrings *xmlDictStringsPtr;
    103 struct _xmlDictStrings {
    104     xmlDictStringsPtr next;
    105     xmlChar *free;
    106     xmlChar *end;
    107     int size;
    108     int nbStrings;
    109     xmlChar array[1];
    110 };
    111 /*
    112  * The entire dictionnary
    113  */
    114 struct _xmlDict {
    115     int ref_counter;
    116 
    117     struct _xmlDictEntry *dict;
    118     int size;
    119     int nbElems;
    120     xmlDictStringsPtr strings;
    121 
    122     struct _xmlDict *subdict;
    123     /* used for randomization */
    124     int seed;
    125 };
    126 
    127 /*
    128  * A mutex for modifying the reference counter for shared
    129  * dictionaries.
    130  */
    131 static xmlRMutexPtr xmlDictMutex = NULL;
    132 
    133 /*
    134  * Whether the dictionary mutex was initialized.
    135  */
    136 static int xmlDictInitialized = 0;
    137 
    138 /**
    139  * xmlInitializeDict:
    140  *
    141  * Do the dictionary mutex initialization.
    142  * this function is not thread safe, initialization should
    143  * preferably be done once at startup
    144  */
    145 static int xmlInitializeDict(void) {
    146     if (xmlDictInitialized)
    147         return(1);
    148 
    149     if ((xmlDictMutex = xmlNewRMutex()) == NULL)
    150         return(0);
    151 
    152 #ifdef DICT_RANDOMIZATION
    153     srand(time(NULL));
    154 #endif
    155     xmlDictInitialized = 1;
    156     return(1);
    157 }
    158 
    159 /**
    160  * xmlDictCleanup:
    161  *
    162  * Free the dictionary mutex.
    163  */
    164 void
    165 xmlDictCleanup(void) {
    166     if (!xmlDictInitialized)
    167         return;
    168 
    169     xmlFreeRMutex(xmlDictMutex);
    170 
    171     xmlDictInitialized = 0;
    172 }
    173 
    174 /*
    175  * xmlDictAddString:
    176  * @dict: the dictionnary
    177  * @name: the name of the userdata
    178  * @len: the length of the name, if -1 it is recomputed
    179  *
    180  * Add the string to the array[s]
    181  *
    182  * Returns the pointer of the local string, or NULL in case of error.
    183  */
    184 static const xmlChar *
    185 xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
    186     xmlDictStringsPtr pool;
    187     const xmlChar *ret;
    188     int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
    189 
    190 #ifdef DICT_DEBUG_PATTERNS
    191     fprintf(stderr, "-");
    192 #endif
    193     pool = dict->strings;
    194     while (pool != NULL) {
    195 	if (pool->end - pool->free > namelen)
    196 	    goto found_pool;
    197 	if (pool->size > size) size = pool->size;
    198 	pool = pool->next;
    199     }
    200     /*
    201      * Not found, need to allocate
    202      */
    203     if (pool == NULL) {
    204         if (size == 0) size = 1000;
    205 	else size *= 4; /* exponential growth */
    206         if (size < 4 * namelen)
    207 	    size = 4 * namelen; /* just in case ! */
    208 	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
    209 	if (pool == NULL)
    210 	    return(NULL);
    211 	pool->size = size;
    212 	pool->nbStrings = 0;
    213 	pool->free = &pool->array[0];
    214 	pool->end = &pool->array[size];
    215 	pool->next = dict->strings;
    216 	dict->strings = pool;
    217 #ifdef DICT_DEBUG_PATTERNS
    218         fprintf(stderr, "+");
    219 #endif
    220     }
    221 found_pool:
    222     ret = pool->free;
    223     memcpy(pool->free, name, namelen);
    224     pool->free += namelen;
    225     *(pool->free++) = 0;
    226     pool->nbStrings++;
    227     return(ret);
    228 }
    229 
    230 /*
    231  * xmlDictAddQString:
    232  * @dict: the dictionnary
    233  * @prefix: the prefix of the userdata
    234  * @plen: the prefix length
    235  * @name: the name of the userdata
    236  * @len: the length of the name, if -1 it is recomputed
    237  *
    238  * Add the QName to the array[s]
    239  *
    240  * Returns the pointer of the local string, or NULL in case of error.
    241  */
    242 static const xmlChar *
    243 xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen,
    244                  const xmlChar *name, int namelen)
    245 {
    246     xmlDictStringsPtr pool;
    247     const xmlChar *ret;
    248     int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
    249 
    250     if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
    251 
    252 #ifdef DICT_DEBUG_PATTERNS
    253     fprintf(stderr, "=");
    254 #endif
    255     pool = dict->strings;
    256     while (pool != NULL) {
    257 	if (pool->end - pool->free > namelen + plen + 1)
    258 	    goto found_pool;
    259 	if (pool->size > size) size = pool->size;
    260 	pool = pool->next;
    261     }
    262     /*
    263      * Not found, need to allocate
    264      */
    265     if (pool == NULL) {
    266         if (size == 0) size = 1000;
    267 	else size *= 4; /* exponential growth */
    268         if (size < 4 * (namelen + plen + 1))
    269 	    size = 4 * (namelen + plen + 1); /* just in case ! */
    270 	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
    271 	if (pool == NULL)
    272 	    return(NULL);
    273 	pool->size = size;
    274 	pool->nbStrings = 0;
    275 	pool->free = &pool->array[0];
    276 	pool->end = &pool->array[size];
    277 	pool->next = dict->strings;
    278 	dict->strings = pool;
    279 #ifdef DICT_DEBUG_PATTERNS
    280         fprintf(stderr, "+");
    281 #endif
    282     }
    283 found_pool:
    284     ret = pool->free;
    285     memcpy(pool->free, prefix, plen);
    286     pool->free += plen;
    287     *(pool->free++) = ':';
    288     memcpy(pool->free, name, namelen);
    289     pool->free += namelen;
    290     *(pool->free++) = 0;
    291     pool->nbStrings++;
    292     return(ret);
    293 }
    294 
    295 #ifdef WITH_BIG_KEY
    296 /*
    297  * xmlDictComputeBigKey:
    298  *
    299  * Calculate a hash key using a good hash function that works well for
    300  * larger hash table sizes.
    301  *
    302  * Hash function by "One-at-a-Time Hash" see
    303  * http://burtleburtle.net/bob/hash/doobs.html
    304  */
    305 
    306 static uint32_t
    307 xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
    308     uint32_t hash;
    309     int i;
    310 
    311     if (namelen <= 0 || data == NULL) return(0);
    312 
    313     hash = seed;
    314 
    315     for (i = 0;i < namelen; i++) {
    316         hash += data[i];
    317 	hash += (hash << 10);
    318 	hash ^= (hash >> 6);
    319     }
    320     hash += (hash << 3);
    321     hash ^= (hash >> 11);
    322     hash += (hash << 15);
    323 
    324     return hash;
    325 }
    326 
    327 /*
    328  * xmlDictComputeBigQKey:
    329  *
    330  * Calculate a hash key for two strings using a good hash function
    331  * that works well for larger hash table sizes.
    332  *
    333  * Hash function by "One-at-a-Time Hash" see
    334  * http://burtleburtle.net/bob/hash/doobs.html
    335  *
    336  * Neither of the two strings must be NULL.
    337  */
    338 static unsigned long
    339 xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
    340                       const xmlChar *name, int len, int seed)
    341 {
    342     uint32_t hash;
    343     int i;
    344 
    345     hash = seed;
    346 
    347     for (i = 0;i < plen; i++) {
    348         hash += prefix[i];
    349 	hash += (hash << 10);
    350 	hash ^= (hash >> 6);
    351     }
    352     hash += ':';
    353     hash += (hash << 10);
    354     hash ^= (hash >> 6);
    355 
    356     for (i = 0;i < len; i++) {
    357         hash += name[i];
    358 	hash += (hash << 10);
    359 	hash ^= (hash >> 6);
    360     }
    361     hash += (hash << 3);
    362     hash ^= (hash >> 11);
    363     hash += (hash << 15);
    364 
    365     return hash;
    366 }
    367 #endif /* WITH_BIG_KEY */
    368 
    369 /*
    370  * xmlDictComputeFastKey:
    371  *
    372  * Calculate a hash key using a fast hash function that works well
    373  * for low hash table fill.
    374  */
    375 static unsigned long
    376 xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
    377     unsigned long value = seed;
    378 
    379     if (name == NULL) return(0);
    380     value = *name;
    381     value <<= 5;
    382     if (namelen > 10) {
    383         value += name[namelen - 1];
    384         namelen = 10;
    385     }
    386     switch (namelen) {
    387         case 10: value += name[9];
    388         case 9: value += name[8];
    389         case 8: value += name[7];
    390         case 7: value += name[6];
    391         case 6: value += name[5];
    392         case 5: value += name[4];
    393         case 4: value += name[3];
    394         case 3: value += name[2];
    395         case 2: value += name[1];
    396         default: break;
    397     }
    398     return(value);
    399 }
    400 
    401 /*
    402  * xmlDictComputeFastQKey:
    403  *
    404  * Calculate a hash key for two strings using a fast hash function
    405  * that works well for low hash table fill.
    406  *
    407  * Neither of the two strings must be NULL.
    408  */
    409 static unsigned long
    410 xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
    411                        const xmlChar *name, int len, int seed)
    412 {
    413     unsigned long value = (unsigned long) seed;
    414 
    415     if (plen == 0)
    416 	value += 30 * (unsigned long) ':';
    417     else
    418 	value += 30 * (*prefix);
    419 
    420     if (len > 10) {
    421         value += name[len - (plen + 1 + 1)];
    422         len = 10;
    423 	if (plen > 10)
    424 	    plen = 10;
    425     }
    426     switch (plen) {
    427         case 10: value += prefix[9];
    428         case 9: value += prefix[8];
    429         case 8: value += prefix[7];
    430         case 7: value += prefix[6];
    431         case 6: value += prefix[5];
    432         case 5: value += prefix[4];
    433         case 4: value += prefix[3];
    434         case 3: value += prefix[2];
    435         case 2: value += prefix[1];
    436         case 1: value += prefix[0];
    437         default: break;
    438     }
    439     len -= plen;
    440     if (len > 0) {
    441         value += (unsigned long) ':';
    442 	len--;
    443     }
    444     switch (len) {
    445         case 10: value += name[9];
    446         case 9: value += name[8];
    447         case 8: value += name[7];
    448         case 7: value += name[6];
    449         case 6: value += name[5];
    450         case 5: value += name[4];
    451         case 4: value += name[3];
    452         case 3: value += name[2];
    453         case 2: value += name[1];
    454         case 1: value += name[0];
    455         default: break;
    456     }
    457     return(value);
    458 }
    459 
    460 /**
    461  * xmlDictCreate:
    462  *
    463  * Create a new dictionary
    464  *
    465  * Returns the newly created dictionnary, or NULL if an error occured.
    466  */
    467 xmlDictPtr
    468 xmlDictCreate(void) {
    469     xmlDictPtr dict;
    470 
    471     if (!xmlDictInitialized)
    472         if (!xmlInitializeDict())
    473             return(NULL);
    474 
    475 #ifdef DICT_DEBUG_PATTERNS
    476     fprintf(stderr, "C");
    477 #endif
    478 
    479     dict = xmlMalloc(sizeof(xmlDict));
    480     if (dict) {
    481         dict->ref_counter = 1;
    482 
    483         dict->size = MIN_DICT_SIZE;
    484 	dict->nbElems = 0;
    485         dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
    486 	dict->strings = NULL;
    487 	dict->subdict = NULL;
    488         if (dict->dict) {
    489 	    memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
    490 #ifdef DICT_RANDOMIZATION
    491             dict->seed = rand();
    492 #else
    493             dict->seed = 0;
    494 #endif
    495 	    return(dict);
    496         }
    497         xmlFree(dict);
    498     }
    499     return(NULL);
    500 }
    501 
    502 /**
    503  * xmlDictCreateSub:
    504  * @sub: an existing dictionnary
    505  *
    506  * Create a new dictionary, inheriting strings from the read-only
    507  * dictionnary @sub. On lookup, strings are first searched in the
    508  * new dictionnary, then in @sub, and if not found are created in the
    509  * new dictionnary.
    510  *
    511  * Returns the newly created dictionnary, or NULL if an error occured.
    512  */
    513 xmlDictPtr
    514 xmlDictCreateSub(xmlDictPtr sub) {
    515     xmlDictPtr dict = xmlDictCreate();
    516 
    517     if ((dict != NULL) && (sub != NULL)) {
    518 #ifdef DICT_DEBUG_PATTERNS
    519         fprintf(stderr, "R");
    520 #endif
    521         dict->seed = sub->seed;
    522         dict->subdict = sub;
    523 	xmlDictReference(dict->subdict);
    524     }
    525     return(dict);
    526 }
    527 
    528 /**
    529  * xmlDictReference:
    530  * @dict: the dictionnary
    531  *
    532  * Increment the reference counter of a dictionary
    533  *
    534  * Returns 0 in case of success and -1 in case of error
    535  */
    536 int
    537 xmlDictReference(xmlDictPtr dict) {
    538     if (!xmlDictInitialized)
    539         if (!xmlInitializeDict())
    540             return(-1);
    541 
    542     if (dict == NULL) return -1;
    543     xmlRMutexLock(xmlDictMutex);
    544     dict->ref_counter++;
    545     xmlRMutexUnlock(xmlDictMutex);
    546     return(0);
    547 }
    548 
    549 /**
    550  * xmlDictGrow:
    551  * @dict: the dictionnary
    552  * @size: the new size of the dictionnary
    553  *
    554  * resize the dictionnary
    555  *
    556  * Returns 0 in case of success, -1 in case of failure
    557  */
    558 static int
    559 xmlDictGrow(xmlDictPtr dict, int size) {
    560     unsigned long key, okey;
    561     int oldsize, i;
    562     xmlDictEntryPtr iter, next;
    563     struct _xmlDictEntry *olddict;
    564 #ifdef DEBUG_GROW
    565     unsigned long nbElem = 0;
    566 #endif
    567     int ret = 0;
    568     int keep_keys = 1;
    569 
    570     if (dict == NULL)
    571 	return(-1);
    572     if (size < 8)
    573         return(-1);
    574     if (size > 8 * 2048)
    575 	return(-1);
    576 
    577 #ifdef DICT_DEBUG_PATTERNS
    578     fprintf(stderr, "*");
    579 #endif
    580 
    581     oldsize = dict->size;
    582     olddict = dict->dict;
    583     if (olddict == NULL)
    584         return(-1);
    585     if (oldsize == MIN_DICT_SIZE)
    586         keep_keys = 0;
    587 
    588     dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
    589     if (dict->dict == NULL) {
    590 	dict->dict = olddict;
    591 	return(-1);
    592     }
    593     memset(dict->dict, 0, size * sizeof(xmlDictEntry));
    594     dict->size = size;
    595 
    596     /*	If the two loops are merged, there would be situations where
    597 	a new entry needs to allocated and data copied into it from
    598 	the main dict. It is nicer to run through the array twice, first
    599 	copying all the elements in the main array (less probability of
    600 	allocate) and then the rest, so we only free in the second loop.
    601     */
    602     for (i = 0; i < oldsize; i++) {
    603 	if (olddict[i].valid == 0)
    604 	    continue;
    605 
    606 	if (keep_keys)
    607 	    okey = olddict[i].okey;
    608 	else
    609 	    okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
    610 	key = okey % dict->size;
    611 
    612 	if (dict->dict[key].valid == 0) {
    613 	    memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
    614 	    dict->dict[key].next = NULL;
    615 	    dict->dict[key].okey = okey;
    616 	} else {
    617 	    xmlDictEntryPtr entry;
    618 
    619 	    entry = xmlMalloc(sizeof(xmlDictEntry));
    620 	    if (entry != NULL) {
    621 		entry->name = olddict[i].name;
    622 		entry->len = olddict[i].len;
    623 		entry->okey = okey;
    624 		entry->next = dict->dict[key].next;
    625 		entry->valid = 1;
    626 		dict->dict[key].next = entry;
    627 	    } else {
    628 	        /*
    629 		 * we don't have much ways to alert from herei
    630 		 * result is loosing an entry and unicity garantee
    631 		 */
    632 	        ret = -1;
    633 	    }
    634 	}
    635 #ifdef DEBUG_GROW
    636 	nbElem++;
    637 #endif
    638     }
    639 
    640     for (i = 0; i < oldsize; i++) {
    641 	iter = olddict[i].next;
    642 	while (iter) {
    643 	    next = iter->next;
    644 
    645 	    /*
    646 	     * put back the entry in the new dict
    647 	     */
    648 
    649 	    if (keep_keys)
    650 		okey = iter->okey;
    651 	    else
    652 		okey = xmlDictComputeKey(dict, iter->name, iter->len);
    653 	    key = okey % dict->size;
    654 	    if (dict->dict[key].valid == 0) {
    655 		memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
    656 		dict->dict[key].next = NULL;
    657 		dict->dict[key].valid = 1;
    658 		dict->dict[key].okey = okey;
    659 		xmlFree(iter);
    660 	    } else {
    661 		iter->next = dict->dict[key].next;
    662 		iter->okey = okey;
    663 		dict->dict[key].next = iter;
    664 	    }
    665 
    666 #ifdef DEBUG_GROW
    667 	    nbElem++;
    668 #endif
    669 
    670 	    iter = next;
    671 	}
    672     }
    673 
    674     xmlFree(olddict);
    675 
    676 #ifdef DEBUG_GROW
    677     xmlGenericError(xmlGenericErrorContext,
    678 	    "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
    679 #endif
    680 
    681     return(ret);
    682 }
    683 
    684 /**
    685  * xmlDictFree:
    686  * @dict: the dictionnary
    687  *
    688  * Free the hash @dict and its contents. The userdata is
    689  * deallocated with @f if provided.
    690  */
    691 void
    692 xmlDictFree(xmlDictPtr dict) {
    693     int i;
    694     xmlDictEntryPtr iter;
    695     xmlDictEntryPtr next;
    696     int inside_dict = 0;
    697     xmlDictStringsPtr pool, nextp;
    698 
    699     if (dict == NULL)
    700 	return;
    701 
    702     if (!xmlDictInitialized)
    703         if (!xmlInitializeDict())
    704             return;
    705 
    706     /* decrement the counter, it may be shared by a parser and docs */
    707     xmlRMutexLock(xmlDictMutex);
    708     dict->ref_counter--;
    709     if (dict->ref_counter > 0) {
    710         xmlRMutexUnlock(xmlDictMutex);
    711         return;
    712     }
    713 
    714     xmlRMutexUnlock(xmlDictMutex);
    715 
    716     if (dict->subdict != NULL) {
    717         xmlDictFree(dict->subdict);
    718     }
    719 
    720     if (dict->dict) {
    721 	for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
    722 	    iter = &(dict->dict[i]);
    723 	    if (iter->valid == 0)
    724 		continue;
    725 	    inside_dict = 1;
    726 	    while (iter) {
    727 		next = iter->next;
    728 		if (!inside_dict)
    729 		    xmlFree(iter);
    730 		dict->nbElems--;
    731 		inside_dict = 0;
    732 		iter = next;
    733 	    }
    734 	}
    735 	xmlFree(dict->dict);
    736     }
    737     pool = dict->strings;
    738     while (pool != NULL) {
    739         nextp = pool->next;
    740 	xmlFree(pool);
    741 	pool = nextp;
    742     }
    743     xmlFree(dict);
    744 }
    745 
    746 /**
    747  * xmlDictLookup:
    748  * @dict: the dictionnary
    749  * @name: the name of the userdata
    750  * @len: the length of the name, if -1 it is recomputed
    751  *
    752  * Add the @name to the dictionnary @dict if not present.
    753  *
    754  * Returns the internal copy of the name or NULL in case of internal error
    755  */
    756 const xmlChar *
    757 xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
    758     unsigned long key, okey, nbi = 0;
    759     xmlDictEntryPtr entry;
    760     xmlDictEntryPtr insert;
    761     const xmlChar *ret;
    762 
    763     if ((dict == NULL) || (name == NULL))
    764 	return(NULL);
    765 
    766     if (len < 0)
    767         len = strlen((const char *) name);
    768 
    769     /*
    770      * Check for duplicate and insertion location.
    771      */
    772     okey = xmlDictComputeKey(dict, name, len);
    773     key = okey % dict->size;
    774     if (dict->dict[key].valid == 0) {
    775 	insert = NULL;
    776     } else {
    777 	for (insert = &(dict->dict[key]); insert->next != NULL;
    778 	     insert = insert->next) {
    779 #ifdef __GNUC__
    780 	    if ((insert->okey == okey) && (insert->len == len)) {
    781 		if (!memcmp(insert->name, name, len))
    782 		    return(insert->name);
    783 	    }
    784 #else
    785 	    if ((insert->okey == okey) && (insert->len == len) &&
    786 	        (!xmlStrncmp(insert->name, name, len)))
    787 		return(insert->name);
    788 #endif
    789 	    nbi++;
    790 	}
    791 #ifdef __GNUC__
    792 	if ((insert->okey == okey) && (insert->len == len)) {
    793 	    if (!memcmp(insert->name, name, len))
    794 		return(insert->name);
    795 	}
    796 #else
    797 	if ((insert->okey == okey) && (insert->len == len) &&
    798 	    (!xmlStrncmp(insert->name, name, len)))
    799 	    return(insert->name);
    800 #endif
    801     }
    802 
    803     if (dict->subdict) {
    804         unsigned long skey;
    805 
    806         /* we cannot always reuse the same okey for the subdict */
    807         if (((dict->size == MIN_DICT_SIZE) &&
    808 	     (dict->subdict->size != MIN_DICT_SIZE)) ||
    809             ((dict->size != MIN_DICT_SIZE) &&
    810 	     (dict->subdict->size == MIN_DICT_SIZE)))
    811 	    skey = xmlDictComputeKey(dict->subdict, name, len);
    812 	else
    813 	    skey = okey;
    814 
    815 	key = skey % dict->subdict->size;
    816 	if (dict->subdict->dict[key].valid != 0) {
    817 	    xmlDictEntryPtr tmp;
    818 
    819 	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
    820 		 tmp = tmp->next) {
    821 #ifdef __GNUC__
    822 		if ((tmp->okey == skey) && (tmp->len == len)) {
    823 		    if (!memcmp(tmp->name, name, len))
    824 			return(tmp->name);
    825 		}
    826 #else
    827 		if ((tmp->okey == skey) && (tmp->len == len) &&
    828 		    (!xmlStrncmp(tmp->name, name, len)))
    829 		    return(tmp->name);
    830 #endif
    831 		nbi++;
    832 	    }
    833 #ifdef __GNUC__
    834 	    if ((tmp->okey == skey) && (tmp->len == len)) {
    835 		if (!memcmp(tmp->name, name, len))
    836 		    return(tmp->name);
    837 	    }
    838 #else
    839 	    if ((tmp->okey == skey) && (tmp->len == len) &&
    840 		(!xmlStrncmp(tmp->name, name, len)))
    841 		return(tmp->name);
    842 #endif
    843 	}
    844 	key = okey % dict->size;
    845     }
    846 
    847     ret = xmlDictAddString(dict, name, len);
    848     if (ret == NULL)
    849         return(NULL);
    850     if (insert == NULL) {
    851 	entry = &(dict->dict[key]);
    852     } else {
    853 	entry = xmlMalloc(sizeof(xmlDictEntry));
    854 	if (entry == NULL)
    855 	     return(NULL);
    856     }
    857     entry->name = ret;
    858     entry->len = len;
    859     entry->next = NULL;
    860     entry->valid = 1;
    861     entry->okey = okey;
    862 
    863 
    864     if (insert != NULL)
    865 	insert->next = entry;
    866 
    867     dict->nbElems++;
    868 
    869     if ((nbi > MAX_HASH_LEN) &&
    870         (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
    871 	if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
    872 	    return(NULL);
    873     }
    874     /* Note that entry may have been freed at this point by xmlDictGrow */
    875 
    876     return(ret);
    877 }
    878 
    879 /**
    880  * xmlDictExists:
    881  * @dict: the dictionnary
    882  * @name: the name of the userdata
    883  * @len: the length of the name, if -1 it is recomputed
    884  *
    885  * Check if the @name exists in the dictionnary @dict.
    886  *
    887  * Returns the internal copy of the name or NULL if not found.
    888  */
    889 const xmlChar *
    890 xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
    891     unsigned long key, okey, nbi = 0;
    892     xmlDictEntryPtr insert;
    893 
    894     if ((dict == NULL) || (name == NULL))
    895 	return(NULL);
    896 
    897     if (len < 0)
    898         len = strlen((const char *) name);
    899 
    900     /*
    901      * Check for duplicate and insertion location.
    902      */
    903     okey = xmlDictComputeKey(dict, name, len);
    904     key = okey % dict->size;
    905     if (dict->dict[key].valid == 0) {
    906 	insert = NULL;
    907     } else {
    908 	for (insert = &(dict->dict[key]); insert->next != NULL;
    909 	     insert = insert->next) {
    910 #ifdef __GNUC__
    911 	    if ((insert->okey == okey) && (insert->len == len)) {
    912 		if (!memcmp(insert->name, name, len))
    913 		    return(insert->name);
    914 	    }
    915 #else
    916 	    if ((insert->okey == okey) && (insert->len == len) &&
    917 	        (!xmlStrncmp(insert->name, name, len)))
    918 		return(insert->name);
    919 #endif
    920 	    nbi++;
    921 	}
    922 #ifdef __GNUC__
    923 	if ((insert->okey == okey) && (insert->len == len)) {
    924 	    if (!memcmp(insert->name, name, len))
    925 		return(insert->name);
    926 	}
    927 #else
    928 	if ((insert->okey == okey) && (insert->len == len) &&
    929 	    (!xmlStrncmp(insert->name, name, len)))
    930 	    return(insert->name);
    931 #endif
    932     }
    933 
    934     if (dict->subdict) {
    935         unsigned long skey;
    936 
    937         /* we cannot always reuse the same okey for the subdict */
    938         if (((dict->size == MIN_DICT_SIZE) &&
    939 	     (dict->subdict->size != MIN_DICT_SIZE)) ||
    940             ((dict->size != MIN_DICT_SIZE) &&
    941 	     (dict->subdict->size == MIN_DICT_SIZE)))
    942 	    skey = xmlDictComputeKey(dict->subdict, name, len);
    943 	else
    944 	    skey = okey;
    945 
    946 	key = skey % dict->subdict->size;
    947 	if (dict->subdict->dict[key].valid != 0) {
    948 	    xmlDictEntryPtr tmp;
    949 
    950 	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
    951 		 tmp = tmp->next) {
    952 #ifdef __GNUC__
    953 		if ((tmp->okey == skey) && (tmp->len == len)) {
    954 		    if (!memcmp(tmp->name, name, len))
    955 			return(tmp->name);
    956 		}
    957 #else
    958 		if ((tmp->okey == skey) && (tmp->len == len) &&
    959 		    (!xmlStrncmp(tmp->name, name, len)))
    960 		    return(tmp->name);
    961 #endif
    962 		nbi++;
    963 	    }
    964 #ifdef __GNUC__
    965 	    if ((tmp->okey == skey) && (tmp->len == len)) {
    966 		if (!memcmp(tmp->name, name, len))
    967 		    return(tmp->name);
    968 	    }
    969 #else
    970 	    if ((tmp->okey == skey) && (tmp->len == len) &&
    971 		(!xmlStrncmp(tmp->name, name, len)))
    972 		return(tmp->name);
    973 #endif
    974 	}
    975     }
    976 
    977     /* not found */
    978     return(NULL);
    979 }
    980 
    981 /**
    982  * xmlDictQLookup:
    983  * @dict: the dictionnary
    984  * @prefix: the prefix
    985  * @name: the name
    986  *
    987  * Add the QName @prefix:@name to the hash @dict if not present.
    988  *
    989  * Returns the internal copy of the QName or NULL in case of internal error
    990  */
    991 const xmlChar *
    992 xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
    993     unsigned long okey, key, nbi = 0;
    994     xmlDictEntryPtr entry;
    995     xmlDictEntryPtr insert;
    996     const xmlChar *ret;
    997     int len, plen, l;
    998 
    999     if ((dict == NULL) || (name == NULL))
   1000 	return(NULL);
   1001     if (prefix == NULL)
   1002         return(xmlDictLookup(dict, name, -1));
   1003 
   1004     l = len = strlen((const char *) name);
   1005     plen = strlen((const char *) prefix);
   1006     len += 1 + plen;
   1007 
   1008     /*
   1009      * Check for duplicate and insertion location.
   1010      */
   1011     okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
   1012     key = okey % dict->size;
   1013     if (dict->dict[key].valid == 0) {
   1014 	insert = NULL;
   1015     } else {
   1016 	for (insert = &(dict->dict[key]); insert->next != NULL;
   1017 	     insert = insert->next) {
   1018 	    if ((insert->okey == okey) && (insert->len == len) &&
   1019 	        (xmlStrQEqual(prefix, name, insert->name)))
   1020 		return(insert->name);
   1021 	    nbi++;
   1022 	}
   1023 	if ((insert->okey == okey) && (insert->len == len) &&
   1024 	    (xmlStrQEqual(prefix, name, insert->name)))
   1025 	    return(insert->name);
   1026     }
   1027 
   1028     if (dict->subdict) {
   1029         unsigned long skey;
   1030 
   1031         /* we cannot always reuse the same okey for the subdict */
   1032         if (((dict->size == MIN_DICT_SIZE) &&
   1033 	     (dict->subdict->size != MIN_DICT_SIZE)) ||
   1034             ((dict->size != MIN_DICT_SIZE) &&
   1035 	     (dict->subdict->size == MIN_DICT_SIZE)))
   1036 	    skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
   1037 	else
   1038 	    skey = okey;
   1039 
   1040 	key = skey % dict->subdict->size;
   1041 	if (dict->subdict->dict[key].valid != 0) {
   1042 	    xmlDictEntryPtr tmp;
   1043 	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
   1044 		 tmp = tmp->next) {
   1045 		if ((tmp->okey == skey) && (tmp->len == len) &&
   1046 		    (xmlStrQEqual(prefix, name, tmp->name)))
   1047 		    return(tmp->name);
   1048 		nbi++;
   1049 	    }
   1050 	    if ((tmp->okey == skey) && (tmp->len == len) &&
   1051 		(xmlStrQEqual(prefix, name, tmp->name)))
   1052 		return(tmp->name);
   1053 	}
   1054 	key = okey % dict->size;
   1055     }
   1056 
   1057     ret = xmlDictAddQString(dict, prefix, plen, name, l);
   1058     if (ret == NULL)
   1059         return(NULL);
   1060     if (insert == NULL) {
   1061 	entry = &(dict->dict[key]);
   1062     } else {
   1063 	entry = xmlMalloc(sizeof(xmlDictEntry));
   1064 	if (entry == NULL)
   1065 	     return(NULL);
   1066     }
   1067     entry->name = ret;
   1068     entry->len = len;
   1069     entry->next = NULL;
   1070     entry->valid = 1;
   1071     entry->okey = okey;
   1072 
   1073     if (insert != NULL)
   1074 	insert->next = entry;
   1075 
   1076     dict->nbElems++;
   1077 
   1078     if ((nbi > MAX_HASH_LEN) &&
   1079         (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
   1080 	xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
   1081     /* Note that entry may have been freed at this point by xmlDictGrow */
   1082 
   1083     return(ret);
   1084 }
   1085 
   1086 /**
   1087  * xmlDictOwns:
   1088  * @dict: the dictionnary
   1089  * @str: the string
   1090  *
   1091  * check if a string is owned by the disctionary
   1092  *
   1093  * Returns 1 if true, 0 if false and -1 in case of error
   1094  * -1 in case of error
   1095  */
   1096 int
   1097 xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
   1098     xmlDictStringsPtr pool;
   1099 
   1100     if ((dict == NULL) || (str == NULL))
   1101 	return(-1);
   1102     pool = dict->strings;
   1103     while (pool != NULL) {
   1104         if ((str >= &pool->array[0]) && (str <= pool->free))
   1105 	    return(1);
   1106 	pool = pool->next;
   1107     }
   1108     if (dict->subdict)
   1109         return(xmlDictOwns(dict->subdict, str));
   1110     return(0);
   1111 }
   1112 
   1113 /**
   1114  * xmlDictSize:
   1115  * @dict: the dictionnary
   1116  *
   1117  * Query the number of elements installed in the hash @dict.
   1118  *
   1119  * Returns the number of elements in the dictionnary or
   1120  * -1 in case of error
   1121  */
   1122 int
   1123 xmlDictSize(xmlDictPtr dict) {
   1124     if (dict == NULL)
   1125 	return(-1);
   1126     if (dict->subdict)
   1127         return(dict->nbElems + dict->subdict->nbElems);
   1128     return(dict->nbElems);
   1129 }
   1130 
   1131 
   1132 #define bottom_dict
   1133 #include "elfgcchack.h"
   1134