cng.sys: New dll.
[wine.git] / libs / xml2 / hash.c
blobafa094ef9076f14ae8d9bb3bd32b099a875d86f0
1 /*
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
20 #define IN_LIBXML
21 #include "libxml.h"
23 #include <string.h>
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27 #ifdef HAVE_TIME_H
28 #include <time.h>
29 #endif
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
39 #endif
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;
58 xmlChar *name;
59 xmlChar *name2;
60 xmlChar *name3;
61 void *payload;
62 int valid;
66 * The entire hash table
68 struct _xmlHashTable {
69 struct _xmlHashEntry *table;
70 int size;
71 int nbElems;
72 xmlDictPtr dict;
73 #ifdef HASH_RANDOMIZATION
74 int random_seed;
75 #endif
79 * xmlHashComputeKey:
80 * Calculate the hash key
82 #ifdef __clang__
83 ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
84 #endif
85 static unsigned long
86 xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
87 const xmlChar *name2, const xmlChar *name3) {
88 unsigned long value = 0L;
89 char ch;
91 #ifdef HASH_RANDOMIZATION
92 value = table->random_seed;
93 #endif
94 if (name != NULL) {
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));
101 if (name2 != NULL) {
102 while ((ch = *name2++) != 0) {
103 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
106 value = value ^ ((value << 5) + (value >> 3));
107 if (name3 != NULL) {
108 while ((ch = *name3++) != 0) {
109 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
112 return (value % table->size);
115 #ifdef __clang__
116 ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
117 #endif
118 static unsigned long
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;
124 char ch;
126 #ifdef HASH_RANDOMIZATION
127 value = table->random_seed;
128 #endif
129 if (prefix != NULL)
130 value += 30 * (*prefix);
131 else
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)':');
140 if (name != NULL) {
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)':');
152 if (name2 != NULL) {
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)':');
164 if (name3 != NULL) {
165 while ((ch = *name3++) != 0) {
166 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
169 return (value % table->size);
173 * xmlHashCreate:
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.
180 xmlHashTablePtr
181 xmlHashCreate(int size) {
182 xmlHashTablePtr table;
184 if (size <= 0)
185 size = 256;
187 table = xmlMalloc(sizeof(xmlHashTable));
188 if (table) {
189 table->dict = NULL;
190 table->size = size;
191 table->nbElems = 0;
192 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
193 if (table->table) {
194 memset(table->table, 0, size * sizeof(xmlHashEntry));
195 #ifdef HASH_RANDOMIZATION
196 table->random_seed = __xmlRandom();
197 #endif
198 return(table);
200 xmlFree(table);
202 return(NULL);
206 * xmlHashCreateDict:
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.
214 xmlHashTablePtr
215 xmlHashCreateDict(int size, xmlDictPtr dict) {
216 xmlHashTablePtr table;
218 table = xmlHashCreate(size);
219 if (table != NULL) {
220 table->dict = dict;
221 xmlDictReference(dict);
223 return(table);
227 * xmlHashGrow:
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
235 static int
236 xmlHashGrow(xmlHashTablePtr table, int size) {
237 unsigned long key;
238 int oldsize, i;
239 xmlHashEntryPtr iter, next;
240 struct _xmlHashEntry *oldtable;
241 #ifdef DEBUG_GROW
242 unsigned long nbElem = 0;
243 #endif
245 if (table == NULL)
246 return(-1);
247 if (size < 8)
248 return(-1);
249 if (size > 8 * 2048)
250 return(-1);
252 oldsize = table->size;
253 oldtable = table->table;
254 if (oldtable == NULL)
255 return(-1);
257 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
258 if (table->table == NULL) {
259 table->table = oldtable;
260 return(-1);
262 memset(table->table, 0, size * sizeof(xmlHashEntry));
263 table->size = size;
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)
273 continue;
274 key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
275 oldtable[i].name3);
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;
282 while (iter) {
283 next = iter->next;
286 * put back the entry in the new table
289 key = xmlHashComputeKey(table, iter->name, iter->name2,
290 iter->name3);
291 if (table->table[key].valid == 0) {
292 memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
293 table->table[key].next = NULL;
294 xmlFree(iter);
295 } else {
296 iter->next = table->table[key].next;
297 table->table[key].next = iter;
300 #ifdef DEBUG_GROW
301 nbElem++;
302 #endif
304 iter = next;
308 xmlFree(oldtable);
310 #ifdef DEBUG_GROW
311 xmlGenericError(xmlGenericErrorContext,
312 "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
313 #endif
315 return(0);
319 * xmlHashFree:
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.
326 void
327 xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
328 int i;
329 xmlHashEntryPtr iter;
330 xmlHashEntryPtr next;
331 int inside_table = 0;
332 int nbElems;
334 if (table == NULL)
335 return;
336 if (table->table) {
337 nbElems = table->nbElems;
338 for(i = 0; (i < table->size) && (nbElems > 0); i++) {
339 iter = &(table->table[i]);
340 if (iter->valid == 0)
341 continue;
342 inside_table = 1;
343 while (iter) {
344 next = iter->next;
345 if ((f != NULL) && (iter->payload != NULL))
346 f(iter->payload, iter->name);
347 if (table->dict == NULL) {
348 if (iter->name)
349 xmlFree(iter->name);
350 if (iter->name2)
351 xmlFree(iter->name2);
352 if (iter->name3)
353 xmlFree(iter->name3);
355 iter->payload = NULL;
356 if (!inside_table)
357 xmlFree(iter);
358 nbElems--;
359 inside_table = 0;
360 iter = next;
363 xmlFree(table->table);
365 if (table->dict)
366 xmlDictFree(table->dict);
367 xmlFree(table);
371 * xmlHashDefaultDeallocator:
372 * @entry: the hash table entry
373 * @name: the entry's name
375 * Free a hash table entry with xmlFree.
377 void
378 xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
379 xmlFree(entry);
383 * xmlHashAddEntry:
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));
399 * xmlHashAddEntry2:
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));
457 * xmlHashLookup:
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
465 void *
466 xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
467 return(xmlHashLookup3(table, name, NULL, NULL));
471 * xmlHashLookup2:
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
480 void *
481 xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
482 const xmlChar *name2) {
483 return(xmlHashLookup3(table, name, name2, NULL));
487 * xmlHashQLookup:
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
496 void *
497 xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
498 const xmlChar *name) {
499 return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
503 * xmlHashQLookup2:
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
514 void *
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));
522 * xmlHashAddEntry3:
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
531 * errors.
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,
538 void *userdata) {
539 unsigned long key, len = 0;
540 xmlHashEntryPtr entry;
541 xmlHashEntryPtr insert;
543 if ((table == NULL) || (name == NULL))
544 return(-1);
547 * If using a dict internalize if needed
549 if (table->dict) {
550 if (!xmlDictOwns(table->dict, name)) {
551 name = xmlDictLookup(table->dict, name, -1);
552 if (name == NULL)
553 return(-1);
555 if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
556 name2 = xmlDictLookup(table->dict, name2, -1);
557 if (name2 == NULL)
558 return(-1);
560 if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
561 name3 = xmlDictLookup(table->dict, name3, -1);
562 if (name3 == NULL)
563 return(-1);
568 * Check for duplicate and insertion location.
570 key = xmlHashComputeKey(table, name, name2, name3);
571 if (table->table[key].valid == 0) {
572 insert = NULL;
573 } else {
574 if (table->dict) {
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))
580 return(-1);
581 len++;
583 if ((insert->name == name) &&
584 (insert->name2 == name2) &&
585 (insert->name3 == name3))
586 return(-1);
587 } else {
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)))
593 return(-1);
594 len++;
596 if ((xmlStrEqual(insert->name, name)) &&
597 (xmlStrEqual(insert->name2, name2)) &&
598 (xmlStrEqual(insert->name3, name3)))
599 return(-1);
603 if (insert == NULL) {
604 entry = &(table->table[key]);
605 } else {
606 entry = xmlMalloc(sizeof(xmlHashEntry));
607 if (entry == NULL)
608 return(-1);
611 if (table->dict != NULL) {
612 entry->name = (xmlChar *) name;
613 entry->name2 = (xmlChar *) name2;
614 entry->name3 = (xmlChar *) name3;
615 } else {
616 entry->name = xmlStrdup(name);
617 entry->name2 = xmlStrdup(name2);
618 entry->name3 = xmlStrdup(name3);
620 entry->payload = userdata;
621 entry->next = NULL;
622 entry->valid = 1;
625 if (insert != NULL)
626 insert->next = entry;
628 table->nbElems++;
630 if (len > MAX_HASH_LEN)
631 xmlHashGrow(table, MAX_HASH_LEN * table->size);
633 return(0);
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) {
655 unsigned long key;
656 xmlHashEntryPtr entry;
657 xmlHashEntryPtr insert;
659 if ((table == NULL) || name == NULL)
660 return(-1);
663 * If using a dict internalize if needed
665 if (table->dict) {
666 if (!xmlDictOwns(table->dict, name)) {
667 name = xmlDictLookup(table->dict, name, -1);
668 if (name == NULL)
669 return(-1);
671 if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
672 name2 = xmlDictLookup(table->dict, name2, -1);
673 if (name2 == NULL)
674 return(-1);
676 if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
677 name3 = xmlDictLookup(table->dict, name3, -1);
678 if (name3 == NULL)
679 return(-1);
684 * Check for duplicate and insertion location.
686 key = xmlHashComputeKey(table, name, name2, name3);
687 if (table->table[key].valid == 0) {
688 insert = NULL;
689 } else {
690 if (table ->dict) {
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)) {
696 if (f)
697 f(insert->payload, insert->name);
698 insert->payload = userdata;
699 return(0);
702 if ((insert->name == name) &&
703 (insert->name2 == name2) &&
704 (insert->name3 == name3)) {
705 if (f)
706 f(insert->payload, insert->name);
707 insert->payload = userdata;
708 return(0);
710 } else {
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))) {
716 if (f)
717 f(insert->payload, insert->name);
718 insert->payload = userdata;
719 return(0);
722 if ((xmlStrEqual(insert->name, name)) &&
723 (xmlStrEqual(insert->name2, name2)) &&
724 (xmlStrEqual(insert->name3, name3))) {
725 if (f)
726 f(insert->payload, insert->name);
727 insert->payload = userdata;
728 return(0);
733 if (insert == NULL) {
734 entry = &(table->table[key]);
735 } else {
736 entry = xmlMalloc(sizeof(xmlHashEntry));
737 if (entry == NULL)
738 return(-1);
741 if (table->dict != NULL) {
742 entry->name = (xmlChar *) name;
743 entry->name2 = (xmlChar *) name2;
744 entry->name3 = (xmlChar *) name3;
745 } else {
746 entry->name = xmlStrdup(name);
747 entry->name2 = xmlStrdup(name2);
748 entry->name3 = xmlStrdup(name3);
750 entry->payload = userdata;
751 entry->next = NULL;
752 entry->valid = 1;
753 table->nbElems++;
756 if (insert != NULL) {
757 insert->next = entry;
759 return(0);
763 * xmlHashLookup3:
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
773 void *
774 xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
775 const xmlChar *name2, const xmlChar *name3) {
776 unsigned long key;
777 xmlHashEntryPtr entry;
779 if (table == NULL)
780 return(NULL);
781 if (name == NULL)
782 return(NULL);
783 key = xmlHashComputeKey(table, name, name2, name3);
784 if (table->table[key].valid == 0)
785 return(NULL);
786 if (table->dict) {
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);
800 return(NULL);
804 * xmlHashQLookup3:
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
817 void *
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) {
822 unsigned long key;
823 xmlHashEntryPtr entry;
825 if (table == NULL)
826 return(NULL);
827 if (name == NULL)
828 return(NULL);
829 key = xmlHashComputeQKey(table, prefix, name, prefix2,
830 name2, prefix3, name3);
831 if (table->table[key].valid == 0)
832 return(NULL);
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);
839 return(NULL);
842 typedef struct {
843 xmlHashScanner hashscanner;
844 void *data;
845 } stubData;
847 static void
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);
856 * xmlHashScan:
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.
863 void
864 xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
865 stubData stubdata;
866 stubdata.data = data;
867 stubdata.hashscanner = f;
868 xmlHashScanFull (table, stubHashScannerFull, &stubdata);
872 * xmlHashScanFull:
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.
879 void
880 xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
881 int i, nb;
882 xmlHashEntryPtr iter;
883 xmlHashEntryPtr next;
885 if (table == NULL)
886 return;
887 if (f == NULL)
888 return;
890 if (table->table) {
891 for(i = 0; i < table->size; i++) {
892 if (table->table[i].valid == 0)
893 continue;
894 iter = &(table->table[i]);
895 while (iter) {
896 next = iter->next;
897 nb = table->nbElems;
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)
905 iter = NULL;
906 if (table->table[i].next != next)
907 iter = &(table->table[i]);
908 } else
909 iter = next;
910 } else
911 iter = next;
918 * xmlHashScan3:
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.
930 void
931 xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
932 const xmlChar *name2, const xmlChar *name3,
933 xmlHashScanner f, void *data) {
934 stubData stubdata;
935 stubdata.data = data;
936 stubdata.hashscanner = f;
937 xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
938 &stubdata);
942 * xmlHashScanFull3:
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.
954 void
955 xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
956 const xmlChar *name2, const xmlChar *name3,
957 xmlHashScannerFull f, void *data) {
958 int i;
959 xmlHashEntryPtr iter;
960 xmlHashEntryPtr next;
962 if (table == NULL)
963 return;
964 if (f == NULL)
965 return;
967 if (table->table) {
968 for(i = 0; i < table->size; i++) {
969 if (table->table[i].valid == 0)
970 continue;
971 iter = &(table->table[i]);
972 while (iter) {
973 next = iter->next;
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);
981 iter = next;
988 * xmlHashCopy:
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.
996 xmlHashTablePtr
997 xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
998 int i;
999 xmlHashEntryPtr iter;
1000 xmlHashEntryPtr next;
1001 xmlHashTablePtr ret;
1003 if (table == NULL)
1004 return(NULL);
1005 if (f == NULL)
1006 return(NULL);
1008 ret = xmlHashCreate(table->size);
1009 if (ret == NULL)
1010 return(NULL);
1012 if (table->table) {
1013 for(i = 0; i < table->size; i++) {
1014 if (table->table[i].valid == 0)
1015 continue;
1016 iter = &(table->table[i]);
1017 while (iter) {
1018 next = iter->next;
1019 xmlHashAddEntry3(ret, iter->name, iter->name2,
1020 iter->name3, f(iter->payload, iter->name));
1021 iter = next;
1025 ret->nbElems = table->nbElems;
1026 return(ret);
1030 * xmlHashSize:
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) {
1040 if (table == NULL)
1041 return(-1);
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) {
1098 unsigned long key;
1099 xmlHashEntryPtr entry;
1100 xmlHashEntryPtr prev = NULL;
1102 if (table == NULL || name == NULL)
1103 return(-1);
1105 key = xmlHashComputeKey(table, name, name2, name3);
1106 if (table->table[key].valid == 0) {
1107 return(-1);
1108 } else {
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) {
1117 if(entry->name)
1118 xmlFree(entry->name);
1119 if(entry->name2)
1120 xmlFree(entry->name2);
1121 if(entry->name3)
1122 xmlFree(entry->name3);
1124 if(prev) {
1125 prev->next = entry->next;
1126 xmlFree(entry);
1127 } else {
1128 if (entry->next == NULL) {
1129 entry->valid = 0;
1130 } else {
1131 entry = entry->next;
1132 memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1133 xmlFree(entry);
1136 table->nbElems--;
1137 return(0);
1139 prev = entry;
1141 return(-1);
1145 #define bottom_hash
1146 #include "elfgcchack.h"