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 (at) 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" 1102