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 #include "private/dict.h"
44 #define MAX_HASH_LEN 8
46 /* #define DEBUG_GROW */
49 * A single entry in the hash table
51 typedef struct _xmlHashEntry xmlHashEntry
;
52 typedef xmlHashEntry
*xmlHashEntryPtr
;
53 struct _xmlHashEntry
{
54 struct _xmlHashEntry
*next
;
63 * The entire hash table
65 struct _xmlHashTable
{
66 struct _xmlHashEntry
*table
;
70 #ifdef HASH_RANDOMIZATION
77 * Calculate the hash key
80 ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
81 ATTRIBUTE_NO_SANITIZE("unsigned-shift-base")
84 xmlHashComputeKey(xmlHashTablePtr table
, const xmlChar
*name
,
85 const xmlChar
*name2
, const xmlChar
*name3
) {
86 unsigned long value
= 0L;
89 #ifdef HASH_RANDOMIZATION
90 value
= table
->random_seed
;
93 value
+= 30 * (*name
);
94 while ((ch
= *name
++) != 0) {
95 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
98 value
= value
^ ((value
<< 5) + (value
>> 3));
100 while ((ch
= *name2
++) != 0) {
101 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
104 value
= value
^ ((value
<< 5) + (value
>> 3));
106 while ((ch
= *name3
++) != 0) {
107 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
110 return (value
% table
->size
);
114 ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
115 ATTRIBUTE_NO_SANITIZE("unsigned-shift-base")
118 xmlHashComputeQKey(xmlHashTablePtr table
,
119 const xmlChar
*prefix
, const xmlChar
*name
,
120 const xmlChar
*prefix2
, const xmlChar
*name2
,
121 const xmlChar
*prefix3
, const xmlChar
*name3
) {
122 unsigned long value
= 0L;
125 #ifdef HASH_RANDOMIZATION
126 value
= table
->random_seed
;
129 value
+= 30 * (*prefix
);
131 value
+= 30 * (*name
);
133 if (prefix
!= NULL
) {
134 while ((ch
= *prefix
++) != 0) {
135 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
137 value
= value
^ ((value
<< 5) + (value
>> 3) + ':');
140 while ((ch
= *name
++) != 0) {
141 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
144 value
= value
^ ((value
<< 5) + (value
>> 3));
145 if (prefix2
!= NULL
) {
146 while ((ch
= *prefix2
++) != 0) {
147 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
149 value
= value
^ ((value
<< 5) + (value
>> 3) + ':');
152 while ((ch
= *name2
++) != 0) {
153 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
156 value
= value
^ ((value
<< 5) + (value
>> 3));
157 if (prefix3
!= NULL
) {
158 while ((ch
= *prefix3
++) != 0) {
159 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
161 value
= value
^ ((value
<< 5) + (value
>> 3) + ':');
164 while ((ch
= *name3
++) != 0) {
165 value
= value
^ ((value
<< 5) + (value
>> 3) + ch
);
168 return (value
% table
->size
);
173 * @size: the size of the hash table
175 * Create a new xmlHashTablePtr.
177 * Returns the newly created object, or NULL if an error occurred.
180 xmlHashCreate(int size
) {
181 xmlHashTablePtr table
;
188 table
= xmlMalloc(sizeof(xmlHashTable
));
193 table
->table
= xmlMalloc(size
* sizeof(xmlHashEntry
));
195 memset(table
->table
, 0, size
* sizeof(xmlHashEntry
));
196 #ifdef HASH_RANDOMIZATION
197 table
->random_seed
= __xmlRandom();
208 * @size: the size of the hash table
209 * @dict: a dictionary to use for the hash
211 * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
213 * Returns the newly created object, or NULL if an error occurred.
216 xmlHashCreateDict(int size
, xmlDictPtr dict
) {
217 xmlHashTablePtr table
;
219 table
= xmlHashCreate(size
);
222 xmlDictReference(dict
);
229 * @table: the hash table
230 * @size: the new size of the hash table
232 * resize the hash table
234 * Returns 0 in case of success, -1 in case of failure
237 xmlHashGrow(xmlHashTablePtr table
, int size
) {
240 xmlHashEntryPtr iter
, next
;
241 struct _xmlHashEntry
*oldtable
;
243 unsigned long nbElem
= 0;
253 oldsize
= table
->size
;
254 oldtable
= table
->table
;
255 if (oldtable
== NULL
)
258 table
->table
= xmlMalloc(size
* sizeof(xmlHashEntry
));
259 if (table
->table
== NULL
) {
260 table
->table
= oldtable
;
263 memset(table
->table
, 0, size
* sizeof(xmlHashEntry
));
266 /* If the two loops are merged, there would be situations where
267 a new entry needs to allocated and data copied into it from
268 the main table. So instead, we run through the array twice, first
269 copying all the elements in the main array (where we can't get
270 conflicts) and then the rest, so we only free (and don't allocate)
272 for (i
= 0; i
< oldsize
; i
++) {
273 if (oldtable
[i
].valid
== 0)
275 key
= xmlHashComputeKey(table
, oldtable
[i
].name
, oldtable
[i
].name2
,
277 memcpy(&(table
->table
[key
]), &(oldtable
[i
]), sizeof(xmlHashEntry
));
278 table
->table
[key
].next
= NULL
;
281 for (i
= 0; i
< oldsize
; i
++) {
282 iter
= oldtable
[i
].next
;
287 * put back the entry in the new table
290 key
= xmlHashComputeKey(table
, iter
->name
, iter
->name2
,
292 if (table
->table
[key
].valid
== 0) {
293 memcpy(&(table
->table
[key
]), iter
, sizeof(xmlHashEntry
));
294 table
->table
[key
].next
= NULL
;
297 iter
->next
= table
->table
[key
].next
;
298 table
->table
[key
].next
= iter
;
312 xmlGenericError(xmlGenericErrorContext
,
313 "xmlHashGrow : from %d to %d, %d elems\n", oldsize
, size
, nbElem
);
321 * @table: the hash table
322 * @f: the deallocator function for items in the hash
324 * Free the hash @table and its contents. The userdata is
325 * deallocated with @f if provided.
328 xmlHashFree(xmlHashTablePtr table
, xmlHashDeallocator f
) {
330 xmlHashEntryPtr iter
;
331 xmlHashEntryPtr next
;
332 int inside_table
= 0;
338 nbElems
= table
->nbElems
;
339 for(i
= 0; (i
< table
->size
) && (nbElems
> 0); i
++) {
340 iter
= &(table
->table
[i
]);
341 if (iter
->valid
== 0)
346 if ((f
!= NULL
) && (iter
->payload
!= NULL
))
347 f(iter
->payload
, iter
->name
);
348 if (table
->dict
== NULL
) {
352 xmlFree(iter
->name2
);
354 xmlFree(iter
->name3
);
356 iter
->payload
= NULL
;
364 xmlFree(table
->table
);
367 xmlDictFree(table
->dict
);
372 * xmlHashDefaultDeallocator:
373 * @entry: the hash table entry
374 * @name: the entry's name
376 * Free a hash table entry with xmlFree.
379 xmlHashDefaultDeallocator(void *entry
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
385 * @table: the hash table
386 * @name: the name of the userdata
387 * @userdata: a pointer to the userdata
389 * Add the @userdata to the hash @table. This can later be retrieved
390 * by using the @name. Duplicate names generate errors.
392 * Returns 0 the addition succeeded and -1 in case of error.
395 xmlHashAddEntry(xmlHashTablePtr table
, const xmlChar
*name
, void *userdata
) {
396 return(xmlHashAddEntry3(table
, name
, NULL
, NULL
, userdata
));
401 * @table: the hash table
402 * @name: the name of the userdata
403 * @name2: a second name of the userdata
404 * @userdata: a pointer to the userdata
406 * Add the @userdata to the hash @table. This can later be retrieved
407 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
409 * Returns 0 the addition succeeded and -1 in case of error.
412 xmlHashAddEntry2(xmlHashTablePtr table
, const xmlChar
*name
,
413 const xmlChar
*name2
, void *userdata
) {
414 return(xmlHashAddEntry3(table
, name
, name2
, NULL
, userdata
));
418 * xmlHashUpdateEntry:
419 * @table: the hash table
420 * @name: the 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. Existing entry for this @name will be removed
426 * and freed with @f if found.
428 * Returns 0 the addition succeeded and -1 in case of error.
431 xmlHashUpdateEntry(xmlHashTablePtr table
, const xmlChar
*name
,
432 void *userdata
, xmlHashDeallocator f
) {
433 return(xmlHashUpdateEntry3(table
, name
, NULL
, NULL
, userdata
, f
));
437 * xmlHashUpdateEntry2:
438 * @table: the hash table
439 * @name: the name of the userdata
440 * @name2: a second name of the userdata
441 * @userdata: a pointer to the userdata
442 * @f: the deallocator function for replaced item (if any)
444 * Add the @userdata to the hash @table. This can later be retrieved
445 * by using the (@name, @name2) tuple. Existing entry for this tuple will
446 * be removed and freed with @f if found.
448 * Returns 0 the addition succeeded and -1 in case of error.
451 xmlHashUpdateEntry2(xmlHashTablePtr table
, const xmlChar
*name
,
452 const xmlChar
*name2
, void *userdata
,
453 xmlHashDeallocator f
) {
454 return(xmlHashUpdateEntry3(table
, name
, name2
, NULL
, userdata
, f
));
459 * @table: the hash table
460 * @name: the name of the userdata
462 * Find the userdata specified by the @name.
464 * Returns the pointer to the userdata
467 xmlHashLookup(xmlHashTablePtr table
, const xmlChar
*name
) {
468 return(xmlHashLookup3(table
, name
, NULL
, NULL
));
473 * @table: the hash table
474 * @name: the name of the userdata
475 * @name2: a second name of the userdata
477 * Find the userdata specified by the (@name, @name2) tuple.
479 * Returns the pointer to the userdata
482 xmlHashLookup2(xmlHashTablePtr table
, const xmlChar
*name
,
483 const xmlChar
*name2
) {
484 return(xmlHashLookup3(table
, name
, name2
, NULL
));
489 * @table: the hash table
490 * @prefix: the prefix of the userdata
491 * @name: the name of the userdata
493 * Find the userdata specified by the QName @prefix:@name/@name.
495 * Returns the pointer to the userdata
498 xmlHashQLookup(xmlHashTablePtr table
, const xmlChar
*prefix
,
499 const xmlChar
*name
) {
500 return(xmlHashQLookup3(table
, prefix
, name
, NULL
, NULL
, NULL
, NULL
));
505 * @table: the hash table
506 * @prefix: the prefix of the userdata
507 * @name: the name of the userdata
508 * @prefix2: the second prefix of the userdata
509 * @name2: a second name of the userdata
511 * Find the userdata specified by the QNames tuple
513 * Returns the pointer to the userdata
516 xmlHashQLookup2(xmlHashTablePtr table
, const xmlChar
*prefix
,
517 const xmlChar
*name
, const xmlChar
*prefix2
,
518 const xmlChar
*name2
) {
519 return(xmlHashQLookup3(table
, prefix
, name
, prefix2
, name2
, NULL
, NULL
));
524 * @table: the hash table
525 * @name: the name of the userdata
526 * @name2: a second name of the userdata
527 * @name3: a third name of the userdata
528 * @userdata: a pointer to the userdata
530 * Add the @userdata to the hash @table. This can later be retrieved
531 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
534 * Returns 0 the addition succeeded and -1 in case of error.
537 xmlHashAddEntry3(xmlHashTablePtr table
, const xmlChar
*name
,
538 const xmlChar
*name2
, const xmlChar
*name3
,
540 unsigned long key
, len
= 0;
541 xmlHashEntryPtr entry
;
542 xmlHashEntryPtr insert
;
544 if ((table
== NULL
) || (name
== NULL
))
548 * If using a dict internalize if needed
551 if (!xmlDictOwns(table
->dict
, name
)) {
552 name
= xmlDictLookup(table
->dict
, name
, -1);
556 if ((name2
!= NULL
) && (!xmlDictOwns(table
->dict
, name2
))) {
557 name2
= xmlDictLookup(table
->dict
, name2
, -1);
561 if ((name3
!= NULL
) && (!xmlDictOwns(table
->dict
, name3
))) {
562 name3
= xmlDictLookup(table
->dict
, name3
, -1);
569 * Check for duplicate and insertion location.
571 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
572 if (table
->table
[key
].valid
== 0) {
576 for (insert
= &(table
->table
[key
]); insert
->next
!= NULL
;
577 insert
= insert
->next
) {
578 if ((insert
->name
== name
) &&
579 (insert
->name2
== name2
) &&
580 (insert
->name3
== name3
))
584 if ((insert
->name
== name
) &&
585 (insert
->name2
== name2
) &&
586 (insert
->name3
== name3
))
589 for (insert
= &(table
->table
[key
]); insert
->next
!= NULL
;
590 insert
= insert
->next
) {
591 if ((xmlStrEqual(insert
->name
, name
)) &&
592 (xmlStrEqual(insert
->name2
, name2
)) &&
593 (xmlStrEqual(insert
->name3
, name3
)))
597 if ((xmlStrEqual(insert
->name
, name
)) &&
598 (xmlStrEqual(insert
->name2
, name2
)) &&
599 (xmlStrEqual(insert
->name3
, name3
)))
604 if (insert
== NULL
) {
605 entry
= &(table
->table
[key
]);
607 entry
= xmlMalloc(sizeof(xmlHashEntry
));
612 if (table
->dict
!= NULL
) {
613 entry
->name
= (xmlChar
*) name
;
614 entry
->name2
= (xmlChar
*) name2
;
615 entry
->name3
= (xmlChar
*) name3
;
617 entry
->name
= xmlStrdup(name
);
618 if (entry
->name
== NULL
) {
625 entry
->name2
= xmlStrdup(name2
);
626 if (entry
->name2
== NULL
)
632 entry
->name3
= xmlStrdup(name3
);
633 if (entry
->name3
== NULL
)
637 entry
->payload
= userdata
;
643 insert
->next
= entry
;
647 if (len
> MAX_HASH_LEN
)
648 xmlHashGrow(table
, MAX_HASH_LEN
* table
->size
);
653 xmlFree(entry
->name2
);
654 xmlFree(entry
->name
);
661 * xmlHashUpdateEntry3:
662 * @table: the hash table
663 * @name: the name of the userdata
664 * @name2: a second name of the userdata
665 * @name3: a third name of the userdata
666 * @userdata: a pointer to the userdata
667 * @f: the deallocator function for replaced item (if any)
669 * Add the @userdata to the hash @table. This can later be retrieved
670 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
671 * will be removed and freed with @f if found.
673 * Returns 0 the addition succeeded and -1 in case of error.
676 xmlHashUpdateEntry3(xmlHashTablePtr table
, const xmlChar
*name
,
677 const xmlChar
*name2
, const xmlChar
*name3
,
678 void *userdata
, xmlHashDeallocator f
) {
680 xmlHashEntryPtr entry
;
681 xmlHashEntryPtr insert
;
683 if ((table
== NULL
) || name
== NULL
)
687 * If using a dict internalize if needed
690 if (!xmlDictOwns(table
->dict
, name
)) {
691 name
= xmlDictLookup(table
->dict
, name
, -1);
695 if ((name2
!= NULL
) && (!xmlDictOwns(table
->dict
, name2
))) {
696 name2
= xmlDictLookup(table
->dict
, name2
, -1);
700 if ((name3
!= NULL
) && (!xmlDictOwns(table
->dict
, name3
))) {
701 name3
= xmlDictLookup(table
->dict
, name3
, -1);
708 * Check for duplicate and insertion location.
710 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
711 if (table
->table
[key
].valid
== 0) {
715 for (insert
= &(table
->table
[key
]); insert
->next
!= NULL
;
716 insert
= insert
->next
) {
717 if ((insert
->name
== name
) &&
718 (insert
->name2
== name2
) &&
719 (insert
->name3
== name3
)) {
721 f(insert
->payload
, insert
->name
);
722 insert
->payload
= userdata
;
726 if ((insert
->name
== name
) &&
727 (insert
->name2
== name2
) &&
728 (insert
->name3
== name3
)) {
730 f(insert
->payload
, insert
->name
);
731 insert
->payload
= userdata
;
735 for (insert
= &(table
->table
[key
]); insert
->next
!= NULL
;
736 insert
= insert
->next
) {
737 if ((xmlStrEqual(insert
->name
, name
)) &&
738 (xmlStrEqual(insert
->name2
, name2
)) &&
739 (xmlStrEqual(insert
->name3
, name3
))) {
741 f(insert
->payload
, insert
->name
);
742 insert
->payload
= userdata
;
746 if ((xmlStrEqual(insert
->name
, name
)) &&
747 (xmlStrEqual(insert
->name2
, name2
)) &&
748 (xmlStrEqual(insert
->name3
, name3
))) {
750 f(insert
->payload
, insert
->name
);
751 insert
->payload
= userdata
;
757 if (insert
== NULL
) {
758 entry
= &(table
->table
[key
]);
760 entry
= xmlMalloc(sizeof(xmlHashEntry
));
765 if (table
->dict
!= NULL
) {
766 entry
->name
= (xmlChar
*) name
;
767 entry
->name2
= (xmlChar
*) name2
;
768 entry
->name3
= (xmlChar
*) name3
;
770 entry
->name
= xmlStrdup(name
);
771 if (entry
->name
== NULL
) {
778 entry
->name2
= xmlStrdup(name2
);
779 if (entry
->name2
== NULL
)
785 entry
->name3
= xmlStrdup(name3
);
786 if (entry
->name3
== NULL
)
790 entry
->payload
= userdata
;
796 if (insert
!= NULL
) {
797 insert
->next
= entry
;
802 xmlFree(entry
->name2
);
803 xmlFree(entry
->name
);
811 * @table: the hash table
812 * @name: the name of the userdata
813 * @name2: a second name of the userdata
814 * @name3: a third name of the userdata
816 * Find the userdata specified by the (@name, @name2, @name3) tuple.
818 * Returns the a pointer to the userdata
821 xmlHashLookup3(xmlHashTablePtr table
, const xmlChar
*name
,
822 const xmlChar
*name2
, const xmlChar
*name3
) {
824 xmlHashEntryPtr entry
;
830 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
831 if (table
->table
[key
].valid
== 0)
834 for (entry
= &(table
->table
[key
]); entry
!= NULL
; entry
= entry
->next
) {
835 if ((entry
->name
== name
) &&
836 (entry
->name2
== name2
) &&
837 (entry
->name3
== name3
))
838 return(entry
->payload
);
841 for (entry
= &(table
->table
[key
]); entry
!= NULL
; entry
= entry
->next
) {
842 if ((xmlStrEqual(entry
->name
, name
)) &&
843 (xmlStrEqual(entry
->name2
, name2
)) &&
844 (xmlStrEqual(entry
->name3
, name3
)))
845 return(entry
->payload
);
852 * @table: the hash table
853 * @prefix: the prefix of the userdata
854 * @name: the name of the userdata
855 * @prefix2: the second prefix of the userdata
856 * @name2: a second name of the userdata
857 * @prefix3: the third prefix of the userdata
858 * @name3: a third name of the userdata
860 * Find the userdata specified by the (@name, @name2, @name3) tuple.
862 * Returns the a pointer to the userdata
865 xmlHashQLookup3(xmlHashTablePtr table
,
866 const xmlChar
*prefix
, const xmlChar
*name
,
867 const xmlChar
*prefix2
, const xmlChar
*name2
,
868 const xmlChar
*prefix3
, const xmlChar
*name3
) {
870 xmlHashEntryPtr entry
;
876 key
= xmlHashComputeQKey(table
, prefix
, name
, prefix2
,
877 name2
, prefix3
, name3
);
878 if (table
->table
[key
].valid
== 0)
880 for (entry
= &(table
->table
[key
]); entry
!= NULL
; entry
= entry
->next
) {
881 if ((xmlStrQEqual(prefix
, name
, entry
->name
)) &&
882 (xmlStrQEqual(prefix2
, name2
, entry
->name2
)) &&
883 (xmlStrQEqual(prefix3
, name3
, entry
->name3
)))
884 return(entry
->payload
);
890 xmlHashScanner hashscanner
;
895 stubHashScannerFull (void *payload
, void *data
, const xmlChar
*name
,
896 const xmlChar
*name2 ATTRIBUTE_UNUSED
,
897 const xmlChar
*name3 ATTRIBUTE_UNUSED
) {
898 stubData
*stubdata
= (stubData
*) data
;
899 stubdata
->hashscanner (payload
, stubdata
->data
, (xmlChar
*) name
);
904 * @table: the hash table
905 * @f: the scanner function for items in the hash
906 * @data: extra data passed to f
908 * Scan the hash @table and applied @f to each value.
911 xmlHashScan(xmlHashTablePtr table
, xmlHashScanner f
, void *data
) {
913 stubdata
.data
= data
;
914 stubdata
.hashscanner
= f
;
915 xmlHashScanFull (table
, stubHashScannerFull
, &stubdata
);
920 * @table: the hash table
921 * @f: the scanner function for items in the hash
922 * @data: extra data passed to f
924 * Scan the hash @table and applied @f to each value.
927 xmlHashScanFull(xmlHashTablePtr table
, xmlHashScannerFull f
, void *data
) {
929 xmlHashEntryPtr iter
;
930 xmlHashEntryPtr next
;
938 for(i
= 0; i
< table
->size
; i
++) {
939 if (table
->table
[i
].valid
== 0)
941 iter
= &(table
->table
[i
]);
945 if ((f
!= NULL
) && (iter
->payload
!= NULL
))
946 f(iter
->payload
, data
, iter
->name
,
947 iter
->name2
, iter
->name3
);
948 if (nb
!= table
->nbElems
) {
949 /* table was modified by the callback, be careful */
950 if (iter
== &(table
->table
[i
])) {
951 if (table
->table
[i
].valid
== 0)
953 if (table
->table
[i
].next
!= next
)
954 iter
= &(table
->table
[i
]);
966 * @table: the hash table
967 * @name: the name of the userdata or NULL
968 * @name2: a second name of the userdata or NULL
969 * @name3: a third name of the userdata or NULL
970 * @f: the scanner function for items in the hash
971 * @data: extra data passed to f
973 * Scan the hash @table and applied @f to each value matching
974 * (@name, @name2, @name3) tuple. If one of the names is null,
975 * the comparison is considered to match.
978 xmlHashScan3(xmlHashTablePtr table
, const xmlChar
*name
,
979 const xmlChar
*name2
, const xmlChar
*name3
,
980 xmlHashScanner f
, void *data
) {
982 stubdata
.data
= data
;
983 stubdata
.hashscanner
= f
;
984 xmlHashScanFull3(table
, name
, name2
, name3
, stubHashScannerFull
,
990 * @table: the hash table
991 * @name: the name of the userdata or NULL
992 * @name2: a second name of the userdata or NULL
993 * @name3: a third name of the userdata or NULL
994 * @f: the scanner function for items in the hash
995 * @data: extra data passed to f
997 * Scan the hash @table and applied @f to each value matching
998 * (@name, @name2, @name3) tuple. If one of the names is null,
999 * the comparison is considered to match.
1002 xmlHashScanFull3(xmlHashTablePtr table
, const xmlChar
*name
,
1003 const xmlChar
*name2
, const xmlChar
*name3
,
1004 xmlHashScannerFull f
, void *data
) {
1006 xmlHashEntryPtr iter
;
1007 xmlHashEntryPtr next
;
1015 for(i
= 0; i
< table
->size
; i
++) {
1016 if (table
->table
[i
].valid
== 0)
1018 iter
= &(table
->table
[i
]);
1021 if (((name
== NULL
) || (xmlStrEqual(name
, iter
->name
))) &&
1022 ((name2
== NULL
) || (xmlStrEqual(name2
, iter
->name2
))) &&
1023 ((name3
== NULL
) || (xmlStrEqual(name3
, iter
->name3
))) &&
1024 (iter
->payload
!= NULL
)) {
1025 f(iter
->payload
, data
, iter
->name
,
1026 iter
->name2
, iter
->name3
);
1036 * @table: the hash table
1037 * @f: the copier function for items in the hash
1039 * Scan the hash @table and applied @f to each value.
1041 * Returns the new table or NULL in case of error.
1044 xmlHashCopy(xmlHashTablePtr table
, xmlHashCopier f
) {
1046 xmlHashEntryPtr iter
;
1047 xmlHashEntryPtr next
;
1048 xmlHashTablePtr ret
;
1055 ret
= xmlHashCreate(table
->size
);
1060 for(i
= 0; i
< table
->size
; i
++) {
1061 if (table
->table
[i
].valid
== 0)
1063 iter
= &(table
->table
[i
]);
1066 xmlHashAddEntry3(ret
, iter
->name
, iter
->name2
,
1067 iter
->name3
, f(iter
->payload
, iter
->name
));
1072 ret
->nbElems
= table
->nbElems
;
1078 * @table: the hash table
1080 * Query the number of elements installed in the hash @table.
1082 * Returns the number of elements in the hash table or
1083 * -1 in case of error
1086 xmlHashSize(xmlHashTablePtr table
) {
1089 return(table
->nbElems
);
1093 * xmlHashRemoveEntry:
1094 * @table: the hash table
1095 * @name: the name of the userdata
1096 * @f: the deallocator function for removed item (if any)
1098 * Find the userdata specified by the @name and remove
1099 * it from the hash @table. Existing userdata for this tuple will be removed
1100 * and freed with @f.
1102 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1104 int xmlHashRemoveEntry(xmlHashTablePtr table
, const xmlChar
*name
,
1105 xmlHashDeallocator f
) {
1106 return(xmlHashRemoveEntry3(table
, name
, NULL
, NULL
, f
));
1110 * xmlHashRemoveEntry2:
1111 * @table: the hash table
1112 * @name: the name of the userdata
1113 * @name2: a second name of the userdata
1114 * @f: the deallocator function for removed item (if any)
1116 * Find the userdata specified by the (@name, @name2) tuple and remove
1117 * it from the hash @table. Existing userdata for this tuple will be removed
1118 * and freed with @f.
1120 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1123 xmlHashRemoveEntry2(xmlHashTablePtr table
, const xmlChar
*name
,
1124 const xmlChar
*name2
, xmlHashDeallocator f
) {
1125 return(xmlHashRemoveEntry3(table
, name
, name2
, NULL
, f
));
1129 * xmlHashRemoveEntry3:
1130 * @table: the hash table
1131 * @name: the name of the userdata
1132 * @name2: a second name of the userdata
1133 * @name3: a third name of the userdata
1134 * @f: the deallocator function for removed item (if any)
1136 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
1137 * it from the hash @table. Existing userdata for this tuple will be removed
1138 * and freed with @f.
1140 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1143 xmlHashRemoveEntry3(xmlHashTablePtr table
, const xmlChar
*name
,
1144 const xmlChar
*name2
, const xmlChar
*name3
, xmlHashDeallocator f
) {
1146 xmlHashEntryPtr entry
;
1147 xmlHashEntryPtr prev
= NULL
;
1149 if (table
== NULL
|| name
== NULL
)
1152 key
= xmlHashComputeKey(table
, name
, name2
, name3
);
1153 if (table
->table
[key
].valid
== 0) {
1156 for (entry
= &(table
->table
[key
]); entry
!= NULL
; entry
= entry
->next
) {
1157 if (xmlStrEqual(entry
->name
, name
) &&
1158 xmlStrEqual(entry
->name2
, name2
) &&
1159 xmlStrEqual(entry
->name3
, name3
)) {
1160 if ((f
!= NULL
) && (entry
->payload
!= NULL
))
1161 f(entry
->payload
, entry
->name
);
1162 entry
->payload
= NULL
;
1163 if (table
->dict
== NULL
) {
1165 xmlFree(entry
->name
);
1167 xmlFree(entry
->name2
);
1169 xmlFree(entry
->name3
);
1172 prev
->next
= entry
->next
;
1175 if (entry
->next
== NULL
) {
1178 entry
= entry
->next
;
1179 memcpy(&(table
->table
[key
]), entry
, sizeof(xmlHashEntry
));