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
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 !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
38 #define HASH_RANDOMIZATION
41 #include <libxml/parser.h>
42 #include <libxml/hash.h>
43 #include <libxml/xmlmemory.h>
44 #include <libxml/xmlerror.h>
45 #include <libxml/globals.h>
47 #define MAX_HASH_LEN 8
49 /* #define DEBUG_GROW */
52 * A single entry in the hash table
54 typedef struct _xmlHashEntry xmlHashEntry
;
55 typedef xmlHashEntry
*xmlHashEntryPtr
;
56 struct _xmlHashEntry
{
57 struct _xmlHashEntry
*next
;
66 * The entire hash table
68 struct _xmlHashTable
{
69 struct _xmlHashEntry
*table
;
73 #ifdef HASH_RANDOMIZATION
80 * Calculate the hash key
83 ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
86 xmlHashComputeKey(xmlHashTablePtr table
, const xmlChar
*name
,
87 const xmlChar
*name2
, const xmlChar
*name3
) {
88 unsigned long value
= 0L;
91 #ifdef HASH_RANDOMIZATION
92 value
= table
->random_seed
;
95 value
+= 30 * (*name
);
96 while ((ch
= *name
++) != 0) {
97 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
100 value
= value
^ ((value
<< 5) + (value
>> 3));
102 while ((ch
= *name2
++) != 0) {
103 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
106 value
= value
^ ((value
<< 5) + (value
>> 3));
108 while ((ch
= *name3
++) != 0) {
109 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
112 return (value
% table
->size
);
116 ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
119 xmlHashComputeQKey(xmlHashTablePtr table
,
120 const xmlChar
*prefix
, const xmlChar
*name
,
121 const xmlChar
*prefix2
, const xmlChar
*name2
,
122 const xmlChar
*prefix3
, const xmlChar
*name3
) {
123 unsigned long value
= 0L;
126 #ifdef HASH_RANDOMIZATION
127 value
= table
->random_seed
;
130 value
+= 30 * (*prefix
);
132 value
+= 30 * (*name
);
134 if (prefix
!= NULL
) {
135 while ((ch
= *prefix
++) != 0) {
136 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
138 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)':');
141 while ((ch
= *name
++) != 0) {
142 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
145 value
= value
^ ((value
<< 5) + (value
>> 3));
146 if (prefix2
!= NULL
) {
147 while ((ch
= *prefix2
++) != 0) {
148 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
150 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)':');
153 while ((ch
= *name2
++) != 0) {
154 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
157 value
= value
^ ((value
<< 5) + (value
>> 3));
158 if (prefix3
!= NULL
) {
159 while ((ch
= *prefix3
++) != 0) {
160 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
162 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)':');
165 while ((ch
= *name3
++) != 0) {
166 value
= value
^ ((value
<< 5) + (value
>> 3) + (unsigned long)ch
);
169 return (value
% table
->size
);
174 * @size: the size of the hash table
176 * Create a new xmlHashTablePtr.
178 * Returns the newly created object, or NULL if an error occurred.
181 xmlHashCreate(int size
) {
182 xmlHashTablePtr table
;
187 table
= xmlMalloc(sizeof(xmlHashTable
));
192 table
->table
= xmlMalloc(size
* sizeof(xmlHashEntry
));
194 memset(table
->table
, 0, size
* sizeof(xmlHashEntry
));
195 #ifdef HASH_RANDOMIZATION
196 table
->random_seed
= __xmlRandom();
207 * @size: the size of the hash table
208 * @dict: a dictionary to use for the hash
210 * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
212 * Returns the newly created object, or NULL if an error occurred.
215 xmlHashCreateDict(int size
, xmlDictPtr dict
) {
216 xmlHashTablePtr table
;
218 table
= xmlHashCreate(size
);
221 xmlDictReference(dict
);
228 * @table: the hash table
229 * @size: the new size of the hash table
231 * resize the hash table
233 * Returns 0 in case of success, -1 in case of failure
236 xmlHashGrow(xmlHashTablePtr table
, int size
) {
239 xmlHashEntryPtr iter
, next
;
240 struct _xmlHashEntry
*oldtable
;
242 unsigned long nbElem
= 0;
252 oldsize
= table
->size
;
253 oldtable
= table
->table
;
254 if (oldtable
== NULL
)
257 table
->table
= xmlMalloc(size
* sizeof(xmlHashEntry
));
258 if (table
->table
== NULL
) {
259 table
->table
= oldtable
;
262 memset(table
->table
, 0, size
* sizeof(xmlHashEntry
));
265 /* If the two loops are merged, there would be situations where
266 a new entry needs to allocated and data copied into it from
267 the main table. So instead, we run through the array twice, first
268 copying all the elements in the main array (where we can't get
269 conflicts) and then the rest, so we only free (and don't allocate)
271 for (i
= 0; i
< oldsize
; i
++) {
272 if (oldtable
[i
].valid
== 0)
274 key
= xmlHashComputeKey(table
, oldtable
[i
].name
, oldtable
[i
].name2
,
276 memcpy(&(table
->table
[key
]), &(oldtable
[i
]), sizeof(xmlHashEntry
));
277 table
->table
[key
].next
= NULL
;
280 for (i
= 0; i
< oldsize
; i
++) {
281 iter
= oldtable
[i
].next
;
286 * put back the entry in the new table
289 key
= xmlHashComputeKey(table
, iter
->name
, iter
->name2
,
291 if (table
->table
[key
].valid
== 0) {
292 memcpy(&(table
->table
[key
]), iter
, sizeof(xmlHashEntry
));
293 table
->table
[key
].next
= NULL
;
296 iter
->next
= table
->table
[key
].next
;
297 table
->table
[key
].next
= iter
;
311 xmlGenericError(xmlGenericErrorContext
,
312 "xmlHashGrow : from %d to %d, %d elems\n", oldsize
, size
, nbElem
);
320 * @table: the hash table
321 * @f: the deallocator function for items in the hash
323 * Free the hash @table and its contents. The userdata is
324 * deallocated with @f if provided.
327 xmlHashFree(xmlHashTablePtr table
, xmlHashDeallocator f
) {
329 xmlHashEntryPtr iter
;
330 xmlHashEntryPtr next
;
331 int inside_table
= 0;
337 nbElems
= table
->nbElems
;
338 for(i
= 0; (i
< table
->size
) && (nbElems
> 0); i
++) {
339 iter
= &(table
->table
[i
]);
340 if (iter
->valid
== 0)
345 if ((f
!= NULL
) && (iter
->payload
!= NULL
))
346 f(iter
->payload
, iter
->name
);
347 if (table
->dict
== NULL
) {
351 xmlFree(iter
->name2
);
353 xmlFree(iter
->name3
);
355 iter
->payload
= NULL
;
363 xmlFree(table
->table
);
366 xmlDictFree(table
->dict
);
371 * xmlHashDefaultDeallocator:
372 * @entry: the hash table entry
373 * @name: the entry's name
375 * Free a hash table entry with xmlFree.
378 xmlHashDefaultDeallocator(void *entry
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
384 * @table: the hash table
385 * @name: the name of the userdata
386 * @userdata: a pointer to the userdata
388 * Add the @userdata to the hash @table. This can later be retrieved
389 * by using the @name. Duplicate names generate errors.
391 * Returns 0 the addition succeeded and -1 in case of error.
394 xmlHashAddEntry(xmlHashTablePtr table
, const xmlChar
*name
, void *userdata
) {
395 return(xmlHashAddEntry3(table
, name
, NULL
, NULL
, userdata
));
400 * @table: the hash table
401 * @name: the name of the userdata
402 * @name2: a second name of the userdata
403 * @userdata: a pointer to the userdata
405 * Add the @userdata to the hash @table. This can later be retrieved
406 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
408 * Returns 0 the addition succeeded and -1 in case of error.
411 xmlHashAddEntry2(xmlHashTablePtr table
, const xmlChar
*name
,
412 const xmlChar
*name2
, void *userdata
) {
413 return(xmlHashAddEntry3(table
, name
, name2
, NULL
, userdata
));
417 * xmlHashUpdateEntry:
418 * @table: the hash table
419 * @name: the name of the userdata
420 * @userdata: a pointer to the userdata
421 * @f: the deallocator function for replaced item (if any)
423 * Add the @userdata to the hash @table. This can later be retrieved
424 * by using the @name. Existing entry for this @name will be removed
425 * and freed with @f if found.
427 * Returns 0 the addition succeeded and -1 in case of error.
430 xmlHashUpdateEntry(xmlHashTablePtr table
, const xmlChar
*name
,
431 void *userdata
, xmlHashDeallocator f
) {
432 return(xmlHashUpdateEntry3(table
, name
, NULL
, NULL
, userdata
, f
));
436 * xmlHashUpdateEntry2:
437 * @table: the hash table
438 * @name: the name of the userdata
439 * @name2: a second name of the userdata
440 * @userdata: a pointer to the userdata
441 * @f: the deallocator function for replaced item (if any)
443 * Add the @userdata to the hash @table. This can later be retrieved
444 * by using the (@name, @name2) tuple. Existing entry for this tuple will
445 * be removed and freed with @f if found.
447 * Returns 0 the addition succeeded and -1 in case of error.
450 xmlHashUpdateEntry2(xmlHashTablePtr table
, const xmlChar
*name
,
451 const xmlChar
*name2
, void *userdata
,
452 xmlHashDeallocator f
) {
453 return(xmlHashUpdateEntry3(table
, name
, name2
, NULL
, userdata
, f
));
458 * @table: the hash table
459 * @name: the name of the userdata
461 * Find the userdata specified by the @name.
463 * Returns the pointer to the userdata
466 xmlHashLookup(xmlHashTablePtr table
, const xmlChar
*name
) {
467 return(xmlHashLookup3(table
, name
, NULL
, NULL
));
472 * @table: the hash table
473 * @name: the name of the userdata
474 * @name2: a second name of the userdata
476 * Find the userdata specified by the (@name, @name2) tuple.
478 * Returns the pointer to the userdata
481 xmlHashLookup2(xmlHashTablePtr table
, const xmlChar
*name
,
482 const xmlChar
*name2
) {
483 return(xmlHashLookup3(table
, name
, name2
, NULL
));
488 * @table: the hash table
489 * @prefix: the prefix of the userdata
490 * @name: the name of the userdata
492 * Find the userdata specified by the QName @prefix:@name/@name.
494 * Returns the pointer to the userdata
497 xmlHashQLookup(xmlHashTablePtr table
, const xmlChar
*prefix
,
498 const xmlChar
*name
) {
499 return(xmlHashQLookup3(table
, prefix
, name
, NULL
, NULL
, NULL
, NULL
));
504 * @table: the hash table
505 * @prefix: the prefix of the userdata
506 * @name: the name of the userdata
507 * @prefix2: the second prefix of the userdata
508 * @name2: a second name of the userdata
510 * Find the userdata specified by the QNames tuple
512 * Returns the pointer to the userdata
515 xmlHashQLookup2(xmlHashTablePtr table
, const xmlChar
*prefix
,
516 const xmlChar
*name
, const xmlChar
*prefix2
,
517 const xmlChar
*name2
) {
518 return(xmlHashQLookup3(table
, prefix
, name
, prefix2
, name2
, NULL
, NULL
));
523 * @table: the hash table
524 * @name: the name of the userdata
525 * @name2: a second name of the userdata
526 * @name3: a third name of the userdata
527 * @userdata: a pointer to the userdata
529 * Add the @userdata to the hash @table. This can later be retrieved
530 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
533 * Returns 0 the addition succeeded and -1 in case of error.
536 xmlHashAddEntry3(xmlHashTablePtr table
, const xmlChar
*name
,
537 const xmlChar
*name2
, const xmlChar
*name3
,
539 unsigned long key
, len
= 0;
540 xmlHashEntryPtr entry
;
541 xmlHashEntryPtr insert
;
543 if ((table
== NULL
) || (name
== NULL
))
547 * If using a dict internalize if needed
550 if (!xmlDictOwns(table
->dict
, name
)) {
551 name
= xmlDictLookup(table
->dict
, name
, -1);
555 if ((name2
!= NULL
) && (!xmlDictOwns(table
->dict
, name2
))) {
556 name2
= xmlDictLookup(table
->dict
, name2
, -1);
560 if ((name3
!= NULL
) && (!xmlDictOwns(table
->dict
, name3
))) {
561 name3
= xmlDictLookup(table
->dict
, name3
, -1);
568 * Check for duplicate and insertion location.
570 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
571 if (table
->table
[key
].valid
== 0) {
575 for (insert
= &(table
->table
[key
]); insert
->next
!= NULL
;
576 insert
= insert
->next
) {
577 if ((insert
->name
== name
) &&
578 (insert
->name2
== name2
) &&
579 (insert
->name3
== name3
))
583 if ((insert
->name
== name
) &&
584 (insert
->name2
== name2
) &&
585 (insert
->name3
== name3
))
588 for (insert
= &(table
->table
[key
]); insert
->next
!= NULL
;
589 insert
= insert
->next
) {
590 if ((xmlStrEqual(insert
->name
, name
)) &&
591 (xmlStrEqual(insert
->name2
, name2
)) &&
592 (xmlStrEqual(insert
->name3
, name3
)))
596 if ((xmlStrEqual(insert
->name
, name
)) &&
597 (xmlStrEqual(insert
->name2
, name2
)) &&
598 (xmlStrEqual(insert
->name3
, name3
)))
603 if (insert
== NULL
) {
604 entry
= &(table
->table
[key
]);
606 entry
= xmlMalloc(sizeof(xmlHashEntry
));
611 if (table
->dict
!= NULL
) {
612 entry
->name
= (xmlChar
*) name
;
613 entry
->name2
= (xmlChar
*) name2
;
614 entry
->name3
= (xmlChar
*) name3
;
616 entry
->name
= xmlStrdup(name
);
617 entry
->name2
= xmlStrdup(name2
);
618 entry
->name3
= xmlStrdup(name3
);
620 entry
->payload
= userdata
;
626 insert
->next
= entry
;
630 if (len
> MAX_HASH_LEN
)
631 xmlHashGrow(table
, MAX_HASH_LEN
* table
->size
);
637 * xmlHashUpdateEntry3:
638 * @table: the hash table
639 * @name: the name of the userdata
640 * @name2: a second name of the userdata
641 * @name3: a third name of the userdata
642 * @userdata: a pointer to the userdata
643 * @f: the deallocator function for replaced item (if any)
645 * Add the @userdata to the hash @table. This can later be retrieved
646 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
647 * will be removed and freed with @f if found.
649 * Returns 0 the addition succeeded and -1 in case of error.
652 xmlHashUpdateEntry3(xmlHashTablePtr table
, const xmlChar
*name
,
653 const xmlChar
*name2
, const xmlChar
*name3
,
654 void *userdata
, xmlHashDeallocator f
) {
656 xmlHashEntryPtr entry
;
657 xmlHashEntryPtr insert
;
659 if ((table
== NULL
) || name
== NULL
)
663 * If using a dict internalize if needed
666 if (!xmlDictOwns(table
->dict
, name
)) {
667 name
= xmlDictLookup(table
->dict
, name
, -1);
671 if ((name2
!= NULL
) && (!xmlDictOwns(table
->dict
, name2
))) {
672 name2
= xmlDictLookup(table
->dict
, name2
, -1);
676 if ((name3
!= NULL
) && (!xmlDictOwns(table
->dict
, name3
))) {
677 name3
= xmlDictLookup(table
->dict
, name3
, -1);
684 * Check for duplicate and insertion location.
686 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
687 if (table
->table
[key
].valid
== 0) {
691 for (insert
= &(table
->table
[key
]); insert
->next
!= NULL
;
692 insert
= insert
->next
) {
693 if ((insert
->name
== name
) &&
694 (insert
->name2
== name2
) &&
695 (insert
->name3
== name3
)) {
697 f(insert
->payload
, insert
->name
);
698 insert
->payload
= userdata
;
702 if ((insert
->name
== name
) &&
703 (insert
->name2
== name2
) &&
704 (insert
->name3
== name3
)) {
706 f(insert
->payload
, insert
->name
);
707 insert
->payload
= userdata
;
711 for (insert
= &(table
->table
[key
]); insert
->next
!= NULL
;
712 insert
= insert
->next
) {
713 if ((xmlStrEqual(insert
->name
, name
)) &&
714 (xmlStrEqual(insert
->name2
, name2
)) &&
715 (xmlStrEqual(insert
->name3
, name3
))) {
717 f(insert
->payload
, insert
->name
);
718 insert
->payload
= userdata
;
722 if ((xmlStrEqual(insert
->name
, name
)) &&
723 (xmlStrEqual(insert
->name2
, name2
)) &&
724 (xmlStrEqual(insert
->name3
, name3
))) {
726 f(insert
->payload
, insert
->name
);
727 insert
->payload
= userdata
;
733 if (insert
== NULL
) {
734 entry
= &(table
->table
[key
]);
736 entry
= xmlMalloc(sizeof(xmlHashEntry
));
741 if (table
->dict
!= NULL
) {
742 entry
->name
= (xmlChar
*) name
;
743 entry
->name2
= (xmlChar
*) name2
;
744 entry
->name3
= (xmlChar
*) name3
;
746 entry
->name
= xmlStrdup(name
);
747 entry
->name2
= xmlStrdup(name2
);
748 entry
->name3
= xmlStrdup(name3
);
750 entry
->payload
= userdata
;
756 if (insert
!= NULL
) {
757 insert
->next
= entry
;
764 * @table: the hash table
765 * @name: the name of the userdata
766 * @name2: a second name of the userdata
767 * @name3: a third name of the userdata
769 * Find the userdata specified by the (@name, @name2, @name3) tuple.
771 * Returns the a pointer to the userdata
774 xmlHashLookup3(xmlHashTablePtr table
, const xmlChar
*name
,
775 const xmlChar
*name2
, const xmlChar
*name3
) {
777 xmlHashEntryPtr entry
;
783 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
784 if (table
->table
[key
].valid
== 0)
787 for (entry
= &(table
->table
[key
]); entry
!= NULL
; entry
= entry
->next
) {
788 if ((entry
->name
== name
) &&
789 (entry
->name2
== name2
) &&
790 (entry
->name3
== name3
))
791 return(entry
->payload
);
794 for (entry
= &(table
->table
[key
]); entry
!= NULL
; entry
= entry
->next
) {
795 if ((xmlStrEqual(entry
->name
, name
)) &&
796 (xmlStrEqual(entry
->name2
, name2
)) &&
797 (xmlStrEqual(entry
->name3
, name3
)))
798 return(entry
->payload
);
805 * @table: the hash table
806 * @prefix: the prefix of the userdata
807 * @name: the name of the userdata
808 * @prefix2: the second prefix of the userdata
809 * @name2: a second name of the userdata
810 * @prefix3: the third prefix of the userdata
811 * @name3: a third name of the userdata
813 * Find the userdata specified by the (@name, @name2, @name3) tuple.
815 * Returns the a pointer to the userdata
818 xmlHashQLookup3(xmlHashTablePtr table
,
819 const xmlChar
*prefix
, const xmlChar
*name
,
820 const xmlChar
*prefix2
, const xmlChar
*name2
,
821 const xmlChar
*prefix3
, const xmlChar
*name3
) {
823 xmlHashEntryPtr entry
;
829 key
= xmlHashComputeQKey(table
, prefix
, name
, prefix2
,
830 name2
, prefix3
, name3
);
831 if (table
->table
[key
].valid
== 0)
833 for (entry
= &(table
->table
[key
]); entry
!= NULL
; entry
= entry
->next
) {
834 if ((xmlStrQEqual(prefix
, name
, entry
->name
)) &&
835 (xmlStrQEqual(prefix2
, name2
, entry
->name2
)) &&
836 (xmlStrQEqual(prefix3
, name3
, entry
->name3
)))
837 return(entry
->payload
);
843 xmlHashScanner hashscanner
;
848 stubHashScannerFull (void *payload
, void *data
, const xmlChar
*name
,
849 const xmlChar
*name2 ATTRIBUTE_UNUSED
,
850 const xmlChar
*name3 ATTRIBUTE_UNUSED
) {
851 stubData
*stubdata
= (stubData
*) data
;
852 stubdata
->hashscanner (payload
, stubdata
->data
, (xmlChar
*) name
);
857 * @table: the hash table
858 * @f: the scanner function for items in the hash
859 * @data: extra data passed to f
861 * Scan the hash @table and applied @f to each value.
864 xmlHashScan(xmlHashTablePtr table
, xmlHashScanner f
, void *data
) {
866 stubdata
.data
= data
;
867 stubdata
.hashscanner
= f
;
868 xmlHashScanFull (table
, stubHashScannerFull
, &stubdata
);
873 * @table: the hash table
874 * @f: the scanner function for items in the hash
875 * @data: extra data passed to f
877 * Scan the hash @table and applied @f to each value.
880 xmlHashScanFull(xmlHashTablePtr table
, xmlHashScannerFull f
, void *data
) {
882 xmlHashEntryPtr iter
;
883 xmlHashEntryPtr next
;
891 for(i
= 0; i
< table
->size
; i
++) {
892 if (table
->table
[i
].valid
== 0)
894 iter
= &(table
->table
[i
]);
898 if ((f
!= NULL
) && (iter
->payload
!= NULL
))
899 f(iter
->payload
, data
, iter
->name
,
900 iter
->name2
, iter
->name3
);
901 if (nb
!= table
->nbElems
) {
902 /* table was modified by the callback, be careful */
903 if (iter
== &(table
->table
[i
])) {
904 if (table
->table
[i
].valid
== 0)
906 if (table
->table
[i
].next
!= next
)
907 iter
= &(table
->table
[i
]);
919 * @table: the hash table
920 * @name: the name of the userdata or NULL
921 * @name2: a second name of the userdata or NULL
922 * @name3: a third name of the userdata or NULL
923 * @f: the scanner function for items in the hash
924 * @data: extra data passed to f
926 * Scan the hash @table and applied @f to each value matching
927 * (@name, @name2, @name3) tuple. If one of the names is null,
928 * the comparison is considered to match.
931 xmlHashScan3(xmlHashTablePtr table
, const xmlChar
*name
,
932 const xmlChar
*name2
, const xmlChar
*name3
,
933 xmlHashScanner f
, void *data
) {
935 stubdata
.data
= data
;
936 stubdata
.hashscanner
= f
;
937 xmlHashScanFull3(table
, name
, name2
, name3
, stubHashScannerFull
,
943 * @table: the hash table
944 * @name: the name of the userdata or NULL
945 * @name2: a second name of the userdata or NULL
946 * @name3: a third name of the userdata or NULL
947 * @f: the scanner function for items in the hash
948 * @data: extra data passed to f
950 * Scan the hash @table and applied @f to each value matching
951 * (@name, @name2, @name3) tuple. If one of the names is null,
952 * the comparison is considered to match.
955 xmlHashScanFull3(xmlHashTablePtr table
, const xmlChar
*name
,
956 const xmlChar
*name2
, const xmlChar
*name3
,
957 xmlHashScannerFull f
, void *data
) {
959 xmlHashEntryPtr iter
;
960 xmlHashEntryPtr next
;
968 for(i
= 0; i
< table
->size
; i
++) {
969 if (table
->table
[i
].valid
== 0)
971 iter
= &(table
->table
[i
]);
974 if (((name
== NULL
) || (xmlStrEqual(name
, iter
->name
))) &&
975 ((name2
== NULL
) || (xmlStrEqual(name2
, iter
->name2
))) &&
976 ((name3
== NULL
) || (xmlStrEqual(name3
, iter
->name3
))) &&
977 (iter
->payload
!= NULL
)) {
978 f(iter
->payload
, data
, iter
->name
,
979 iter
->name2
, iter
->name3
);
989 * @table: the hash table
990 * @f: the copier function for items in the hash
992 * Scan the hash @table and applied @f to each value.
994 * Returns the new table or NULL in case of error.
997 xmlHashCopy(xmlHashTablePtr table
, xmlHashCopier f
) {
999 xmlHashEntryPtr iter
;
1000 xmlHashEntryPtr next
;
1001 xmlHashTablePtr ret
;
1008 ret
= xmlHashCreate(table
->size
);
1013 for(i
= 0; i
< table
->size
; i
++) {
1014 if (table
->table
[i
].valid
== 0)
1016 iter
= &(table
->table
[i
]);
1019 xmlHashAddEntry3(ret
, iter
->name
, iter
->name2
,
1020 iter
->name3
, f(iter
->payload
, iter
->name
));
1025 ret
->nbElems
= table
->nbElems
;
1031 * @table: the hash table
1033 * Query the number of elements installed in the hash @table.
1035 * Returns the number of elements in the hash table or
1036 * -1 in case of error
1039 xmlHashSize(xmlHashTablePtr table
) {
1042 return(table
->nbElems
);
1046 * xmlHashRemoveEntry:
1047 * @table: the hash table
1048 * @name: the name of the userdata
1049 * @f: the deallocator function for removed item (if any)
1051 * Find the userdata specified by the @name and remove
1052 * it from the hash @table. Existing userdata for this tuple will be removed
1053 * and freed with @f.
1055 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1057 int xmlHashRemoveEntry(xmlHashTablePtr table
, const xmlChar
*name
,
1058 xmlHashDeallocator f
) {
1059 return(xmlHashRemoveEntry3(table
, name
, NULL
, NULL
, f
));
1063 * xmlHashRemoveEntry2:
1064 * @table: the hash table
1065 * @name: the name of the userdata
1066 * @name2: a second name of the userdata
1067 * @f: the deallocator function for removed item (if any)
1069 * Find the userdata specified by the (@name, @name2) tuple and remove
1070 * it from the hash @table. Existing userdata for this tuple will be removed
1071 * and freed with @f.
1073 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1076 xmlHashRemoveEntry2(xmlHashTablePtr table
, const xmlChar
*name
,
1077 const xmlChar
*name2
, xmlHashDeallocator f
) {
1078 return(xmlHashRemoveEntry3(table
, name
, name2
, NULL
, f
));
1082 * xmlHashRemoveEntry3:
1083 * @table: the hash table
1084 * @name: the name of the userdata
1085 * @name2: a second name of the userdata
1086 * @name3: a third name of the userdata
1087 * @f: the deallocator function for removed item (if any)
1089 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
1090 * it from the hash @table. Existing userdata for this tuple will be removed
1091 * and freed with @f.
1093 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1096 xmlHashRemoveEntry3(xmlHashTablePtr table
, const xmlChar
*name
,
1097 const xmlChar
*name2
, const xmlChar
*name3
, xmlHashDeallocator f
) {
1099 xmlHashEntryPtr entry
;
1100 xmlHashEntryPtr prev
= NULL
;
1102 if (table
== NULL
|| name
== NULL
)
1105 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
1106 if (table
->table
[key
].valid
== 0) {
1109 for (entry
= &(table
->table
[key
]); entry
!= NULL
; entry
= entry
->next
) {
1110 if (xmlStrEqual(entry
->name
, name
) &&
1111 xmlStrEqual(entry
->name2
, name2
) &&
1112 xmlStrEqual(entry
->name3
, name3
)) {
1113 if ((f
!= NULL
) && (entry
->payload
!= NULL
))
1114 f(entry
->payload
, entry
->name
);
1115 entry
->payload
= NULL
;
1116 if (table
->dict
== NULL
) {
1118 xmlFree(entry
->name
);
1120 xmlFree(entry
->name2
);
1122 xmlFree(entry
->name3
);
1125 prev
->next
= entry
->next
;
1128 if (entry
->next
== NULL
) {
1131 entry
= entry
->next
;
1132 memcpy(&(table
->table
[key
]), entry
, sizeof(xmlHashEntry
));
1146 #include "elfgcchack.h"