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