1 /* 2 * hash.c: chained hash tables 3 * 4 * Reference: Your favorite introductory book on algorithms 5 * 6 * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard. 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 13 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 14 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND 15 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. 16 * 17 * Author: breese@users.sourceforge.net 18 */ 19 20 #define IN_LIBXML 21 #include "libxml.h" 22 23 #include <string.h> 24 #ifdef HAVE_STDLIB_H 25 #include <stdlib.h> 26 #endif 27 #ifdef HAVE_TIME_H 28 #include <time.h> 29 #endif 30 31 /* 32 * Following http://www.ocert.org/advisories/ocert-2011-003.html 33 * it seems that having hash randomization might be a good idea 34 * when using XML with untrusted data 35 */ 36 #if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME) 37 #define HASH_RANDOMIZATION 38 #endif 39 40 #include <libxml/parser.h> 41 #include <libxml/hash.h> 42 #include <libxml/xmlmemory.h> 43 #include <libxml/xmlerror.h> 44 #include <libxml/globals.h> 45 46 #define MAX_HASH_LEN 8 47 48 /* #define DEBUG_GROW */ 49 50 /* 51 * A single entry in the hash table 52 */ 53 typedef struct _xmlHashEntry xmlHashEntry; 54 typedef xmlHashEntry *xmlHashEntryPtr; 55 struct _xmlHashEntry { 56 struct _xmlHashEntry *next; 57 xmlChar *name; 58 xmlChar *name2; 59 xmlChar *name3; 60 void *payload; 61 int valid; 62 }; 63 64 /* 65 * The entire hash table 66 */ 67 struct _xmlHashTable { 68 struct _xmlHashEntry *table; 69 int size; 70 int nbElems; 71 xmlDictPtr dict; 72 #ifdef HASH_RANDOMIZATION 73 int random_seed; 74 #endif 75 }; 76 77 /* 78 * xmlHashComputeKey: 79 * Calculate the hash key 80 */ 81 static unsigned long 82 xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name, 83 const xmlChar *name2, const xmlChar *name3) { 84 unsigned long value = 0L; 85 char ch; 86 87 #ifdef HASH_RANDOMIZATION 88 value = table->random_seed; 89 #endif 90 if (name != NULL) { 91 value += 30 * (*name); 92 while ((ch = *name++) != 0) { 93 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); 94 } 95 } 96 value = value ^ ((value << 5) + (value >> 3)); 97 if (name2 != NULL) { 98 while ((ch = *name2++) != 0) { 99 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); 100 } 101 } 102 value = value ^ ((value << 5) + (value >> 3)); 103 if (name3 != NULL) { 104 while ((ch = *name3++) != 0) { 105 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); 106 } 107 } 108 return (value % table->size); 109 } 110 111 static unsigned long 112 xmlHashComputeQKey(xmlHashTablePtr table, 113 const xmlChar *prefix, const xmlChar *name, 114 const xmlChar *prefix2, const xmlChar *name2, 115 const xmlChar *prefix3, const xmlChar *name3) { 116 unsigned long value = 0L; 117 char ch; 118 119 #ifdef HASH_RANDOMIZATION 120 value = table->random_seed; 121 #endif 122 if (prefix != NULL) 123 value += 30 * (*prefix); 124 else 125 value += 30 * (*name); 126 127 if (prefix != NULL) { 128 while ((ch = *prefix++) != 0) { 129 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); 130 } 131 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); 132 } 133 if (name != NULL) { 134 while ((ch = *name++) != 0) { 135 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); 136 } 137 } 138 value = value ^ ((value << 5) + (value >> 3)); 139 if (prefix2 != NULL) { 140 while ((ch = *prefix2++) != 0) { 141 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); 142 } 143 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); 144 } 145 if (name2 != NULL) { 146 while ((ch = *name2++) != 0) { 147 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); 148 } 149 } 150 value = value ^ ((value << 5) + (value >> 3)); 151 if (prefix3 != NULL) { 152 while ((ch = *prefix3++) != 0) { 153 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); 154 } 155 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); 156 } 157 if (name3 != NULL) { 158 while ((ch = *name3++) != 0) { 159 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); 160 } 161 } 162 return (value % table->size); 163 } 164 165 /** 166 * xmlHashCreate: 167 * @size: the size of the hash table 168 * 169 * Create a new xmlHashTablePtr. 170 * 171 * Returns the newly created object, or NULL if an error occurred. 172 */ 173 xmlHashTablePtr 174 xmlHashCreate(int size) { 175 xmlHashTablePtr table; 176 177 if (size <= 0) 178 size = 256; 179 180 table = xmlMalloc(sizeof(xmlHashTable)); 181 if (table) { 182 table->dict = NULL; 183 table->size = size; 184 table->nbElems = 0; 185 table->table = xmlMalloc(size * sizeof(xmlHashEntry)); 186 if (table->table) { 187 memset(table->table, 0, size * sizeof(xmlHashEntry)); 188 #ifdef HASH_RANDOMIZATION 189 table->random_seed = __xmlRandom(); 190 #endif 191 return(table); 192 } 193 xmlFree(table); 194 } 195 return(NULL); 196 } 197 198 /** 199 * xmlHashCreateDict: 200 * @size: the size of the hash table 201 * @dict: a dictionary to use for the hash 202 * 203 * Create a new xmlHashTablePtr which will use @dict as the internal dictionary 204 * 205 * Returns the newly created object, or NULL if an error occurred. 206 */ 207 xmlHashTablePtr 208 xmlHashCreateDict(int size, xmlDictPtr dict) { 209 xmlHashTablePtr table; 210 211 table = xmlHashCreate(size); 212 if (table != NULL) { 213 table->dict = dict; 214 xmlDictReference(dict); 215 } 216 return(table); 217 } 218 219 /** 220 * xmlHashGrow: 221 * @table: the hash table 222 * @size: the new size of the hash table 223 * 224 * resize the hash table 225 * 226 * Returns 0 in case of success, -1 in case of failure 227 */ 228 static int 229 xmlHashGrow(xmlHashTablePtr table, int size) { 230 unsigned long key; 231 int oldsize, i; 232 xmlHashEntryPtr iter, next; 233 struct _xmlHashEntry *oldtable; 234 #ifdef DEBUG_GROW 235 unsigned long nbElem = 0; 236 #endif 237 238 if (table == NULL) 239 return(-1); 240 if (size < 8) 241 return(-1); 242 if (size > 8 * 2048) 243 return(-1); 244 245 oldsize = table->size; 246 oldtable = table->table; 247 if (oldtable == NULL) 248 return(-1); 249 250 table->table = xmlMalloc(size * sizeof(xmlHashEntry)); 251 if (table->table == NULL) { 252 table->table = oldtable; 253 return(-1); 254 } 255 memset(table->table, 0, size * sizeof(xmlHashEntry)); 256 table->size = size; 257 258 /* If the two loops are merged, there would be situations where 259 a new entry needs to allocated and data copied into it from 260 the main table. So instead, we run through the array twice, first 261 copying all the elements in the main array (where we can't get 262 conflicts) and then the rest, so we only free (and don't allocate) 263 */ 264 for (i = 0; i < oldsize; i++) { 265 if (oldtable[i].valid == 0) 266 continue; 267 key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2, 268 oldtable[i].name3); 269 memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry)); 270 table->table[key].next = NULL; 271 } 272 273 for (i = 0; i < oldsize; i++) { 274 iter = oldtable[i].next; 275 while (iter) { 276 next = iter->next; 277 278 /* 279 * put back the entry in the new table 280 */ 281 282 key = xmlHashComputeKey(table, iter->name, iter->name2, 283 iter->name3); 284 if (table->table[key].valid == 0) { 285 memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry)); 286 table->table[key].next = NULL; 287 xmlFree(iter); 288 } else { 289 iter->next = table->table[key].next; 290 table->table[key].next = iter; 291 } 292 293 #ifdef DEBUG_GROW 294 nbElem++; 295 #endif 296 297 iter = next; 298 } 299 } 300 301 xmlFree(oldtable); 302 303 #ifdef DEBUG_GROW 304 xmlGenericError(xmlGenericErrorContext, 305 "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem); 306 #endif 307 308 return(0); 309 } 310 311 /** 312 * xmlHashFree: 313 * @table: the hash table 314 * @f: the deallocator function for items in the hash 315 * 316 * Free the hash @table and its contents. The userdata is 317 * deallocated with @f if provided. 318 */ 319 void 320 xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) { 321 int i; 322 xmlHashEntryPtr iter; 323 xmlHashEntryPtr next; 324 int inside_table = 0; 325 int nbElems; 326 327 if (table == NULL) 328 return; 329 if (table->table) { 330 nbElems = table->nbElems; 331 for(i = 0; (i < table->size) && (nbElems > 0); i++) { 332 iter = &(table->table[i]); 333 if (iter->valid == 0) 334 continue; 335 inside_table = 1; 336 while (iter) { 337 next = iter->next; 338 if ((f != NULL) && (iter->payload != NULL)) 339 f(iter->payload, iter->name); 340 if (table->dict == NULL) { 341 if (iter->name) 342 xmlFree(iter->name); 343 if (iter->name2) 344 xmlFree(iter->name2); 345 if (iter->name3) 346 xmlFree(iter->name3); 347 } 348 iter->payload = NULL; 349 if (!inside_table) 350 xmlFree(iter); 351 nbElems--; 352 inside_table = 0; 353 iter = next; 354 } 355 } 356 xmlFree(table->table); 357 } 358 if (table->dict) 359 xmlDictFree(table->dict); 360 xmlFree(table); 361 } 362 363 /** 364 * xmlHashDefaultDeallocator: 365 * @entry: the hash table entry 366 * @name: the entry's name 367 * 368 * Free a hash table entry with xmlFree. 369 */ 370 void 371 xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) { 372 xmlFree(entry); 373 } 374 375 /** 376 * xmlHashAddEntry: 377 * @table: the hash table 378 * @name: the name of the userdata 379 * @userdata: a pointer to the userdata 380 * 381 * Add the @userdata to the hash @table. This can later be retrieved 382 * by using the @name. Duplicate names generate errors. 383 * 384 * Returns 0 the addition succeeded and -1 in case of error. 385 */ 386 int 387 xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) { 388 return(xmlHashAddEntry3(table, name, NULL, NULL, userdata)); 389 } 390 391 /** 392 * xmlHashAddEntry2: 393 * @table: the hash table 394 * @name: the name of the userdata 395 * @name2: a second name of the userdata 396 * @userdata: a pointer to the userdata 397 * 398 * Add the @userdata to the hash @table. This can later be retrieved 399 * by using the (@name, @name2) tuple. Duplicate tuples generate errors. 400 * 401 * Returns 0 the addition succeeded and -1 in case of error. 402 */ 403 int 404 xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name, 405 const xmlChar *name2, void *userdata) { 406 return(xmlHashAddEntry3(table, name, name2, NULL, userdata)); 407 } 408 409 /** 410 * xmlHashUpdateEntry: 411 * @table: the hash table 412 * @name: the name of the userdata 413 * @userdata: a pointer to the userdata 414 * @f: the deallocator function for replaced item (if any) 415 * 416 * Add the @userdata to the hash @table. This can later be retrieved 417 * by using the @name. Existing entry for this @name will be removed 418 * and freed with @f if found. 419 * 420 * Returns 0 the addition succeeded and -1 in case of error. 421 */ 422 int 423 xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name, 424 void *userdata, xmlHashDeallocator f) { 425 return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f)); 426 } 427 428 /** 429 * xmlHashUpdateEntry2: 430 * @table: the hash table 431 * @name: the name of the userdata 432 * @name2: a second name of the userdata 433 * @userdata: a pointer to the userdata 434 * @f: the deallocator function for replaced item (if any) 435 * 436 * Add the @userdata to the hash @table. This can later be retrieved 437 * by using the (@name, @name2) tuple. Existing entry for this tuple will 438 * be removed and freed with @f if found. 439 * 440 * Returns 0 the addition succeeded and -1 in case of error. 441 */ 442 int 443 xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name, 444 const xmlChar *name2, void *userdata, 445 xmlHashDeallocator f) { 446 return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f)); 447 } 448 449 /** 450 * xmlHashLookup: 451 * @table: the hash table 452 * @name: the name of the userdata 453 * 454 * Find the userdata specified by the @name. 455 * 456 * Returns the pointer to the userdata 457 */ 458 void * 459 xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) { 460 return(xmlHashLookup3(table, name, NULL, NULL)); 461 } 462 463 /** 464 * xmlHashLookup2: 465 * @table: the hash table 466 * @name: the name of the userdata 467 * @name2: a second name of the userdata 468 * 469 * Find the userdata specified by the (@name, @name2) tuple. 470 * 471 * Returns the pointer to the userdata 472 */ 473 void * 474 xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name, 475 const xmlChar *name2) { 476 return(xmlHashLookup3(table, name, name2, NULL)); 477 } 478 479 /** 480 * xmlHashQLookup: 481 * @table: the hash table 482 * @prefix: the prefix of the userdata 483 * @name: the name of the userdata 484 * 485 * Find the userdata specified by the QName @prefix:@name/@name. 486 * 487 * Returns the pointer to the userdata 488 */ 489 void * 490 xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix, 491 const xmlChar *name) { 492 return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL)); 493 } 494 495 /** 496 * xmlHashQLookup2: 497 * @table: the hash table 498 * @prefix: the prefix of the userdata 499 * @name: the name of the userdata 500 * @prefix2: the second prefix of the userdata 501 * @name2: a second name of the userdata 502 * 503 * Find the userdata specified by the QNames tuple 504 * 505 * Returns the pointer to the userdata 506 */ 507 void * 508 xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix, 509 const xmlChar *name, const xmlChar *prefix2, 510 const xmlChar *name2) { 511 return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL)); 512 } 513 514 /** 515 * xmlHashAddEntry3: 516 * @table: the hash table 517 * @name: the name of the userdata 518 * @name2: a second name of the userdata 519 * @name3: a third name of the userdata 520 * @userdata: a pointer to the userdata 521 * 522 * Add the @userdata to the hash @table. This can later be retrieved 523 * by using the tuple (@name, @name2, @name3). Duplicate entries generate 524 * errors. 525 * 526 * Returns 0 the addition succeeded and -1 in case of error. 527 */ 528 int 529 xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name, 530 const xmlChar *name2, const xmlChar *name3, 531 void *userdata) { 532 unsigned long key, len = 0; 533 xmlHashEntryPtr entry; 534 xmlHashEntryPtr insert; 535 536 if ((table == NULL) || (name == NULL)) 537 return(-1); 538 539 /* 540 * If using a dict internalize if needed 541 */ 542 if (table->dict) { 543 if (!xmlDictOwns(table->dict, name)) { 544 name = xmlDictLookup(table->dict, name, -1); 545 if (name == NULL) 546 return(-1); 547 } 548 if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) { 549 name2 = xmlDictLookup(table->dict, name2, -1); 550 if (name2 == NULL) 551 return(-1); 552 } 553 if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) { 554 name3 = xmlDictLookup(table->dict, name3, -1); 555 if (name3 == NULL) 556 return(-1); 557 } 558 } 559 560 /* 561 * Check for duplicate and insertion location. 562 */ 563 key = xmlHashComputeKey(table, name, name2, name3); 564 if (table->table[key].valid == 0) { 565 insert = NULL; 566 } else { 567 if (table->dict) { 568 for (insert = &(table->table[key]); insert->next != NULL; 569 insert = insert->next) { 570 if ((insert->name == name) && 571 (insert->name2 == name2) && 572 (insert->name3 == name3)) 573 return(-1); 574 len++; 575 } 576 if ((insert->name == name) && 577 (insert->name2 == name2) && 578 (insert->name3 == name3)) 579 return(-1); 580 } else { 581 for (insert = &(table->table[key]); insert->next != NULL; 582 insert = insert->next) { 583 if ((xmlStrEqual(insert->name, name)) && 584 (xmlStrEqual(insert->name2, name2)) && 585 (xmlStrEqual(insert->name3, name3))) 586 return(-1); 587 len++; 588 } 589 if ((xmlStrEqual(insert->name, name)) && 590 (xmlStrEqual(insert->name2, name2)) && 591 (xmlStrEqual(insert->name3, name3))) 592 return(-1); 593 } 594 } 595 596 if (insert == NULL) { 597 entry = &(table->table[key]); 598 } else { 599 entry = xmlMalloc(sizeof(xmlHashEntry)); 600 if (entry == NULL) 601 return(-1); 602 } 603 604 if (table->dict != NULL) { 605 entry->name = (xmlChar *) name; 606 entry->name2 = (xmlChar *) name2; 607 entry->name3 = (xmlChar *) name3; 608 } else { 609 entry->name = xmlStrdup(name); 610 entry->name2 = xmlStrdup(name2); 611 entry->name3 = xmlStrdup(name3); 612 } 613 entry->payload = userdata; 614 entry->next = NULL; 615 entry->valid = 1; 616 617 618 if (insert != NULL) 619 insert->next = entry; 620 621 table->nbElems++; 622 623 if (len > MAX_HASH_LEN) 624 xmlHashGrow(table, MAX_HASH_LEN * table->size); 625 626 return(0); 627 } 628 629 /** 630 * xmlHashUpdateEntry3: 631 * @table: the hash table 632 * @name: the name of the userdata 633 * @name2: a second name of the userdata 634 * @name3: a third name of the userdata 635 * @userdata: a pointer to the userdata 636 * @f: the deallocator function for replaced item (if any) 637 * 638 * Add the @userdata to the hash @table. This can later be retrieved 639 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple 640 * will be removed and freed with @f if found. 641 * 642 * Returns 0 the addition succeeded and -1 in case of error. 643 */ 644 int 645 xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name, 646 const xmlChar *name2, const xmlChar *name3, 647 void *userdata, xmlHashDeallocator f) { 648 unsigned long key; 649 xmlHashEntryPtr entry; 650 xmlHashEntryPtr insert; 651 652 if ((table == NULL) || name == NULL) 653 return(-1); 654 655 /* 656 * If using a dict internalize if needed 657 */ 658 if (table->dict) { 659 if (!xmlDictOwns(table->dict, name)) { 660 name = xmlDictLookup(table->dict, name, -1); 661 if (name == NULL) 662 return(-1); 663 } 664 if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) { 665 name2 = xmlDictLookup(table->dict, name2, -1); 666 if (name2 == NULL) 667 return(-1); 668 } 669 if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) { 670 name3 = xmlDictLookup(table->dict, name3, -1); 671 if (name3 == NULL) 672 return(-1); 673 } 674 } 675 676 /* 677 * Check for duplicate and insertion location. 678 */ 679 key = xmlHashComputeKey(table, name, name2, name3); 680 if (table->table[key].valid == 0) { 681 insert = NULL; 682 } else { 683 if (table ->dict) { 684 for (insert = &(table->table[key]); insert->next != NULL; 685 insert = insert->next) { 686 if ((insert->name == name) && 687 (insert->name2 == name2) && 688 (insert->name3 == name3)) { 689 if (f) 690 f(insert->payload, insert->name); 691 insert->payload = userdata; 692 return(0); 693 } 694 } 695 if ((insert->name == name) && 696 (insert->name2 == name2) && 697 (insert->name3 == name3)) { 698 if (f) 699 f(insert->payload, insert->name); 700 insert->payload = userdata; 701 return(0); 702 } 703 } else { 704 for (insert = &(table->table[key]); insert->next != NULL; 705 insert = insert->next) { 706 if ((xmlStrEqual(insert->name, name)) && 707 (xmlStrEqual(insert->name2, name2)) && 708 (xmlStrEqual(insert->name3, name3))) { 709 if (f) 710 f(insert->payload, insert->name); 711 insert->payload = userdata; 712 return(0); 713 } 714 } 715 if ((xmlStrEqual(insert->name, name)) && 716 (xmlStrEqual(insert->name2, name2)) && 717 (xmlStrEqual(insert->name3, name3))) { 718 if (f) 719 f(insert->payload, insert->name); 720 insert->payload = userdata; 721 return(0); 722 } 723 } 724 } 725 726 if (insert == NULL) { 727 entry = &(table->table[key]); 728 } else { 729 entry = xmlMalloc(sizeof(xmlHashEntry)); 730 if (entry == NULL) 731 return(-1); 732 } 733 734 if (table->dict != NULL) { 735 entry->name = (xmlChar *) name; 736 entry->name2 = (xmlChar *) name2; 737 entry->name3 = (xmlChar *) name3; 738 } else { 739 entry->name = xmlStrdup(name); 740 entry->name2 = xmlStrdup(name2); 741 entry->name3 = xmlStrdup(name3); 742 } 743 entry->payload = userdata; 744 entry->next = NULL; 745 entry->valid = 1; 746 table->nbElems++; 747 748 749 if (insert != NULL) { 750 insert->next = entry; 751 } 752 return(0); 753 } 754 755 /** 756 * xmlHashLookup3: 757 * @table: the hash table 758 * @name: the name of the userdata 759 * @name2: a second name of the userdata 760 * @name3: a third name of the userdata 761 * 762 * Find the userdata specified by the (@name, @name2, @name3) tuple. 763 * 764 * Returns the a pointer to the userdata 765 */ 766 void * 767 xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, 768 const xmlChar *name2, const xmlChar *name3) { 769 unsigned long key; 770 xmlHashEntryPtr entry; 771 772 if (table == NULL) 773 return(NULL); 774 if (name == NULL) 775 return(NULL); 776 key = xmlHashComputeKey(table, name, name2, name3); 777 if (table->table[key].valid == 0) 778 return(NULL); 779 if (table->dict) { 780 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { 781 if ((entry->name == name) && 782 (entry->name2 == name2) && 783 (entry->name3 == name3)) 784 return(entry->payload); 785 } 786 } 787 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { 788 if ((xmlStrEqual(entry->name, name)) && 789 (xmlStrEqual(entry->name2, name2)) && 790 (xmlStrEqual(entry->name3, name3))) 791 return(entry->payload); 792 } 793 return(NULL); 794 } 795 796 /** 797 * xmlHashQLookup3: 798 * @table: the hash table 799 * @prefix: the prefix of the userdata 800 * @name: the name of the userdata 801 * @prefix2: the second prefix of the userdata 802 * @name2: a second name of the userdata 803 * @prefix3: the third prefix of the userdata 804 * @name3: a third name of the userdata 805 * 806 * Find the userdata specified by the (@name, @name2, @name3) tuple. 807 * 808 * Returns the a pointer to the userdata 809 */ 810 void * 811 xmlHashQLookup3(xmlHashTablePtr table, 812 const xmlChar *prefix, const xmlChar *name, 813 const xmlChar *prefix2, const xmlChar *name2, 814 const xmlChar *prefix3, const xmlChar *name3) { 815 unsigned long key; 816 xmlHashEntryPtr entry; 817 818 if (table == NULL) 819 return(NULL); 820 if (name == NULL) 821 return(NULL); 822 key = xmlHashComputeQKey(table, prefix, name, prefix2, 823 name2, prefix3, name3); 824 if (table->table[key].valid == 0) 825 return(NULL); 826 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { 827 if ((xmlStrQEqual(prefix, name, entry->name)) && 828 (xmlStrQEqual(prefix2, name2, entry->name2)) && 829 (xmlStrQEqual(prefix3, name3, entry->name3))) 830 return(entry->payload); 831 } 832 return(NULL); 833 } 834 835 typedef struct { 836 xmlHashScanner hashscanner; 837 void *data; 838 } stubData; 839 840 static void 841 stubHashScannerFull (void *payload, void *data, const xmlChar *name, 842 const xmlChar *name2 ATTRIBUTE_UNUSED, 843 const xmlChar *name3 ATTRIBUTE_UNUSED) { 844 stubData *stubdata = (stubData *) data; 845 stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name); 846 } 847 848 /** 849 * xmlHashScan: 850 * @table: the hash table 851 * @f: the scanner function for items in the hash 852 * @data: extra data passed to f 853 * 854 * Scan the hash @table and applied @f to each value. 855 */ 856 void 857 xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) { 858 stubData stubdata; 859 stubdata.data = data; 860 stubdata.hashscanner = f; 861 xmlHashScanFull (table, stubHashScannerFull, &stubdata); 862 } 863 864 /** 865 * xmlHashScanFull: 866 * @table: the hash table 867 * @f: the scanner function for items in the hash 868 * @data: extra data passed to f 869 * 870 * Scan the hash @table and applied @f to each value. 871 */ 872 void 873 xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) { 874 int i, nb; 875 xmlHashEntryPtr iter; 876 xmlHashEntryPtr next; 877 878 if (table == NULL) 879 return; 880 if (f == NULL) 881 return; 882 883 if (table->table) { 884 for(i = 0; i < table->size; i++) { 885 if (table->table[i].valid == 0) 886 continue; 887 iter = &(table->table[i]); 888 while (iter) { 889 next = iter->next; 890 nb = table->nbElems; 891 if ((f != NULL) && (iter->payload != NULL)) 892 f(iter->payload, data, iter->name, 893 iter->name2, iter->name3); 894 if (nb != table->nbElems) { 895 /* table was modified by the callback, be careful */ 896 if (iter == &(table->table[i])) { 897 if (table->table[i].valid == 0) 898 iter = NULL; 899 if (table->table[i].next != next) 900 iter = &(table->table[i]); 901 } else 902 iter = next; 903 } else 904 iter = next; 905 } 906 } 907 } 908 } 909 910 /** 911 * xmlHashScan3: 912 * @table: the hash table 913 * @name: the name of the userdata or NULL 914 * @name2: a second name of the userdata or NULL 915 * @name3: a third name of the userdata or NULL 916 * @f: the scanner function for items in the hash 917 * @data: extra data passed to f 918 * 919 * Scan the hash @table and applied @f to each value matching 920 * (@name, @name2, @name3) tuple. If one of the names is null, 921 * the comparison is considered to match. 922 */ 923 void 924 xmlHashScan3(xmlHashTablePtr table, const xmlChar *name, 925 const xmlChar *name2, const xmlChar *name3, 926 xmlHashScanner f, void *data) { 927 stubData stubdata; 928 stubdata.data = data; 929 stubdata.hashscanner = f; 930 xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull, 931 &stubdata); 932 } 933 934 /** 935 * xmlHashScanFull3: 936 * @table: the hash table 937 * @name: the name of the userdata or NULL 938 * @name2: a second name of the userdata or NULL 939 * @name3: a third name of the userdata or NULL 940 * @f: the scanner function for items in the hash 941 * @data: extra data passed to f 942 * 943 * Scan the hash @table and applied @f to each value matching 944 * (@name, @name2, @name3) tuple. If one of the names is null, 945 * the comparison is considered to match. 946 */ 947 void 948 xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name, 949 const xmlChar *name2, const xmlChar *name3, 950 xmlHashScannerFull f, void *data) { 951 int i; 952 xmlHashEntryPtr iter; 953 xmlHashEntryPtr next; 954 955 if (table == NULL) 956 return; 957 if (f == NULL) 958 return; 959 960 if (table->table) { 961 for(i = 0; i < table->size; i++) { 962 if (table->table[i].valid == 0) 963 continue; 964 iter = &(table->table[i]); 965 while (iter) { 966 next = iter->next; 967 if (((name == NULL) || (xmlStrEqual(name, iter->name))) && 968 ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) && 969 ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) && 970 (iter->payload != NULL)) { 971 f(iter->payload, data, iter->name, 972 iter->name2, iter->name3); 973 } 974 iter = next; 975 } 976 } 977 } 978 } 979 980 /** 981 * xmlHashCopy: 982 * @table: the hash table 983 * @f: the copier function for items in the hash 984 * 985 * Scan the hash @table and applied @f to each value. 986 * 987 * Returns the new table or NULL in case of error. 988 */ 989 xmlHashTablePtr 990 xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) { 991 int i; 992 xmlHashEntryPtr iter; 993 xmlHashEntryPtr next; 994 xmlHashTablePtr ret; 995 996 if (table == NULL) 997 return(NULL); 998 if (f == NULL) 999 return(NULL); 1000 1001 ret = xmlHashCreate(table->size); 1002 if (ret == NULL) 1003 return(NULL); 1004 1005 if (table->table) { 1006 for(i = 0; i < table->size; i++) { 1007 if (table->table[i].valid == 0) 1008 continue; 1009 iter = &(table->table[i]); 1010 while (iter) { 1011 next = iter->next; 1012 xmlHashAddEntry3(ret, iter->name, iter->name2, 1013 iter->name3, f(iter->payload, iter->name)); 1014 iter = next; 1015 } 1016 } 1017 } 1018 ret->nbElems = table->nbElems; 1019 return(ret); 1020 } 1021 1022 /** 1023 * xmlHashSize: 1024 * @table: the hash table 1025 * 1026 * Query the number of elements installed in the hash @table. 1027 * 1028 * Returns the number of elements in the hash table or 1029 * -1 in case of error 1030 */ 1031 int 1032 xmlHashSize(xmlHashTablePtr table) { 1033 if (table == NULL) 1034 return(-1); 1035 return(table->nbElems); 1036 } 1037 1038 /** 1039 * xmlHashRemoveEntry: 1040 * @table: the hash table 1041 * @name: the name of the userdata 1042 * @f: the deallocator function for removed item (if any) 1043 * 1044 * Find the userdata specified by the @name and remove 1045 * it from the hash @table. Existing userdata for this tuple will be removed 1046 * and freed with @f. 1047 * 1048 * Returns 0 if the removal succeeded and -1 in case of error or not found. 1049 */ 1050 int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name, 1051 xmlHashDeallocator f) { 1052 return(xmlHashRemoveEntry3(table, name, NULL, NULL, f)); 1053 } 1054 1055 /** 1056 * xmlHashRemoveEntry2: 1057 * @table: the hash table 1058 * @name: the name of the userdata 1059 * @name2: a second name of the userdata 1060 * @f: the deallocator function for removed item (if any) 1061 * 1062 * Find the userdata specified by the (@name, @name2) tuple and remove 1063 * it from the hash @table. Existing userdata for this tuple will be removed 1064 * and freed with @f. 1065 * 1066 * Returns 0 if the removal succeeded and -1 in case of error or not found. 1067 */ 1068 int 1069 xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name, 1070 const xmlChar *name2, xmlHashDeallocator f) { 1071 return(xmlHashRemoveEntry3(table, name, name2, NULL, f)); 1072 } 1073 1074 /** 1075 * xmlHashRemoveEntry3: 1076 * @table: the hash table 1077 * @name: the name of the userdata 1078 * @name2: a second name of the userdata 1079 * @name3: a third name of the userdata 1080 * @f: the deallocator function for removed item (if any) 1081 * 1082 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove 1083 * it from the hash @table. Existing userdata for this tuple will be removed 1084 * and freed with @f. 1085 * 1086 * Returns 0 if the removal succeeded and -1 in case of error or not found. 1087 */ 1088 int 1089 xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name, 1090 const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) { 1091 unsigned long key; 1092 xmlHashEntryPtr entry; 1093 xmlHashEntryPtr prev = NULL; 1094 1095 if (table == NULL || name == NULL) 1096 return(-1); 1097 1098 key = xmlHashComputeKey(table, name, name2, name3); 1099 if (table->table[key].valid == 0) { 1100 return(-1); 1101 } else { 1102 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { 1103 if (xmlStrEqual(entry->name, name) && 1104 xmlStrEqual(entry->name2, name2) && 1105 xmlStrEqual(entry->name3, name3)) { 1106 if ((f != NULL) && (entry->payload != NULL)) 1107 f(entry->payload, entry->name); 1108 entry->payload = NULL; 1109 if (table->dict == NULL) { 1110 if(entry->name) 1111 xmlFree(entry->name); 1112 if(entry->name2) 1113 xmlFree(entry->name2); 1114 if(entry->name3) 1115 xmlFree(entry->name3); 1116 } 1117 if(prev) { 1118 prev->next = entry->next; 1119 xmlFree(entry); 1120 } else { 1121 if (entry->next == NULL) { 1122 entry->valid = 0; 1123 } else { 1124 entry = entry->next; 1125 memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry)); 1126 xmlFree(entry); 1127 } 1128 } 1129 table->nbElems--; 1130 return(0); 1131 } 1132 prev = entry; 1133 } 1134 return(-1); 1135 } 1136 } 1137 1138 #define bottom_hash 1139 #include "elfgcchack.h" 1140