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 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
15 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
17 * Author: breese@users.sourceforge.net
28 * Following http://www.ocert.org/advisories/ocert-2011-003.html
29 * it seems that having hash randomization might be a good idea
30 * when using XML with untrusted data
32 #if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
33 #define HASH_RANDOMIZATION
36 #include <libxml/parser.h>
37 #include <libxml/hash.h>
38 #include <libxml/xmlmemory.h>
39 #include <libxml/xmlerror.h>
40 #include <libxml/globals.h>
42 #define MAX_HASH_LEN 8
44 /* #define DEBUG_GROW */
47 * A single entry in the hash table
49 typedef struct _xmlHashEntry xmlHashEntry
;
50 typedef xmlHashEntry
*xmlHashEntryPtr
;
51 struct _xmlHashEntry
{
52 struct _xmlHashEntry
*next
;
61 * The entire hash table
63 struct _xmlHashTable
{
64 struct _xmlHashEntry
*table
;
68 #ifdef HASH_RANDOMIZATION
75 * Calculate the hash key
78 ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
81 xmlHashComputeKey(xmlHashTablePtr table
, const xmlChar
*name
,
82 const xmlChar
*name2
, const xmlChar
*name3
) {
83 unsigned long value
= 0L;
86 #ifdef HASH_RANDOMIZATION
87 value
= table
->random_seed
;
90 value
+= 30 * (*name
);
91 while ((ch
= *name
++) != 0) {
92 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
95 value
= value
^ ((value
<< 5) + (value
>> 3));
97 while ((ch
= *name2
++) != 0) {
98 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
101 value
= value
^ ((value
<< 5) + (value
>> 3));
103 while ((ch
= *name3
++) != 0) {
104 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
107 return (value
% table
->size
);
111 ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
114 xmlHashComputeQKey(xmlHashTablePtr table
,
115 const xmlChar
*prefix
, const xmlChar
*name
,
116 const xmlChar
*prefix2
, const xmlChar
*name2
,
117 const xmlChar
*prefix3
, const xmlChar
*name3
) {
118 unsigned long value
= 0L;
121 #ifdef HASH_RANDOMIZATION
122 value
= table
->random_seed
;
125 value
+= 30 * (*prefix
);
127 value
+= 30 * (*name
);
129 if (prefix
!= NULL
) {
130 while ((ch
= *prefix
++) != 0) {
131 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
133 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)':');
136 while ((ch
= *name
++) != 0) {
137 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
140 value
= value
^ ((value
<< 5) + (value
>> 3));
141 if (prefix2
!= NULL
) {
142 while ((ch
= *prefix2
++) != 0) {
143 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
145 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)':');
148 while ((ch
= *name2
++) != 0) {
149 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
152 value
= value
^ ((value
<< 5) + (value
>> 3));
153 if (prefix3
!= NULL
) {
154 while ((ch
= *prefix3
++) != 0) {
155 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
157 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)':');
160 while ((ch
= *name3
++) != 0) {
161 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
164 return (value
% table
->size
);
169 * @size: the size of the hash table
171 * Create a new xmlHashTablePtr.
173 * Returns the newly created object, or NULL if an error occurred.
176 xmlHashCreate(int size
) {
177 xmlHashTablePtr table
;
182 table
= xmlMalloc(sizeof(xmlHashTable
));
187 table
->table
= xmlMalloc(size
* sizeof(xmlHashEntry
));
189 memset(table
->table
, 0, size
* sizeof(xmlHashEntry
));
190 #ifdef HASH_RANDOMIZATION
191 table
->random_seed
= __xmlRandom();
202 * @size: the size of the hash table
203 * @dict: a dictionary to use for the hash
205 * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
207 * Returns the newly created object, or NULL if an error occurred.
210 xmlHashCreateDict(int size
, xmlDictPtr dict
) {
211 xmlHashTablePtr table
;
213 table
= xmlHashCreate(size
);
216 xmlDictReference(dict
);
223 * @table: the hash table
224 * @size: the new size of the hash table
226 * resize the hash table
228 * Returns 0 in case of success, -1 in case of failure
231 xmlHashGrow(xmlHashTablePtr table
, int size
) {
234 xmlHashEntryPtr iter
, next
;
235 struct _xmlHashEntry
*oldtable
;
237 unsigned long nbElem
= 0;
247 oldsize
= table
->size
;
248 oldtable
= table
->table
;
249 if (oldtable
== NULL
)
252 table
->table
= xmlMalloc(size
* sizeof(xmlHashEntry
));
253 if (table
->table
== NULL
) {
254 table
->table
= oldtable
;
257 memset(table
->table
, 0, size
* sizeof(xmlHashEntry
));
260 /* If the two loops are merged, there would be situations where
261 a new entry needs to allocated and data copied into it from
262 the main table. So instead, we run through the array twice, first
263 copying all the elements in the main array (where we can't get
264 conflicts) and then the rest, so we only free (and don't allocate)
266 for (i
= 0; i
< oldsize
; i
++) {
267 if (oldtable
[i
].valid
== 0)
269 key
= xmlHashComputeKey(table
, oldtable
[i
].name
, oldtable
[i
].name2
,
271 memcpy(&(table
->table
[key
]), &(oldtable
[i
]), sizeof(xmlHashEntry
));
272 table
->table
[key
].next
= NULL
;
275 for (i
= 0; i
< oldsize
; i
++) {
276 iter
= oldtable
[i
].next
;
281 * put back the entry in the new table
284 key
= xmlHashComputeKey(table
, iter
->name
, iter
->name2
,
286 if (table
->table
[key
].valid
== 0) {
287 memcpy(&(table
->table
[key
]), iter
, sizeof(xmlHashEntry
));
288 table
->table
[key
].next
= NULL
;
291 iter
->next
= table
->table
[key
].next
;
292 table
->table
[key
].next
= iter
;
306 xmlGenericError(xmlGenericErrorContext
,
307 "xmlHashGrow : from %d to %d, %d elems\n", oldsize
, size
, nbElem
);
315 * @table: the hash table
316 * @f: the deallocator function for items in the hash
318 * Free the hash @table and its contents. The userdata is
319 * deallocated with @f if provided.
322 xmlHashFree(xmlHashTablePtr table
, xmlHashDeallocator f
) {
324 xmlHashEntryPtr iter
;
325 xmlHashEntryPtr next
;
326 int inside_table
= 0;
332 nbElems
= table
->nbElems
;
333 for(i
= 0; (i
< table
->size
) && (nbElems
> 0); i
++) {
334 iter
= &(table
->table
[i
]);
335 if (iter
->valid
== 0)
340 if ((f
!= NULL
) && (iter
->payload
!= NULL
))
341 f(iter
->payload
, iter
->name
);
342 if (table
->dict
== NULL
) {
346 xmlFree(iter
->name2
);
348 xmlFree(iter
->name3
);
350 iter
->payload
= NULL
;
358 xmlFree(table
->table
);
361 xmlDictFree(table
->dict
);
366 * xmlHashDefaultDeallocator:
367 * @entry: the hash table entry
368 * @name: the entry's name
370 * Free a hash table entry with xmlFree.
373 xmlHashDefaultDeallocator(void *entry
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
379 * @table: the hash table
380 * @name: the name of the userdata
381 * @userdata: a pointer to the userdata
383 * Add the @userdata to the hash @table. This can later be retrieved
384 * by using the @name. Duplicate names generate errors.
386 * Returns 0 the addition succeeded and -1 in case of error.
389 xmlHashAddEntry(xmlHashTablePtr table
, const xmlChar
*name
, void *userdata
) {
390 return(xmlHashAddEntry3(table
, name
, NULL
, NULL
, userdata
));
395 * @table: the hash table
396 * @name: the name of the userdata
397 * @name2: a second name of the userdata
398 * @userdata: a pointer to the userdata
400 * Add the @userdata to the hash @table. This can later be retrieved
401 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
403 * Returns 0 the addition succeeded and -1 in case of error.
406 xmlHashAddEntry2(xmlHashTablePtr table
, const xmlChar
*name
,
407 const xmlChar
*name2
, void *userdata
) {
408 return(xmlHashAddEntry3(table
, name
, name2
, NULL
, userdata
));
412 * xmlHashUpdateEntry:
413 * @table: the hash table
414 * @name: the name of the userdata
415 * @userdata: a pointer to the userdata
416 * @f: the deallocator function for replaced item (if any)
418 * Add the @userdata to the hash @table. This can later be retrieved
419 * by using the @name. Existing entry for this @name will be removed
420 * and freed with @f if found.
422 * Returns 0 the addition succeeded and -1 in case of error.
425 xmlHashUpdateEntry(xmlHashTablePtr table
, const xmlChar
*name
,
426 void *userdata
, xmlHashDeallocator f
) {
427 return(xmlHashUpdateEntry3(table
, name
, NULL
, NULL
, userdata
, f
));
431 * xmlHashUpdateEntry2:
432 * @table: the hash table
433 * @name: the name of the userdata
434 * @name2: a second name of the userdata
435 * @userdata: a pointer to the userdata
436 * @f: the deallocator function for replaced item (if any)
438 * Add the @userdata to the hash @table. This can later be retrieved
439 * by using the (@name, @name2) tuple. Existing entry for this tuple will
440 * be removed and freed with @f if found.
442 * Returns 0 the addition succeeded and -1 in case of error.
445 xmlHashUpdateEntry2(xmlHashTablePtr table
, const xmlChar
*name
,
446 const xmlChar
*name2
, void *userdata
,
447 xmlHashDeallocator f
) {
448 return(xmlHashUpdateEntry3(table
, name
, name2
, NULL
, userdata
, f
));
453 * @table: the hash table
454 * @name: the name of the userdata
456 * Find the userdata specified by the @name.
458 * Returns the pointer to the userdata
461 xmlHashLookup(xmlHashTablePtr table
, const xmlChar
*name
) {
462 return(xmlHashLookup3(table
, name
, NULL
, NULL
));
467 * @table: the hash table
468 * @name: the name of the userdata
469 * @name2: a second name of the userdata
471 * Find the userdata specified by the (@name, @name2) tuple.
473 * Returns the pointer to the userdata
476 xmlHashLookup2(xmlHashTablePtr table
, const xmlChar
*name
,
477 const xmlChar
*name2
) {
478 return(xmlHashLookup3(table
, name
, name2
, NULL
));
483 * @table: the hash table
484 * @prefix: the prefix of the userdata
485 * @name: the name of the userdata
487 * Find the userdata specified by the QName @prefix:@name/@name.
489 * Returns the pointer to the userdata
492 xmlHashQLookup(xmlHashTablePtr table
, const xmlChar
*prefix
,
493 const xmlChar
*name
) {
494 return(xmlHashQLookup3(table
, prefix
, name
, NULL
, NULL
, NULL
, NULL
));
499 * @table: the hash table
500 * @prefix: the prefix of the userdata
501 * @name: the name of the userdata
502 * @prefix2: the second prefix of the userdata
503 * @name2: a second name of the userdata
505 * Find the userdata specified by the QNames tuple
507 * Returns the pointer to the userdata
510 xmlHashQLookup2(xmlHashTablePtr table
, const xmlChar
*prefix
,
511 const xmlChar
*name
, const xmlChar
*prefix2
,
512 const xmlChar
*name2
) {
513 return(xmlHashQLookup3(table
, prefix
, name
, prefix2
, name2
, NULL
, NULL
));
518 * @table: the hash table
519 * @name: the name of the userdata
520 * @name2: a second name of the userdata
521 * @name3: a third name of the userdata
522 * @userdata: a pointer to the userdata
524 * Add the @userdata to the hash @table. This can later be retrieved
525 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
528 * Returns 0 the addition succeeded and -1 in case of error.
531 xmlHashAddEntry3(xmlHashTablePtr table
, const xmlChar
*name
,
532 const xmlChar
*name2
, const xmlChar
*name3
,
534 unsigned long key
, len
= 0;
535 xmlHashEntryPtr entry
;
536 xmlHashEntryPtr insert
;
538 if ((table
== NULL
) || (name
== NULL
))
542 * If using a dict internalize if needed
545 if (!xmlDictOwns(table
->dict
, name
)) {
546 name
= xmlDictLookup(table
->dict
, name
, -1);
550 if ((name2
!= NULL
) && (!xmlDictOwns(table
->dict
, name2
))) {
551 name2
= xmlDictLookup(table
->dict
, name2
, -1);
555 if ((name3
!= NULL
) && (!xmlDictOwns(table
->dict
, name3
))) {
556 name3
= xmlDictLookup(table
->dict
, name3
, -1);
563 * Check for duplicate and insertion location.
565 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
566 if (table
->table
[key
].valid
== 0) {
570 for (insert
= &(table
->table
[key
]); insert
->next
!= NULL
;
571 insert
= insert
->next
) {
572 if ((insert
->name
== name
) &&
573 (insert
->name2
== name2
) &&
574 (insert
->name3
== name3
))
578 if ((insert
->name
== name
) &&
579 (insert
->name2
== name2
) &&
580 (insert
->name3
== name3
))
583 for (insert
= &(table
->table
[key
]); insert
->next
!= NULL
;
584 insert
= insert
->next
) {
585 if ((xmlStrEqual(insert
->name
, name
)) &&
586 (xmlStrEqual(insert
->name2
, name2
)) &&
587 (xmlStrEqual(insert
->name3
, name3
)))
591 if ((xmlStrEqual(insert
->name
, name
)) &&
592 (xmlStrEqual(insert
->name2
, name2
)) &&
593 (xmlStrEqual(insert
->name3
, name3
)))
598 if (insert
== NULL
) {
599 entry
= &(table
->table
[key
]);
601 entry
= xmlMalloc(sizeof(xmlHashEntry
));
606 if (table
->dict
!= NULL
) {
607 entry
->name
= (xmlChar
*) name
;
608 entry
->name2
= (xmlChar
*) name2
;
609 entry
->name3
= (xmlChar
*) name3
;
611 entry
->name
= xmlStrdup(name
);
612 entry
->name2
= xmlStrdup(name2
);
613 entry
->name3
= xmlStrdup(name3
);
615 entry
->payload
= userdata
;
621 insert
->next
= entry
;
625 if (len
> MAX_HASH_LEN
)
626 xmlHashGrow(table
, MAX_HASH_LEN
* table
->size
);
632 * xmlHashUpdateEntry3:
633 * @table: the hash table
634 * @name: the name of the userdata
635 * @name2: a second name of the userdata
636 * @name3: a third name of the userdata
637 * @userdata: a pointer to the userdata
638 * @f: the deallocator function for replaced item (if any)
640 * Add the @userdata to the hash @table. This can later be retrieved
641 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
642 * will be removed and freed with @f if found.
644 * Returns 0 the addition succeeded and -1 in case of error.
647 xmlHashUpdateEntry3(xmlHashTablePtr table
, const xmlChar
*name
,
648 const xmlChar
*name2
, const xmlChar
*name3
,
649 void *userdata
, xmlHashDeallocator f
) {
651 xmlHashEntryPtr entry
;
652 xmlHashEntryPtr insert
;
654 if ((table
== NULL
) || name
== NULL
)
658 * If using a dict internalize if needed
661 if (!xmlDictOwns(table
->dict
, name
)) {
662 name
= xmlDictLookup(table
->dict
, name
, -1);
666 if ((name2
!= NULL
) && (!xmlDictOwns(table
->dict
, name2
))) {
667 name2
= xmlDictLookup(table
->dict
, name2
, -1);
671 if ((name3
!= NULL
) && (!xmlDictOwns(table
->dict
, name3
))) {
672 name3
= xmlDictLookup(table
->dict
, name3
, -1);
679 * Check for duplicate and insertion location.
681 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
682 if (table
->table
[key
].valid
== 0) {
686 for (insert
= &(table
->table
[key
]); insert
->next
!= NULL
;
687 insert
= insert
->next
) {
688 if ((insert
->name
== name
) &&
689 (insert
->name2
== name2
) &&
690 (insert
->name3
== name3
)) {
692 f(insert
->payload
, insert
->name
);
693 insert
->payload
= userdata
;
697 if ((insert
->name
== name
) &&
698 (insert
->name2
== name2
) &&
699 (insert
->name3
== name3
)) {
701 f(insert
->payload
, insert
->name
);
702 insert
->payload
= userdata
;
706 for (insert
= &(table
->table
[key
]); insert
->next
!= NULL
;
707 insert
= insert
->next
) {
708 if ((xmlStrEqual(insert
->name
, name
)) &&
709 (xmlStrEqual(insert
->name2
, name2
)) &&
710 (xmlStrEqual(insert
->name3
, name3
))) {
712 f(insert
->payload
, insert
->name
);
713 insert
->payload
= userdata
;
717 if ((xmlStrEqual(insert
->name
, name
)) &&
718 (xmlStrEqual(insert
->name2
, name2
)) &&
719 (xmlStrEqual(insert
->name3
, name3
))) {
721 f(insert
->payload
, insert
->name
);
722 insert
->payload
= userdata
;
728 if (insert
== NULL
) {
729 entry
= &(table
->table
[key
]);
731 entry
= xmlMalloc(sizeof(xmlHashEntry
));
736 if (table
->dict
!= NULL
) {
737 entry
->name
= (xmlChar
*) name
;
738 entry
->name2
= (xmlChar
*) name2
;
739 entry
->name3
= (xmlChar
*) name3
;
741 entry
->name
= xmlStrdup(name
);
742 entry
->name2
= xmlStrdup(name2
);
743 entry
->name3
= xmlStrdup(name3
);
745 entry
->payload
= userdata
;
751 if (insert
!= NULL
) {
752 insert
->next
= entry
;
759 * @table: the hash table
760 * @name: the name of the userdata
761 * @name2: a second name of the userdata
762 * @name3: a third name of the userdata
764 * Find the userdata specified by the (@name, @name2, @name3) tuple.
766 * Returns the a pointer to the userdata
769 xmlHashLookup3(xmlHashTablePtr table
, const xmlChar
*name
,
770 const xmlChar
*name2
, const xmlChar
*name3
) {
772 xmlHashEntryPtr entry
;
778 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
779 if (table
->table
[key
].valid
== 0)
782 for (entry
= &(table
->table
[key
]); entry
!= NULL
; entry
= entry
->next
) {
783 if ((entry
->name
== name
) &&
784 (entry
->name2
== name2
) &&
785 (entry
->name3
== name3
))
786 return(entry
->payload
);
789 for (entry
= &(table
->table
[key
]); entry
!= NULL
; entry
= entry
->next
) {
790 if ((xmlStrEqual(entry
->name
, name
)) &&
791 (xmlStrEqual(entry
->name2
, name2
)) &&
792 (xmlStrEqual(entry
->name3
, name3
)))
793 return(entry
->payload
);
800 * @table: the hash table
801 * @prefix: the prefix of the userdata
802 * @name: the name of the userdata
803 * @prefix2: the second prefix of the userdata
804 * @name2: a second name of the userdata
805 * @prefix3: the third prefix of the userdata
806 * @name3: a third name of the userdata
808 * Find the userdata specified by the (@name, @name2, @name3) tuple.
810 * Returns the a pointer to the userdata
813 xmlHashQLookup3(xmlHashTablePtr table
,
814 const xmlChar
*prefix
, const xmlChar
*name
,
815 const xmlChar
*prefix2
, const xmlChar
*name2
,
816 const xmlChar
*prefix3
, const xmlChar
*name3
) {
818 xmlHashEntryPtr entry
;
824 key
= xmlHashComputeQKey(table
, prefix
, name
, prefix2
,
825 name2
, prefix3
, name3
);
826 if (table
->table
[key
].valid
== 0)
828 for (entry
= &(table
->table
[key
]); entry
!= NULL
; entry
= entry
->next
) {
829 if ((xmlStrQEqual(prefix
, name
, entry
->name
)) &&
830 (xmlStrQEqual(prefix2
, name2
, entry
->name2
)) &&
831 (xmlStrQEqual(prefix3
, name3
, entry
->name3
)))
832 return(entry
->payload
);
838 xmlHashScanner hashscanner
;
843 stubHashScannerFull (void *payload
, void *data
, const xmlChar
*name
,
844 const xmlChar
*name2 ATTRIBUTE_UNUSED
,
845 const xmlChar
*name3 ATTRIBUTE_UNUSED
) {
846 stubData
*stubdata
= (stubData
*) data
;
847 stubdata
->hashscanner (payload
, stubdata
->data
, (xmlChar
*) name
);
852 * @table: the hash table
853 * @f: the scanner function for items in the hash
854 * @data: extra data passed to f
856 * Scan the hash @table and applied @f to each value.
859 xmlHashScan(xmlHashTablePtr table
, xmlHashScanner f
, void *data
) {
861 stubdata
.data
= data
;
862 stubdata
.hashscanner
= f
;
863 xmlHashScanFull (table
, stubHashScannerFull
, &stubdata
);
868 * @table: the hash table
869 * @f: the scanner function for items in the hash
870 * @data: extra data passed to f
872 * Scan the hash @table and applied @f to each value.
875 xmlHashScanFull(xmlHashTablePtr table
, xmlHashScannerFull f
, void *data
) {
877 xmlHashEntryPtr iter
;
878 xmlHashEntryPtr next
;
886 for(i
= 0; i
< table
->size
; i
++) {
887 if (table
->table
[i
].valid
== 0)
889 iter
= &(table
->table
[i
]);
893 if ((f
!= NULL
) && (iter
->payload
!= NULL
))
894 f(iter
->payload
, data
, iter
->name
,
895 iter
->name2
, iter
->name3
);
896 if (nb
!= table
->nbElems
) {
897 /* table was modified by the callback, be careful */
898 if (iter
== &(table
->table
[i
])) {
899 if (table
->table
[i
].valid
== 0)
901 if (table
->table
[i
].next
!= next
)
902 iter
= &(table
->table
[i
]);
914 * @table: the hash table
915 * @name: the name of the userdata or NULL
916 * @name2: a second name of the userdata or NULL
917 * @name3: a third name of the userdata or NULL
918 * @f: the scanner function for items in the hash
919 * @data: extra data passed to f
921 * Scan the hash @table and applied @f to each value matching
922 * (@name, @name2, @name3) tuple. If one of the names is null,
923 * the comparison is considered to match.
926 xmlHashScan3(xmlHashTablePtr table
, const xmlChar
*name
,
927 const xmlChar
*name2
, const xmlChar
*name3
,
928 xmlHashScanner f
, void *data
) {
930 stubdata
.data
= data
;
931 stubdata
.hashscanner
= f
;
932 xmlHashScanFull3(table
, name
, name2
, name3
, stubHashScannerFull
,
938 * @table: the hash table
939 * @name: the name of the userdata or NULL
940 * @name2: a second name of the userdata or NULL
941 * @name3: a third name of the userdata or NULL
942 * @f: the scanner function for items in the hash
943 * @data: extra data passed to f
945 * Scan the hash @table and applied @f to each value matching
946 * (@name, @name2, @name3) tuple. If one of the names is null,
947 * the comparison is considered to match.
950 xmlHashScanFull3(xmlHashTablePtr table
, const xmlChar
*name
,
951 const xmlChar
*name2
, const xmlChar
*name3
,
952 xmlHashScannerFull f
, void *data
) {
954 xmlHashEntryPtr iter
;
955 xmlHashEntryPtr next
;
963 for(i
= 0; i
< table
->size
; i
++) {
964 if (table
->table
[i
].valid
== 0)
966 iter
= &(table
->table
[i
]);
969 if (((name
== NULL
) || (xmlStrEqual(name
, iter
->name
))) &&
970 ((name2
== NULL
) || (xmlStrEqual(name2
, iter
->name2
))) &&
971 ((name3
== NULL
) || (xmlStrEqual(name3
, iter
->name3
))) &&
972 (iter
->payload
!= NULL
)) {
973 f(iter
->payload
, data
, iter
->name
,
974 iter
->name2
, iter
->name3
);
984 * @table: the hash table
985 * @f: the copier function for items in the hash
987 * Scan the hash @table and applied @f to each value.
989 * Returns the new table or NULL in case of error.
992 xmlHashCopy(xmlHashTablePtr table
, xmlHashCopier f
) {
994 xmlHashEntryPtr iter
;
995 xmlHashEntryPtr next
;
1003 ret
= xmlHashCreate(table
->size
);
1008 for(i
= 0; i
< table
->size
; i
++) {
1009 if (table
->table
[i
].valid
== 0)
1011 iter
= &(table
->table
[i
]);
1014 xmlHashAddEntry3(ret
, iter
->name
, iter
->name2
,
1015 iter
->name3
, f(iter
->payload
, iter
->name
));
1020 ret
->nbElems
= table
->nbElems
;
1026 * @table: the hash table
1028 * Query the number of elements installed in the hash @table.
1030 * Returns the number of elements in the hash table or
1031 * -1 in case of error
1034 xmlHashSize(xmlHashTablePtr table
) {
1037 return(table
->nbElems
);
1041 * xmlHashRemoveEntry:
1042 * @table: the hash table
1043 * @name: the name of the userdata
1044 * @f: the deallocator function for removed item (if any)
1046 * Find the userdata specified by the @name and remove
1047 * it from the hash @table. Existing userdata for this tuple will be removed
1048 * and freed with @f.
1050 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1052 int xmlHashRemoveEntry(xmlHashTablePtr table
, const xmlChar
*name
,
1053 xmlHashDeallocator f
) {
1054 return(xmlHashRemoveEntry3(table
, name
, NULL
, NULL
, f
));
1058 * xmlHashRemoveEntry2:
1059 * @table: the hash table
1060 * @name: the name of the userdata
1061 * @name2: a second name of the userdata
1062 * @f: the deallocator function for removed item (if any)
1064 * Find the userdata specified by the (@name, @name2) tuple and remove
1065 * it from the hash @table. Existing userdata for this tuple will be removed
1066 * and freed with @f.
1068 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1071 xmlHashRemoveEntry2(xmlHashTablePtr table
, const xmlChar
*name
,
1072 const xmlChar
*name2
, xmlHashDeallocator f
) {
1073 return(xmlHashRemoveEntry3(table
, name
, name2
, NULL
, f
));
1077 * xmlHashRemoveEntry3:
1078 * @table: the hash table
1079 * @name: the name of the userdata
1080 * @name2: a second name of the userdata
1081 * @name3: a third name of the userdata
1082 * @f: the deallocator function for removed item (if any)
1084 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
1085 * it from the hash @table. Existing userdata for this tuple will be removed
1086 * and freed with @f.
1088 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1091 xmlHashRemoveEntry3(xmlHashTablePtr table
, const xmlChar
*name
,
1092 const xmlChar
*name2
, const xmlChar
*name3
, xmlHashDeallocator f
) {
1094 xmlHashEntryPtr entry
;
1095 xmlHashEntryPtr prev
= NULL
;
1097 if (table
== NULL
|| name
== NULL
)
1100 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
1101 if (table
->table
[key
].valid
== 0) {
1104 for (entry
= &(table
->table
[key
]); entry
!= NULL
; entry
= entry
->next
) {
1105 if (xmlStrEqual(entry
->name
, name
) &&
1106 xmlStrEqual(entry
->name2
, name2
) &&
1107 xmlStrEqual(entry
->name3
, name3
)) {
1108 if ((f
!= NULL
) && (entry
->payload
!= NULL
))
1109 f(entry
->payload
, entry
->name
);
1110 entry
->payload
= NULL
;
1111 if (table
->dict
== NULL
) {
1113 xmlFree(entry
->name
);
1115 xmlFree(entry
->name2
);
1117 xmlFree(entry
->name3
);
1120 prev
->next
= entry
->next
;
1123 if (entry
->next
== NULL
) {
1126 entry
= entry
->next
;
1127 memcpy(&(table
->table
[key
]), entry
, sizeof(xmlHashEntry
));