2 * hash.c: chained hash tables
4 * Reference: Your favorite introductory book on algorithms
6 * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard.
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.
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.
17 * Author: breese@users.sourceforge.net
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
36 #if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME)
37 #define HASH_RANDOMIZATION
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>
46 #define MAX_HASH_LEN 8
48 /* #define DEBUG_GROW */
51 * A single entry in the hash table
53 typedef struct _xmlHashEntry xmlHashEntry;
54 typedef xmlHashEntry *xmlHashEntryPtr;
55 struct _xmlHashEntry {
56 struct _xmlHashEntry *next;
65 * The entire hash table
67 struct _xmlHashTable {
68 struct _xmlHashEntry *table;
72 #ifdef HASH_RANDOMIZATION
79 * Calculate the hash key
82 xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
83 const xmlChar *name2, const xmlChar *name3) {
84 unsigned long value = 0L;
87 #ifdef HASH_RANDOMIZATION
88 value = table->random_seed;
91 value += 30 * (*name);
92 while ((ch = *name++) != 0) {
93 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
96 value = value ^ ((value << 5) + (value >> 3));
98 while ((ch = *name2++) != 0) {
99 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
102 value = value ^ ((value << 5) + (value >> 3));
104 while ((ch = *name3++) != 0) {
105 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
108 return (value % table->size);
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;
119 #ifdef HASH_RANDOMIZATION
120 value = table->random_seed;
123 value += 30 * (*prefix);
125 value += 30 * (*name);
127 if (prefix != NULL) {
128 while ((ch = *prefix++) != 0) {
129 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
131 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
134 while ((ch = *name++) != 0) {
135 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
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);
143 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
146 while ((ch = *name2++) != 0) {
147 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
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);
155 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
158 while ((ch = *name3++) != 0) {
159 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
162 return (value % table->size);
167 * @size: the size of the hash table
169 * Create a new xmlHashTablePtr.
171 * Returns the newly created object, or NULL if an error occurred.
174 xmlHashCreate(int size) {
175 xmlHashTablePtr table;
180 table = xmlMalloc(sizeof(xmlHashTable));
185 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
187 memset(table->table, 0, size * sizeof(xmlHashEntry));
188 #ifdef HASH_RANDOMIZATION
189 table->random_seed = __xmlRandom();
200 * @size: the size of the hash table
201 * @dict: a dictionary to use for the hash
203 * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
205 * Returns the newly created object, or NULL if an error occurred.
208 xmlHashCreateDict(int size, xmlDictPtr dict) {
209 xmlHashTablePtr table;
211 table = xmlHashCreate(size);
214 xmlDictReference(dict);
221 * @table: the hash table
222 * @size: the new size of the hash table
224 * resize the hash table
226 * Returns 0 in case of success, -1 in case of failure
229 xmlHashGrow(xmlHashTablePtr table, int size) {
232 xmlHashEntryPtr iter, next;
233 struct _xmlHashEntry *oldtable;
235 unsigned long nbElem = 0;
245 oldsize = table->size;
246 oldtable = table->table;
247 if (oldtable == NULL)
250 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
251 if (table->table == NULL) {
252 table->table = oldtable;
255 memset(table->table, 0, size * sizeof(xmlHashEntry));
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)
264 for (i = 0; i < oldsize; i++) {
265 if (oldtable[i].valid == 0)
267 key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
269 memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
270 table->table[key].next = NULL;
273 for (i = 0; i < oldsize; i++) {
274 iter = oldtable[i].next;
279 * put back the entry in the new table
282 key = xmlHashComputeKey(table, iter->name, iter->name2,
284 if (table->table[key].valid == 0) {
285 memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
286 table->table[key].next = NULL;
289 iter->next = table->table[key].next;
290 table->table[key].next = iter;
304 xmlGenericError(xmlGenericErrorContext,
305 "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
313 * @table: the hash table
314 * @f: the deallocator function for items in the hash
316 * Free the hash @table and its contents. The userdata is
317 * deallocated with @f if provided.
320 xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
322 xmlHashEntryPtr iter;
323 xmlHashEntryPtr next;
324 int inside_table = 0;
330 nbElems = table->nbElems;
331 for(i = 0; (i < table->size) && (nbElems > 0); i++) {
332 iter = &(table->table[i]);
333 if (iter->valid == 0)
338 if ((f != NULL) && (iter->payload != NULL))
339 f(iter->payload, iter->name);
340 if (table->dict == NULL) {
344 xmlFree(iter->name2);
346 xmlFree(iter->name3);
348 iter->payload = NULL;
356 xmlFree(table->table);
359 xmlDictFree(table->dict);
365 * @table: the hash table
366 * @name: the name of the userdata
367 * @userdata: a pointer to the userdata
369 * Add the @userdata to the hash @table. This can later be retrieved
370 * by using the @name. Duplicate names generate errors.
372 * Returns 0 the addition succeeded and -1 in case of error.
375 xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
376 return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
381 * @table: the hash table
382 * @name: the name of the userdata
383 * @name2: a second name of the userdata
384 * @userdata: a pointer to the userdata
386 * Add the @userdata to the hash @table. This can later be retrieved
387 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
389 * Returns 0 the addition succeeded and -1 in case of error.
392 xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
393 const xmlChar *name2, void *userdata) {
394 return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
398 * xmlHashUpdateEntry:
399 * @table: the hash table
400 * @name: the name of the userdata
401 * @userdata: a pointer to the userdata
402 * @f: the deallocator function for replaced item (if any)
404 * Add the @userdata to the hash @table. This can later be retrieved
405 * by using the @name. Existing entry for this @name will be removed
406 * and freed with @f if found.
408 * Returns 0 the addition succeeded and -1 in case of error.
411 xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
412 void *userdata, xmlHashDeallocator f) {
413 return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
417 * xmlHashUpdateEntry2:
418 * @table: the hash table
419 * @name: the name of the userdata
420 * @name2: a second name of the userdata
421 * @userdata: a pointer to the userdata
422 * @f: the deallocator function for replaced item (if any)
424 * Add the @userdata to the hash @table. This can later be retrieved
425 * by using the (@name, @name2) tuple. Existing entry for this tuple will
426 * be removed and freed with @f if found.
428 * Returns 0 the addition succeeded and -1 in case of error.
431 xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
432 const xmlChar *name2, void *userdata,
433 xmlHashDeallocator f) {
434 return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
439 * @table: the hash table
440 * @name: the name of the userdata
442 * Find the userdata specified by the @name.
444 * Returns the pointer to the userdata
447 xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
448 return(xmlHashLookup3(table, name, NULL, NULL));
453 * @table: the hash table
454 * @name: the name of the userdata
455 * @name2: a second name of the userdata
457 * Find the userdata specified by the (@name, @name2) tuple.
459 * Returns the pointer to the userdata
462 xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
463 const xmlChar *name2) {
464 return(xmlHashLookup3(table, name, name2, NULL));
469 * @table: the hash table
470 * @prefix: the prefix of the userdata
471 * @name: the name of the userdata
473 * Find the userdata specified by the QName @prefix:@name/@name.
475 * Returns the pointer to the userdata
478 xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
479 const xmlChar *name) {
480 return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
485 * @table: the hash table
486 * @prefix: the prefix of the userdata
487 * @name: the name of the userdata
488 * @prefix2: the second prefix of the userdata
489 * @name2: a second name of the userdata
491 * Find the userdata specified by the QNames tuple
493 * Returns the pointer to the userdata
496 xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix,
497 const xmlChar *name, const xmlChar *prefix2,
498 const xmlChar *name2) {
499 return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
504 * @table: the hash table
505 * @name: the name of the userdata
506 * @name2: a second name of the userdata
507 * @name3: a third name of the userdata
508 * @userdata: a pointer to the userdata
510 * Add the @userdata to the hash @table. This can later be retrieved
511 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
514 * Returns 0 the addition succeeded and -1 in case of error.
517 xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
518 const xmlChar *name2, const xmlChar *name3,
520 unsigned long key, len = 0;
521 xmlHashEntryPtr entry;
522 xmlHashEntryPtr insert;
524 if ((table == NULL) || (name == NULL))
528 * If using a dict internalize if needed
531 if (!xmlDictOwns(table->dict, name)) {
532 name = xmlDictLookup(table->dict, name, -1);
536 if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
537 name2 = xmlDictLookup(table->dict, name2, -1);
541 if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
542 name3 = xmlDictLookup(table->dict, name3, -1);
549 * Check for duplicate and insertion location.
551 key = xmlHashComputeKey(table, name, name2, name3);
552 if (table->table[key].valid == 0) {
556 for (insert = &(table->table[key]); insert->next != NULL;
557 insert = insert->next) {
558 if ((insert->name == name) &&
559 (insert->name2 == name2) &&
560 (insert->name3 == name3))
564 if ((insert->name == name) &&
565 (insert->name2 == name2) &&
566 (insert->name3 == name3))
569 for (insert = &(table->table[key]); insert->next != NULL;
570 insert = insert->next) {
571 if ((xmlStrEqual(insert->name, name)) &&
572 (xmlStrEqual(insert->name2, name2)) &&
573 (xmlStrEqual(insert->name3, name3)))
577 if ((xmlStrEqual(insert->name, name)) &&
578 (xmlStrEqual(insert->name2, name2)) &&
579 (xmlStrEqual(insert->name3, name3)))
584 if (insert == NULL) {
585 entry = &(table->table[key]);
587 entry = xmlMalloc(sizeof(xmlHashEntry));
592 if (table->dict != NULL) {
593 entry->name = (xmlChar *) name;
594 entry->name2 = (xmlChar *) name2;
595 entry->name3 = (xmlChar *) name3;
597 entry->name = xmlStrdup(name);
598 entry->name2 = xmlStrdup(name2);
599 entry->name3 = xmlStrdup(name3);
601 entry->payload = userdata;
607 insert->next = entry;
611 if (len > MAX_HASH_LEN)
612 xmlHashGrow(table, MAX_HASH_LEN * table->size);
618 * xmlHashUpdateEntry3:
619 * @table: the hash table
620 * @name: the name of the userdata
621 * @name2: a second name of the userdata
622 * @name3: a third name of the userdata
623 * @userdata: a pointer to the userdata
624 * @f: the deallocator function for replaced item (if any)
626 * Add the @userdata to the hash @table. This can later be retrieved
627 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
628 * will be removed and freed with @f if found.
630 * Returns 0 the addition succeeded and -1 in case of error.
633 xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
634 const xmlChar *name2, const xmlChar *name3,
635 void *userdata, xmlHashDeallocator f) {
637 xmlHashEntryPtr entry;
638 xmlHashEntryPtr insert;
640 if ((table == NULL) || name == NULL)
644 * If using a dict internalize if needed
647 if (!xmlDictOwns(table->dict, name)) {
648 name = xmlDictLookup(table->dict, name, -1);
652 if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
653 name2 = xmlDictLookup(table->dict, name2, -1);
657 if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
658 name3 = xmlDictLookup(table->dict, name3, -1);
665 * Check for duplicate and insertion location.
667 key = xmlHashComputeKey(table, name, name2, name3);
668 if (table->table[key].valid == 0) {
672 for (insert = &(table->table[key]); insert->next != NULL;
673 insert = insert->next) {
674 if ((insert->name == name) &&
675 (insert->name2 == name2) &&
676 (insert->name3 == name3)) {
678 f(insert->payload, insert->name);
679 insert->payload = userdata;
683 if ((insert->name == name) &&
684 (insert->name2 == name2) &&
685 (insert->name3 == name3)) {
687 f(insert->payload, insert->name);
688 insert->payload = userdata;
692 for (insert = &(table->table[key]); insert->next != NULL;
693 insert = insert->next) {
694 if ((xmlStrEqual(insert->name, name)) &&
695 (xmlStrEqual(insert->name2, name2)) &&
696 (xmlStrEqual(insert->name3, name3))) {
698 f(insert->payload, insert->name);
699 insert->payload = userdata;
703 if ((xmlStrEqual(insert->name, name)) &&
704 (xmlStrEqual(insert->name2, name2)) &&
705 (xmlStrEqual(insert->name3, name3))) {
707 f(insert->payload, insert->name);
708 insert->payload = userdata;
714 if (insert == NULL) {
715 entry = &(table->table[key]);
717 entry = xmlMalloc(sizeof(xmlHashEntry));
722 if (table->dict != NULL) {
723 entry->name = (xmlChar *) name;
724 entry->name2 = (xmlChar *) name2;
725 entry->name3 = (xmlChar *) name3;
727 entry->name = xmlStrdup(name);
728 entry->name2 = xmlStrdup(name2);
729 entry->name3 = xmlStrdup(name3);
731 entry->payload = userdata;
737 if (insert != NULL) {
738 insert->next = entry;
745 * @table: the hash table
746 * @name: the name of the userdata
747 * @name2: a second name of the userdata
748 * @name3: a third name of the userdata
750 * Find the userdata specified by the (@name, @name2, @name3) tuple.
752 * Returns the a pointer to the userdata
755 xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
756 const xmlChar *name2, const xmlChar *name3) {
758 xmlHashEntryPtr entry;
764 key = xmlHashComputeKey(table, name, name2, name3);
765 if (table->table[key].valid == 0)
768 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
769 if ((entry->name == name) &&
770 (entry->name2 == name2) &&
771 (entry->name3 == name3))
772 return(entry->payload);
775 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
776 if ((xmlStrEqual(entry->name, name)) &&
777 (xmlStrEqual(entry->name2, name2)) &&
778 (xmlStrEqual(entry->name3, name3)))
779 return(entry->payload);
786 * @table: the hash table
787 * @prefix: the prefix of the userdata
788 * @name: the name of the userdata
789 * @prefix2: the second prefix of the userdata
790 * @name2: a second name of the userdata
791 * @prefix3: the third prefix of the userdata
792 * @name3: a third name of the userdata
794 * Find the userdata specified by the (@name, @name2, @name3) tuple.
796 * Returns the a pointer to the userdata
799 xmlHashQLookup3(xmlHashTablePtr table,
800 const xmlChar *prefix, const xmlChar *name,
801 const xmlChar *prefix2, const xmlChar *name2,
802 const xmlChar *prefix3, const xmlChar *name3) {
804 xmlHashEntryPtr entry;
810 key = xmlHashComputeQKey(table, prefix, name, prefix2,
811 name2, prefix3, name3);
812 if (table->table[key].valid == 0)
814 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
815 if ((xmlStrQEqual(prefix, name, entry->name)) &&
816 (xmlStrQEqual(prefix2, name2, entry->name2)) &&
817 (xmlStrQEqual(prefix3, name3, entry->name3)))
818 return(entry->payload);
824 xmlHashScanner hashscanner;
829 stubHashScannerFull (void *payload, void *data, const xmlChar *name,
830 const xmlChar *name2 ATTRIBUTE_UNUSED,
831 const xmlChar *name3 ATTRIBUTE_UNUSED) {
832 stubData *stubdata = (stubData *) data;
833 stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
838 * @table: the hash table
839 * @f: the scanner function for items in the hash
840 * @data: extra data passed to f
842 * Scan the hash @table and applied @f to each value.
845 xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
847 stubdata.data = data;
848 stubdata.hashscanner = f;
849 xmlHashScanFull (table, stubHashScannerFull, &stubdata);
854 * @table: the hash table
855 * @f: the scanner function for items in the hash
856 * @data: extra data passed to f
858 * Scan the hash @table and applied @f to each value.
861 xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
863 xmlHashEntryPtr iter;
864 xmlHashEntryPtr next;
872 for(i = 0; i < table->size; i++) {
873 if (table->table[i].valid == 0)
875 iter = &(table->table[i]);
879 if ((f != NULL) && (iter->payload != NULL))
880 f(iter->payload, data, iter->name,
881 iter->name2, iter->name3);
882 if (nb != table->nbElems) {
883 /* table was modified by the callback, be careful */
884 if (iter == &(table->table[i])) {
885 if (table->table[i].valid == 0)
887 if (table->table[i].next != next)
888 iter = &(table->table[i]);
900 * @table: the hash table
901 * @name: the name of the userdata or NULL
902 * @name2: a second name of the userdata or NULL
903 * @name3: a third name of the userdata or NULL
904 * @f: the scanner function for items in the hash
905 * @data: extra data passed to f
907 * Scan the hash @table and applied @f to each value matching
908 * (@name, @name2, @name3) tuple. If one of the names is null,
909 * the comparison is considered to match.
912 xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
913 const xmlChar *name2, const xmlChar *name3,
914 xmlHashScanner f, void *data) {
915 xmlHashScanFull3 (table, name, name2, name3,
916 (xmlHashScannerFull) f, data);
921 * @table: the hash table
922 * @name: the name of the userdata or NULL
923 * @name2: a second name of the userdata or NULL
924 * @name3: a third name of the userdata or NULL
925 * @f: the scanner function for items in the hash
926 * @data: extra data passed to f
928 * Scan the hash @table and applied @f to each value matching
929 * (@name, @name2, @name3) tuple. If one of the names is null,
930 * the comparison is considered to match.
933 xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
934 const xmlChar *name2, const xmlChar *name3,
935 xmlHashScannerFull f, void *data) {
937 xmlHashEntryPtr iter;
938 xmlHashEntryPtr next;
946 for(i = 0; i < table->size; i++) {
947 if (table->table[i].valid == 0)
949 iter = &(table->table[i]);
952 if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
953 ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
954 ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
955 (iter->payload != NULL)) {
956 f(iter->payload, data, iter->name,
957 iter->name2, iter->name3);
967 * @table: the hash table
968 * @f: the copier function for items in the hash
970 * Scan the hash @table and applied @f to each value.
972 * Returns the new table or NULL in case of error.
975 xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
977 xmlHashEntryPtr iter;
978 xmlHashEntryPtr next;
986 ret = xmlHashCreate(table->size);
991 for(i = 0; i < table->size; i++) {
992 if (table->table[i].valid == 0)
994 iter = &(table->table[i]);
997 xmlHashAddEntry3(ret, iter->name, iter->name2,
998 iter->name3, f(iter->payload, iter->name));
1003 ret->nbElems = table->nbElems;
1009 * @table: the hash table
1011 * Query the number of elements installed in the hash @table.
1013 * Returns the number of elements in the hash table or
1014 * -1 in case of error
1017 xmlHashSize(xmlHashTablePtr table) {
1020 return(table->nbElems);
1024 * xmlHashRemoveEntry:
1025 * @table: the hash table
1026 * @name: the name of the userdata
1027 * @f: the deallocator function for removed item (if any)
1029 * Find the userdata specified by the @name and remove
1030 * it from the hash @table. Existing userdata for this tuple will be removed
1031 * and freed with @f.
1033 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1035 int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
1036 xmlHashDeallocator f) {
1037 return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
1041 * xmlHashRemoveEntry2:
1042 * @table: the hash table
1043 * @name: the name of the userdata
1044 * @name2: a second name of the userdata
1045 * @f: the deallocator function for removed item (if any)
1047 * Find the userdata specified by the (@name, @name2) tuple and remove
1048 * it from the hash @table. Existing userdata for this tuple will be removed
1049 * and freed with @f.
1051 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1054 xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
1055 const xmlChar *name2, xmlHashDeallocator f) {
1056 return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
1060 * xmlHashRemoveEntry3:
1061 * @table: the hash table
1062 * @name: the name of the userdata
1063 * @name2: a second name of the userdata
1064 * @name3: a third name of the userdata
1065 * @f: the deallocator function for removed item (if any)
1067 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
1068 * it from the hash @table. Existing userdata for this tuple will be removed
1069 * and freed with @f.
1071 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1074 xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
1075 const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1077 xmlHashEntryPtr entry;
1078 xmlHashEntryPtr prev = NULL;
1080 if (table == NULL || name == NULL)
1083 key = xmlHashComputeKey(table, name, name2, name3);
1084 if (table->table[key].valid == 0) {
1087 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
1088 if (xmlStrEqual(entry->name, name) &&
1089 xmlStrEqual(entry->name2, name2) &&
1090 xmlStrEqual(entry->name3, name3)) {
1091 if ((f != NULL) && (entry->payload != NULL))
1092 f(entry->payload, entry->name);
1093 entry->payload = NULL;
1094 if (table->dict == NULL) {
1096 xmlFree(entry->name);
1098 xmlFree(entry->name2);
1100 xmlFree(entry->name3);
1103 prev->next = entry->next;
1106 if (entry->next == NULL) {
1109 entry = entry->next;
1110 memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1124 #include "elfgcchack.h"