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