(root)/
libxml2-2.12.3/
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   * MERCHANTABILITY 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  #include <string.h>
      24  #include <time.h>
      25  
      26  #include "private/dict.h"
      27  #include "private/threads.h"
      28  
      29  #include <libxml/parser.h>
      30  #include <libxml/dict.h>
      31  #include <libxml/xmlmemory.h>
      32  #include <libxml/xmlstring.h>
      33  
      34  #ifndef SIZE_MAX
      35    #define SIZE_MAX ((size_t) -1)
      36  #endif
      37  
      38  #define MAX_FILL_NUM 7
      39  #define MAX_FILL_DENOM 8
      40  #define MIN_HASH_SIZE 8
      41  #define MAX_HASH_SIZE (1u << 31)
      42  
      43  typedef struct _xmlDictStrings xmlDictStrings;
      44  typedef xmlDictStrings *xmlDictStringsPtr;
      45  struct _xmlDictStrings {
      46      xmlDictStringsPtr next;
      47      xmlChar *free;
      48      xmlChar *end;
      49      size_t size;
      50      size_t nbStrings;
      51      xmlChar array[1];
      52  };
      53  
      54  typedef xmlHashedString xmlDictEntry;
      55  
      56  /*
      57   * The entire dictionary
      58   */
      59  struct _xmlDict {
      60      int ref_counter;
      61  
      62      xmlDictEntry *table;
      63      size_t size;
      64      unsigned int nbElems;
      65      xmlDictStringsPtr strings;
      66  
      67      struct _xmlDict *subdict;
      68      /* used for randomization */
      69      unsigned seed;
      70      /* used to impose a limit on size */
      71      size_t limit;
      72  };
      73  
      74  /*
      75   * A mutex for modifying the reference counter for shared
      76   * dictionaries.
      77   */
      78  static xmlMutex xmlDictMutex;
      79  
      80  /**
      81   * xmlInitializeDict:
      82   *
      83   * DEPRECATED: Alias for xmlInitParser.
      84   *
      85   * Returns 0.
      86   */
      87  int
      88  xmlInitializeDict(void) {
      89      xmlInitParser();
      90      return(0);
      91  }
      92  
      93  /**
      94   * xmlInitDictInternal:
      95   *
      96   * Initialize mutex.
      97   */
      98  void
      99  xmlInitDictInternal(void) {
     100      xmlInitMutex(&xmlDictMutex);
     101  }
     102  
     103  /**
     104   * xmlDictCleanup:
     105   *
     106   * DEPRECATED: This function is a no-op. Call xmlCleanupParser
     107   * to free global state but see the warnings there. xmlCleanupParser
     108   * should be only called once at program exit. In most cases, you don't
     109   * have call cleanup functions at all.
     110   */
     111  void
     112  xmlDictCleanup(void) {
     113  }
     114  
     115  /**
     116   * xmlCleanupDictInternal:
     117   *
     118   * Free the dictionary mutex.
     119   */
     120  void
     121  xmlCleanupDictInternal(void) {
     122      xmlCleanupMutex(&xmlDictMutex);
     123  }
     124  
     125  /*
     126   * xmlDictAddString:
     127   * @dict: the dictionary
     128   * @name: the name of the userdata
     129   * @len: the length of the name
     130   *
     131   * Add the string to the array[s]
     132   *
     133   * Returns the pointer of the local string, or NULL in case of error.
     134   */
     135  static const xmlChar *
     136  xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
     137      xmlDictStringsPtr pool;
     138      const xmlChar *ret;
     139      size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
     140      size_t limit = 0;
     141  
     142      pool = dict->strings;
     143      while (pool != NULL) {
     144  	if ((size_t)(pool->end - pool->free) > namelen)
     145  	    goto found_pool;
     146  	if (pool->size > size) size = pool->size;
     147          limit += pool->size;
     148  	pool = pool->next;
     149      }
     150      /*
     151       * Not found, need to allocate
     152       */
     153      if (pool == NULL) {
     154          if ((dict->limit > 0) && (limit > dict->limit)) {
     155              return(NULL);
     156          }
     157  
     158          if (size == 0) {
     159              size = 1000;
     160          } else {
     161              if (size < (SIZE_MAX - sizeof(xmlDictStrings)) / 4)
     162                  size *= 4; /* exponential growth */
     163              else
     164                  size = SIZE_MAX - sizeof(xmlDictStrings);
     165          }
     166          if (size / 4 < namelen) {
     167              if ((size_t) namelen + 0 < (SIZE_MAX - sizeof(xmlDictStrings)) / 4)
     168                  size = 4 * (size_t) namelen; /* just in case ! */
     169              else
     170                  return(NULL);
     171          }
     172  	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
     173  	if (pool == NULL)
     174  	    return(NULL);
     175  	pool->size = size;
     176  	pool->nbStrings = 0;
     177  	pool->free = &pool->array[0];
     178  	pool->end = &pool->array[size];
     179  	pool->next = dict->strings;
     180  	dict->strings = pool;
     181      }
     182  found_pool:
     183      ret = pool->free;
     184      memcpy(pool->free, name, namelen);
     185      pool->free += namelen;
     186      *(pool->free++) = 0;
     187      pool->nbStrings++;
     188      return(ret);
     189  }
     190  
     191  /*
     192   * xmlDictAddQString:
     193   * @dict: the dictionary
     194   * @prefix: the prefix of the userdata
     195   * @plen: the prefix length
     196   * @name: the name of the userdata
     197   * @len: the length of the name
     198   *
     199   * Add the QName to the array[s]
     200   *
     201   * Returns the pointer of the local string, or NULL in case of error.
     202   */
     203  static const xmlChar *
     204  xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
     205                   const xmlChar *name, unsigned int namelen)
     206  {
     207      xmlDictStringsPtr pool;
     208      const xmlChar *ret;
     209      size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
     210      size_t limit = 0;
     211  
     212      pool = dict->strings;
     213      while (pool != NULL) {
     214  	if ((size_t)(pool->end - pool->free) > namelen + plen + 1)
     215  	    goto found_pool;
     216  	if (pool->size > size) size = pool->size;
     217          limit += pool->size;
     218  	pool = pool->next;
     219      }
     220      /*
     221       * Not found, need to allocate
     222       */
     223      if (pool == NULL) {
     224          if ((dict->limit > 0) && (limit > dict->limit)) {
     225              return(NULL);
     226          }
     227  
     228          if (size == 0) size = 1000;
     229  	else size *= 4; /* exponential growth */
     230          if (size < 4 * (namelen + plen + 1))
     231  	    size = 4 * (namelen + plen + 1); /* just in case ! */
     232  	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
     233  	if (pool == NULL)
     234  	    return(NULL);
     235  	pool->size = size;
     236  	pool->nbStrings = 0;
     237  	pool->free = &pool->array[0];
     238  	pool->end = &pool->array[size];
     239  	pool->next = dict->strings;
     240  	dict->strings = pool;
     241      }
     242  found_pool:
     243      ret = pool->free;
     244      memcpy(pool->free, prefix, plen);
     245      pool->free += plen;
     246      *(pool->free++) = ':';
     247      memcpy(pool->free, name, namelen);
     248      pool->free += namelen;
     249      *(pool->free++) = 0;
     250      pool->nbStrings++;
     251      return(ret);
     252  }
     253  
     254  /**
     255   * xmlDictCreate:
     256   *
     257   * Create a new dictionary
     258   *
     259   * Returns the newly created dictionary, or NULL if an error occurred.
     260   */
     261  xmlDictPtr
     262  xmlDictCreate(void) {
     263      xmlDictPtr dict;
     264  
     265      xmlInitParser();
     266  
     267      dict = xmlMalloc(sizeof(xmlDict));
     268      if (dict == NULL)
     269          return(NULL);
     270      dict->ref_counter = 1;
     271      dict->limit = 0;
     272  
     273      dict->size = 0;
     274      dict->nbElems = 0;
     275      dict->table = NULL;
     276      dict->strings = NULL;
     277      dict->subdict = NULL;
     278      dict->seed = xmlRandom();
     279  #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
     280      dict->seed = 0;
     281  #endif
     282      return(dict);
     283  }
     284  
     285  /**
     286   * xmlDictCreateSub:
     287   * @sub: an existing dictionary
     288   *
     289   * Create a new dictionary, inheriting strings from the read-only
     290   * dictionary @sub. On lookup, strings are first searched in the
     291   * new dictionary, then in @sub, and if not found are created in the
     292   * new dictionary.
     293   *
     294   * Returns the newly created dictionary, or NULL if an error occurred.
     295   */
     296  xmlDictPtr
     297  xmlDictCreateSub(xmlDictPtr sub) {
     298      xmlDictPtr dict = xmlDictCreate();
     299  
     300      if ((dict != NULL) && (sub != NULL)) {
     301          dict->seed = sub->seed;
     302          dict->subdict = sub;
     303  	xmlDictReference(dict->subdict);
     304      }
     305      return(dict);
     306  }
     307  
     308  /**
     309   * xmlDictReference:
     310   * @dict: the dictionary
     311   *
     312   * Increment the reference counter of a dictionary
     313   *
     314   * Returns 0 in case of success and -1 in case of error
     315   */
     316  int
     317  xmlDictReference(xmlDictPtr dict) {
     318      if (dict == NULL) return -1;
     319      xmlMutexLock(&xmlDictMutex);
     320      dict->ref_counter++;
     321      xmlMutexUnlock(&xmlDictMutex);
     322      return(0);
     323  }
     324  
     325  /**
     326   * xmlDictFree:
     327   * @dict: the dictionary
     328   *
     329   * Free the hash @dict and its contents. The userdata is
     330   * deallocated with @f if provided.
     331   */
     332  void
     333  xmlDictFree(xmlDictPtr dict) {
     334      xmlDictStringsPtr pool, nextp;
     335  
     336      if (dict == NULL)
     337  	return;
     338  
     339      /* decrement the counter, it may be shared by a parser and docs */
     340      xmlMutexLock(&xmlDictMutex);
     341      dict->ref_counter--;
     342      if (dict->ref_counter > 0) {
     343          xmlMutexUnlock(&xmlDictMutex);
     344          return;
     345      }
     346  
     347      xmlMutexUnlock(&xmlDictMutex);
     348  
     349      if (dict->subdict != NULL) {
     350          xmlDictFree(dict->subdict);
     351      }
     352  
     353      if (dict->table) {
     354  	xmlFree(dict->table);
     355      }
     356      pool = dict->strings;
     357      while (pool != NULL) {
     358          nextp = pool->next;
     359  	xmlFree(pool);
     360  	pool = nextp;
     361      }
     362      xmlFree(dict);
     363  }
     364  
     365  /**
     366   * xmlDictOwns:
     367   * @dict: the dictionary
     368   * @str: the string
     369   *
     370   * check if a string is owned by the dictionary
     371   *
     372   * Returns 1 if true, 0 if false and -1 in case of error
     373   * -1 in case of error
     374   */
     375  int
     376  xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
     377      xmlDictStringsPtr pool;
     378  
     379      if ((dict == NULL) || (str == NULL))
     380  	return(-1);
     381      pool = dict->strings;
     382      while (pool != NULL) {
     383          if ((str >= &pool->array[0]) && (str <= pool->free))
     384  	    return(1);
     385  	pool = pool->next;
     386      }
     387      if (dict->subdict)
     388          return(xmlDictOwns(dict->subdict, str));
     389      return(0);
     390  }
     391  
     392  /**
     393   * xmlDictSize:
     394   * @dict: the dictionary
     395   *
     396   * Query the number of elements installed in the hash @dict.
     397   *
     398   * Returns the number of elements in the dictionary or
     399   * -1 in case of error
     400   */
     401  int
     402  xmlDictSize(xmlDictPtr dict) {
     403      if (dict == NULL)
     404  	return(-1);
     405      if (dict->subdict)
     406          return(dict->nbElems + dict->subdict->nbElems);
     407      return(dict->nbElems);
     408  }
     409  
     410  /**
     411   * xmlDictSetLimit:
     412   * @dict: the dictionary
     413   * @limit: the limit in bytes
     414   *
     415   * Set a size limit for the dictionary
     416   * Added in 2.9.0
     417   *
     418   * Returns the previous limit of the dictionary or 0
     419   */
     420  size_t
     421  xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
     422      size_t ret;
     423  
     424      if (dict == NULL)
     425  	return(0);
     426      ret = dict->limit;
     427      dict->limit = limit;
     428      return(ret);
     429  }
     430  
     431  /**
     432   * xmlDictGetUsage:
     433   * @dict: the dictionary
     434   *
     435   * Get how much memory is used by a dictionary for strings
     436   * Added in 2.9.0
     437   *
     438   * Returns the amount of strings allocated
     439   */
     440  size_t
     441  xmlDictGetUsage(xmlDictPtr dict) {
     442      xmlDictStringsPtr pool;
     443      size_t limit = 0;
     444  
     445      if (dict == NULL)
     446  	return(0);
     447      pool = dict->strings;
     448      while (pool != NULL) {
     449          limit += pool->size;
     450  	pool = pool->next;
     451      }
     452      return(limit);
     453  }
     454  
     455  /*****************************************************************
     456   *
     457   * The code below was rewritten and is additionally licensed under
     458   * the main license in file 'Copyright'.
     459   *
     460   *****************************************************************/
     461  
     462  ATTRIBUTE_NO_SANITIZE_INTEGER
     463  static unsigned
     464  xmlDictHashName(unsigned seed, const xmlChar* data, size_t maxLen,
     465                  size_t *plen) {
     466      unsigned h1, h2;
     467      size_t i;
     468  
     469      HASH_INIT(h1, h2, seed);
     470  
     471      for (i = 0; i < maxLen && data[i]; i++) {
     472          HASH_UPDATE(h1, h2, data[i]);
     473      }
     474  
     475      HASH_FINISH(h1, h2);
     476  
     477      *plen = i;
     478      return(h2 | MAX_HASH_SIZE);
     479  }
     480  
     481  ATTRIBUTE_NO_SANITIZE_INTEGER
     482  static unsigned
     483  xmlDictHashQName(unsigned seed, const xmlChar *prefix, const xmlChar *name,
     484                   size_t *pplen, size_t *plen) {
     485      unsigned h1, h2;
     486      size_t i;
     487  
     488      HASH_INIT(h1, h2, seed);
     489  
     490      for (i = 0; prefix[i] != 0; i++) {
     491          HASH_UPDATE(h1, h2, prefix[i]);
     492      }
     493      *pplen = i;
     494  
     495      HASH_UPDATE(h1, h2, ':');
     496  
     497      for (i = 0; name[i] != 0; i++) {
     498          HASH_UPDATE(h1, h2, name[i]);
     499      }
     500      *plen = i;
     501  
     502      HASH_FINISH(h1, h2);
     503  
     504      /*
     505       * Always set the upper bit of hash values since 0 means an unoccupied
     506       * bucket.
     507       */
     508      return(h2 | MAX_HASH_SIZE);
     509  }
     510  
     511  unsigned
     512  xmlDictComputeHash(const xmlDict *dict, const xmlChar *string) {
     513      size_t len;
     514      return(xmlDictHashName(dict->seed, string, SIZE_MAX, &len));
     515  }
     516  
     517  #define HASH_ROL31(x,n) ((x) << (n) | ((x) & 0x7FFFFFFF) >> (31 - (n)))
     518  
     519  ATTRIBUTE_NO_SANITIZE_INTEGER
     520  unsigned
     521  xmlDictCombineHash(unsigned v1, unsigned v2) {
     522      /*
     523       * The upper bit of hash values is always set, so we have to operate on
     524       * 31-bit hashes here.
     525       */
     526      v1 ^= v2;
     527      v1 += HASH_ROL31(v2, 5);
     528  
     529      return((v1 & 0xFFFFFFFF) | 0x80000000);
     530  }
     531  
     532  /**
     533   * xmlDictFindEntry:
     534   * @dict: dict
     535   * @prefix: optional QName prefix
     536   * @name: string
     537   * @len: length of string
     538   * @hashValue: valid hash value of string
     539   * @pfound: result of search
     540   *
     541   * Try to find a matching hash table entry. If an entry was found, set
     542   * @found to 1 and return the entry. Otherwise, set @found to 0 and return
     543   * the location where a new entry should be inserted.
     544   */
     545  ATTRIBUTE_NO_SANITIZE_INTEGER
     546  static xmlDictEntry *
     547  xmlDictFindEntry(const xmlDict *dict, const xmlChar *prefix,
     548                   const xmlChar *name, int len, unsigned hashValue,
     549                   int *pfound) {
     550      xmlDictEntry *entry;
     551      unsigned mask, pos, displ;
     552      int found = 0;
     553  
     554      mask = dict->size - 1;
     555      pos = hashValue & mask;
     556      entry = &dict->table[pos];
     557  
     558      if (entry->hashValue != 0) {
     559          /*
     560           * Robin hood hashing: abort if the displacement of the entry
     561           * is smaller than the displacement of the key we look for.
     562           * This also stops at the correct position when inserting.
     563           */
     564          displ = 0;
     565  
     566          do {
     567              if (entry->hashValue == hashValue) {
     568                  if (prefix == NULL) {
     569                      /*
     570                       * name is not necessarily null-terminated.
     571                       */
     572                      if ((strncmp((const char *) entry->name,
     573                                   (const char *) name, len) == 0) &&
     574                          (entry->name[len] == 0)) {
     575                          found = 1;
     576                          break;
     577                      }
     578                  } else {
     579                      if (xmlStrQEqual(prefix, name, entry->name)) {
     580                          found = 1;
     581                          break;
     582                      }
     583                  }
     584              }
     585  
     586              displ++;
     587              pos++;
     588              entry++;
     589              if ((pos & mask) == 0)
     590                  entry = dict->table;
     591          } while ((entry->hashValue != 0) &&
     592                   (((pos - entry->hashValue) & mask) >= displ));
     593      }
     594  
     595      *pfound = found;
     596      return(entry);
     597  }
     598  
     599  /**
     600   * xmlDictGrow:
     601   * @dict: dictionary
     602   * @size: new size of the dictionary
     603   *
     604   * Resize the dictionary hash table.
     605   *
     606   * Returns 0 in case of success, -1 if a memory allocation failed.
     607   */
     608  static int
     609  xmlDictGrow(xmlDictPtr dict, unsigned size) {
     610      const xmlDictEntry *oldentry, *oldend, *end;
     611      xmlDictEntry *table;
     612      unsigned oldsize, i;
     613  
     614      /* Add 0 to avoid spurious -Wtype-limits warning on 64-bit GCC */
     615      if ((size_t) size + 0 > SIZE_MAX / sizeof(table[0]))
     616          return(-1);
     617      table = xmlMalloc(size * sizeof(table[0]));
     618      if (table == NULL)
     619          return(-1);
     620      memset(table, 0, size * sizeof(table[0]));
     621  
     622      oldsize = dict->size;
     623      if (oldsize == 0)
     624          goto done;
     625  
     626      oldend = &dict->table[oldsize];
     627      end = &table[size];
     628  
     629      /*
     630       * Robin Hood sorting order is maintained if we
     631       *
     632       * - compute dict indices with modulo
     633       * - resize by an integer factor
     634       * - start to copy from the beginning of a probe sequence
     635       */
     636      oldentry = dict->table;
     637      while (oldentry->hashValue != 0) {
     638          if (++oldentry >= oldend)
     639              oldentry = dict->table;
     640      }
     641  
     642      for (i = 0; i < oldsize; i++) {
     643          if (oldentry->hashValue != 0) {
     644              xmlDictEntry *entry = &table[oldentry->hashValue & (size - 1)];
     645  
     646              while (entry->hashValue != 0) {
     647                  if (++entry >= end)
     648                      entry = table;
     649              }
     650              *entry = *oldentry;
     651          }
     652  
     653          if (++oldentry >= oldend)
     654              oldentry = dict->table;
     655      }
     656  
     657      xmlFree(dict->table);
     658  
     659  done:
     660      dict->table = table;
     661      dict->size = size;
     662  
     663      return(0);
     664  }
     665  
     666  /**
     667   * xmlDictLookupInternal:
     668   * @dict: dict
     669   * @prefix: optional QName prefix
     670   * @name: string
     671   * @maybeLen: length of string or -1 if unknown
     672   * @update: whether the string should be added
     673   *
     674   * Internal lookup and update function.
     675   */
     676  ATTRIBUTE_NO_SANITIZE_INTEGER
     677  static const xmlDictEntry *
     678  xmlDictLookupInternal(xmlDictPtr dict, const xmlChar *prefix,
     679                        const xmlChar *name, int maybeLen, int update) {
     680      xmlDictEntry *entry = NULL;
     681      const xmlChar *ret;
     682      unsigned hashValue;
     683      size_t maxLen, len, plen, klen;
     684      int found = 0;
     685  
     686      if ((dict == NULL) || (name == NULL))
     687  	return(NULL);
     688  
     689      maxLen = (maybeLen < 0) ? SIZE_MAX : (size_t) maybeLen;
     690  
     691      if (prefix == NULL) {
     692          hashValue = xmlDictHashName(dict->seed, name, maxLen, &len);
     693          if (len > INT_MAX / 2)
     694              return(NULL);
     695          klen = len;
     696      } else {
     697          hashValue = xmlDictHashQName(dict->seed, prefix, name, &plen, &len);
     698          if ((len > INT_MAX / 2) || (plen >= INT_MAX / 2 - len))
     699              return(NULL);
     700          klen = plen + 1 + len;
     701      }
     702  
     703      if ((dict->limit > 0) && (klen >= dict->limit))
     704          return(NULL);
     705  
     706      /*
     707       * Check for an existing entry
     708       */
     709      if (dict->size > 0)
     710          entry = xmlDictFindEntry(dict, prefix, name, klen, hashValue, &found);
     711      if (found)
     712          return(entry);
     713  
     714      if ((dict->subdict != NULL) && (dict->subdict->size > 0)) {
     715          xmlDictEntry *subEntry;
     716          unsigned subHashValue;
     717  
     718          if (prefix == NULL)
     719              subHashValue = xmlDictHashName(dict->subdict->seed, name, len,
     720                                             &len);
     721          else
     722              subHashValue = xmlDictHashQName(dict->subdict->seed, prefix, name,
     723                                              &plen, &len);
     724          subEntry = xmlDictFindEntry(dict->subdict, prefix, name, klen,
     725                                      subHashValue, &found);
     726          if (found)
     727              return(subEntry);
     728      }
     729  
     730      if (!update)
     731          return(NULL);
     732  
     733      /*
     734       * Grow the hash table if needed
     735       */
     736      if (dict->nbElems + 1 > dict->size / MAX_FILL_DENOM * MAX_FILL_NUM) {
     737          unsigned newSize, mask, displ, pos;
     738  
     739          if (dict->size == 0) {
     740              newSize = MIN_HASH_SIZE;
     741          } else {
     742              if (dict->size >= MAX_HASH_SIZE)
     743                  return(NULL);
     744              newSize = dict->size * 2;
     745          }
     746          if (xmlDictGrow(dict, newSize) != 0)
     747              return(NULL);
     748  
     749          /*
     750           * Find new entry
     751           */
     752          mask = dict->size - 1;
     753          displ = 0;
     754          pos = hashValue & mask;
     755          entry = &dict->table[pos];
     756  
     757          while ((entry->hashValue != 0) &&
     758                 ((pos - entry->hashValue) & mask) >= displ) {
     759              displ++;
     760              pos++;
     761              entry++;
     762              if ((pos & mask) == 0)
     763                  entry = dict->table;
     764          }
     765      }
     766  
     767      if (prefix == NULL)
     768          ret = xmlDictAddString(dict, name, len);
     769      else
     770          ret = xmlDictAddQString(dict, prefix, plen, name, len);
     771      if (ret == NULL)
     772          return(NULL);
     773  
     774      /*
     775       * Shift the remainder of the probe sequence to the right
     776       */
     777      if (entry->hashValue != 0) {
     778          const xmlDictEntry *end = &dict->table[dict->size];
     779          const xmlDictEntry *cur = entry;
     780  
     781          do {
     782              cur++;
     783              if (cur >= end)
     784                  cur = dict->table;
     785          } while (cur->hashValue != 0);
     786  
     787          if (cur < entry) {
     788              /*
     789               * If we traversed the end of the buffer, handle the part
     790               * at the start of the buffer.
     791               */
     792              memmove(&dict->table[1], dict->table,
     793                      (char *) cur - (char *) dict->table);
     794              cur = end - 1;
     795              dict->table[0] = *cur;
     796          }
     797  
     798          memmove(&entry[1], entry, (char *) cur - (char *) entry);
     799      }
     800  
     801      /*
     802       * Populate entry
     803       */
     804      entry->hashValue = hashValue;
     805      entry->name = ret;
     806  
     807      dict->nbElems++;
     808  
     809      return(entry);
     810  }
     811  
     812  /**
     813   * xmlDictLookup:
     814   * @dict: dictionary
     815   * @name: string key
     816   * @len: length of the key, if -1 it is recomputed
     817   *
     818   * Lookup a string and add it to the dictionary if it wasn't found.
     819   *
     820   * Returns the interned copy of the string or NULL if a memory allocation
     821   * failed.
     822   */
     823  const xmlChar *
     824  xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
     825      const xmlDictEntry *entry;
     826  
     827      entry = xmlDictLookupInternal(dict, NULL, name, len, 1);
     828      if (entry == NULL)
     829          return(NULL);
     830      return(entry->name);
     831  }
     832  
     833  /**
     834   * xmlDictLookupHashed:
     835   * @dict: dictionary
     836   * @name: string key
     837   * @len: length of the key, if -1 it is recomputed
     838   *
     839   * Lookup a dictionary entry and add the string to the dictionary if
     840   * it wasn't found.
     841   *
     842   * Returns the dictionary entry.
     843   */
     844  xmlHashedString
     845  xmlDictLookupHashed(xmlDictPtr dict, const xmlChar *name, int len) {
     846      const xmlDictEntry *entry;
     847      xmlHashedString ret;
     848  
     849      entry = xmlDictLookupInternal(dict, NULL, name, len, 1);
     850  
     851      if (entry == NULL) {
     852          ret.name = NULL;
     853          ret.hashValue = 0;
     854      } else {
     855          ret = *entry;
     856      }
     857  
     858      return(ret);
     859  }
     860  
     861  /**
     862   * xmlDictExists:
     863   * @dict: the dictionary
     864   * @name: the name of the userdata
     865   * @len: the length of the name, if -1 it is recomputed
     866   *
     867   * Check if a string exists in the dictionary.
     868   *
     869   * Returns the internal copy of the name or NULL if not found.
     870   */
     871  const xmlChar *
     872  xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
     873      const xmlDictEntry *entry;
     874  
     875      entry = xmlDictLookupInternal(dict, NULL, name, len, 0);
     876      if (entry == NULL)
     877          return(NULL);
     878      return(entry->name);
     879  }
     880  
     881  /**
     882   * xmlDictQLookup:
     883   * @dict: the dictionary
     884   * @prefix: the prefix
     885   * @name: the name
     886   *
     887   * Lookup the QName @prefix:@name and add it to the dictionary if
     888   * it wasn't found.
     889   *
     890   * Returns the interned copy of the string or NULL if a memory allocation
     891   * failed.
     892   */
     893  const xmlChar *
     894  xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
     895      const xmlDictEntry *entry;
     896  
     897      entry = xmlDictLookupInternal(dict, prefix, name, -1, 1);
     898      if (entry == NULL)
     899          return(NULL);
     900      return(entry->name);
     901  }
     902  
     903  /*
     904   * Pseudo-random generator
     905   */
     906  
     907  static xmlMutex xmlRngMutex;
     908  
     909  static unsigned globalRngState[2];
     910  
     911  #ifdef XML_THREAD_LOCAL
     912  static XML_THREAD_LOCAL int localRngInitialized = 0;
     913  static XML_THREAD_LOCAL unsigned localRngState[2];
     914  #endif
     915  
     916  ATTRIBUTE_NO_SANITIZE_INTEGER
     917  void
     918  xmlInitRandom(void) {
     919      int var;
     920  
     921      xmlInitMutex(&xmlRngMutex);
     922  
     923      /* TODO: Get seed values from system PRNG */
     924  
     925      globalRngState[0] = (unsigned) time(NULL) ^
     926                          HASH_ROL((unsigned) (size_t) &xmlInitRandom, 8);
     927      globalRngState[1] = HASH_ROL((unsigned) (size_t) &xmlRngMutex, 16) ^
     928                          HASH_ROL((unsigned) (size_t) &var, 24);
     929  }
     930  
     931  void
     932  xmlCleanupRandom(void) {
     933      xmlCleanupMutex(&xmlRngMutex);
     934  }
     935  
     936  ATTRIBUTE_NO_SANITIZE_INTEGER
     937  static unsigned
     938  xoroshiro64ss(unsigned *s) {
     939      unsigned s0 = s[0];
     940      unsigned s1 = s[1];
     941      unsigned result = HASH_ROL(s0 * 0x9E3779BB, 5) * 5;
     942  
     943      s1 ^= s0;
     944      s[0] = HASH_ROL(s0, 26) ^ s1 ^ (s1 << 9);
     945      s[1] = HASH_ROL(s1, 13);
     946  
     947      return(result & 0xFFFFFFFF);
     948  }
     949  
     950  unsigned
     951  xmlRandom(void) {
     952  #ifdef XML_THREAD_LOCAL
     953      if (!localRngInitialized) {
     954          xmlMutexLock(&xmlRngMutex);
     955          localRngState[0] = xoroshiro64ss(globalRngState);
     956          localRngState[1] = xoroshiro64ss(globalRngState);
     957          localRngInitialized = 1;
     958          xmlMutexUnlock(&xmlRngMutex);
     959      }
     960  
     961      return(xoroshiro64ss(localRngState));
     962  #else
     963      unsigned ret;
     964  
     965      xmlMutexLock(&xmlRngMutex);
     966      ret = xoroshiro64ss(globalRngState);
     967      xmlMutexUnlock(&xmlRngMutex);
     968  
     969      return(ret);
     970  #endif
     971  }
     972