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