OLD | NEW |
1 /* | 1 /* |
2 * hash.c: chained hash tables | 2 * hash.c: chained hash tables |
3 * | 3 * |
4 * Reference: Your favorite introductory book on algorithms | 4 * Reference: Your favorite introductory book on algorithms |
5 * | 5 * |
6 * Copyright (C) 2000 Bjorn Reese and Daniel Veillard. | 6 * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard. |
7 * | 7 * |
8 * Permission to use, copy, modify, and distribute this software for any | 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 | 9 * purpose with or without fee is hereby granted, provided that the above |
10 * copyright notice and this permission notice appear in all copies. | 10 * copyright notice and this permission notice appear in all copies. |
11 * | 11 * |
12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED | 12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
13 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | 13 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
14 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND | 14 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND |
15 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. | 15 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. |
16 * | 16 * |
17 * Author: breese@users.sourceforge.net | 17 * Author: breese@users.sourceforge.net |
18 */ | 18 */ |
19 | 19 |
20 #define IN_LIBXML | 20 #define IN_LIBXML |
21 #include "libxml.h" | 21 #include "libxml.h" |
22 | 22 |
23 #include <string.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 |
| 30 |
| 31 /* |
| 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 |
| 35 */ |
| 36 #if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME) |
| 37 #define HASH_RANDOMIZATION |
| 38 #endif |
| 39 |
24 #include <libxml/parser.h> | 40 #include <libxml/parser.h> |
25 #include <libxml/hash.h> | 41 #include <libxml/hash.h> |
26 #include <libxml/xmlmemory.h> | 42 #include <libxml/xmlmemory.h> |
27 #include <libxml/xmlerror.h> | 43 #include <libxml/xmlerror.h> |
28 #include <libxml/globals.h> | 44 #include <libxml/globals.h> |
29 | 45 |
30 #define MAX_HASH_LEN 8 | 46 #define MAX_HASH_LEN 8 |
31 | 47 |
32 /* #define DEBUG_GROW */ | 48 /* #define DEBUG_GROW */ |
33 | 49 |
(...skipping 12 matching lines...) Expand all Loading... |
46 }; | 62 }; |
47 | 63 |
48 /* | 64 /* |
49 * The entire hash table | 65 * The entire hash table |
50 */ | 66 */ |
51 struct _xmlHashTable { | 67 struct _xmlHashTable { |
52 struct _xmlHashEntry *table; | 68 struct _xmlHashEntry *table; |
53 int size; | 69 int size; |
54 int nbElems; | 70 int nbElems; |
55 xmlDictPtr dict; | 71 xmlDictPtr dict; |
| 72 #ifdef HASH_RANDOMIZATION |
| 73 int random_seed; |
| 74 #endif |
56 }; | 75 }; |
57 | 76 |
58 /* | 77 /* |
59 * xmlHashComputeKey: | 78 * xmlHashComputeKey: |
60 * Calculate the hash key | 79 * Calculate the hash key |
61 */ | 80 */ |
62 static unsigned long | 81 static unsigned long |
63 xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name, | 82 xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name, |
64 const xmlChar *name2, const xmlChar *name3) { | 83 const xmlChar *name2, const xmlChar *name3) { |
65 unsigned long value = 0L; | 84 unsigned long value = 0L; |
66 char ch; | 85 char ch; |
67 | 86 |
| 87 #ifdef HASH_RANDOMIZATION |
| 88 value = table->random_seed; |
| 89 #endif |
68 if (name != NULL) { | 90 if (name != NULL) { |
69 value += 30 * (*name); | 91 value += 30 * (*name); |
70 while ((ch = *name++) != 0) { | 92 while ((ch = *name++) != 0) { |
71 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 93 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
72 } | 94 } |
73 } | 95 } |
| 96 value = value ^ ((value << 5) + (value >> 3)); |
74 if (name2 != NULL) { | 97 if (name2 != NULL) { |
75 while ((ch = *name2++) != 0) { | 98 while ((ch = *name2++) != 0) { |
76 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 99 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
77 } | 100 } |
78 } | 101 } |
| 102 value = value ^ ((value << 5) + (value >> 3)); |
79 if (name3 != NULL) { | 103 if (name3 != NULL) { |
80 while ((ch = *name3++) != 0) { | 104 while ((ch = *name3++) != 0) { |
81 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 105 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
82 } | 106 } |
83 } | 107 } |
84 return (value % table->size); | 108 return (value % table->size); |
85 } | 109 } |
86 | 110 |
87 static unsigned long | 111 static unsigned long |
88 xmlHashComputeQKey(xmlHashTablePtr table, | 112 xmlHashComputeQKey(xmlHashTablePtr table, |
89 const xmlChar *prefix, const xmlChar *name, | 113 const xmlChar *prefix, const xmlChar *name, |
90 const xmlChar *prefix2, const xmlChar *name2, | 114 const xmlChar *prefix2, const xmlChar *name2, |
91 const xmlChar *prefix3, const xmlChar *name3) { | 115 const xmlChar *prefix3, const xmlChar *name3) { |
92 unsigned long value = 0L; | 116 unsigned long value = 0L; |
93 char ch; | 117 char ch; |
94 | 118 |
| 119 #ifdef HASH_RANDOMIZATION |
| 120 value = table->random_seed; |
| 121 #endif |
95 if (prefix != NULL) | 122 if (prefix != NULL) |
96 value += 30 * (*prefix); | 123 value += 30 * (*prefix); |
97 else | 124 else |
98 value += 30 * (*name); | 125 value += 30 * (*name); |
99 | 126 |
100 if (prefix != NULL) { | 127 if (prefix != NULL) { |
101 while ((ch = *prefix++) != 0) { | 128 while ((ch = *prefix++) != 0) { |
102 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 129 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
103 } | 130 } |
104 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); | 131 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); |
105 } | 132 } |
106 if (name != NULL) { | 133 if (name != NULL) { |
107 while ((ch = *name++) != 0) { | 134 while ((ch = *name++) != 0) { |
108 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 135 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
109 } | 136 } |
110 } | 137 } |
| 138 value = value ^ ((value << 5) + (value >> 3)); |
111 if (prefix2 != NULL) { | 139 if (prefix2 != NULL) { |
112 while ((ch = *prefix2++) != 0) { | 140 while ((ch = *prefix2++) != 0) { |
113 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 141 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
114 } | 142 } |
115 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); | 143 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); |
116 } | 144 } |
117 if (name2 != NULL) { | 145 if (name2 != NULL) { |
118 while ((ch = *name2++) != 0) { | 146 while ((ch = *name2++) != 0) { |
119 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 147 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
120 } | 148 } |
121 } | 149 } |
| 150 value = value ^ ((value << 5) + (value >> 3)); |
122 if (prefix3 != NULL) { | 151 if (prefix3 != NULL) { |
123 while ((ch = *prefix3++) != 0) { | 152 while ((ch = *prefix3++) != 0) { |
124 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 153 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
125 } | 154 } |
126 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); | 155 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); |
127 } | 156 } |
128 if (name3 != NULL) { | 157 if (name3 != NULL) { |
129 while ((ch = *name3++) != 0) { | 158 while ((ch = *name3++) != 0) { |
130 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 159 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
131 } | 160 } |
132 } | 161 } |
133 return (value % table->size); | 162 return (value % table->size); |
134 } | 163 } |
135 | 164 |
136 /** | 165 /** |
137 * xmlHashCreate: | 166 * xmlHashCreate: |
138 * @size: the size of the hash table | 167 * @size: the size of the hash table |
139 * | 168 * |
140 * Create a new xmlHashTablePtr. | 169 * Create a new xmlHashTablePtr. |
141 * | 170 * |
142 * Returns the newly created object, or NULL if an error occured. | 171 * Returns the newly created object, or NULL if an error occured. |
143 */ | 172 */ |
144 xmlHashTablePtr | 173 xmlHashTablePtr |
145 xmlHashCreate(int size) { | 174 xmlHashCreate(int size) { |
146 xmlHashTablePtr table; | 175 xmlHashTablePtr table; |
147 | 176 |
148 if (size <= 0) | 177 if (size <= 0) |
149 size = 256; | 178 size = 256; |
150 | 179 |
151 table = xmlMalloc(sizeof(xmlHashTable)); | 180 table = xmlMalloc(sizeof(xmlHashTable)); |
152 if (table) { | 181 if (table) { |
153 table->dict = NULL; | 182 table->dict = NULL; |
154 table->size = size; | 183 table->size = size; |
155 table->nbElems = 0; | 184 table->nbElems = 0; |
156 table->table = xmlMalloc(size * sizeof(xmlHashEntry)); | 185 table->table = xmlMalloc(size * sizeof(xmlHashEntry)); |
157 if (table->table) { | 186 if (table->table) { |
158 » memset(table->table, 0, size * sizeof(xmlHashEntry)); | 187 » memset(table->table, 0, size * sizeof(xmlHashEntry)); |
159 » return(table); | 188 #ifdef HASH_RANDOMIZATION |
| 189 table->random_seed = __xmlRandom(); |
| 190 #endif |
| 191 » return(table); |
160 } | 192 } |
161 xmlFree(table); | 193 xmlFree(table); |
162 } | 194 } |
163 return(NULL); | 195 return(NULL); |
164 } | 196 } |
165 | 197 |
166 /** | 198 /** |
167 * xmlHashCreateDict: | 199 * xmlHashCreateDict: |
168 * @size: the size of the hash table | 200 * @size: the size of the hash table |
169 * @dict: a dictionary to use for the hash | 201 * @dict: a dictionary to use for the hash |
(...skipping 25 matching lines...) Expand all Loading... |
195 */ | 227 */ |
196 static int | 228 static int |
197 xmlHashGrow(xmlHashTablePtr table, int size) { | 229 xmlHashGrow(xmlHashTablePtr table, int size) { |
198 unsigned long key; | 230 unsigned long key; |
199 int oldsize, i; | 231 int oldsize, i; |
200 xmlHashEntryPtr iter, next; | 232 xmlHashEntryPtr iter, next; |
201 struct _xmlHashEntry *oldtable; | 233 struct _xmlHashEntry *oldtable; |
202 #ifdef DEBUG_GROW | 234 #ifdef DEBUG_GROW |
203 unsigned long nbElem = 0; | 235 unsigned long nbElem = 0; |
204 #endif | 236 #endif |
205 | 237 |
206 if (table == NULL) | 238 if (table == NULL) |
207 return(-1); | 239 return(-1); |
208 if (size < 8) | 240 if (size < 8) |
209 return(-1); | 241 return(-1); |
210 if (size > 8 * 2048) | 242 if (size > 8 * 2048) |
211 return(-1); | 243 return(-1); |
212 | 244 |
213 oldsize = table->size; | 245 oldsize = table->size; |
214 oldtable = table->table; | 246 oldtable = table->table; |
215 if (oldtable == NULL) | 247 if (oldtable == NULL) |
216 return(-1); | 248 return(-1); |
217 | 249 |
218 table->table = xmlMalloc(size * sizeof(xmlHashEntry)); | 250 table->table = xmlMalloc(size * sizeof(xmlHashEntry)); |
219 if (table->table == NULL) { | 251 if (table->table == NULL) { |
220 table->table = oldtable; | 252 table->table = oldtable; |
221 return(-1); | 253 return(-1); |
222 } | 254 } |
223 memset(table->table, 0, size * sizeof(xmlHashEntry)); | 255 memset(table->table, 0, size * sizeof(xmlHashEntry)); |
224 table->size = size; | 256 table->size = size; |
225 | 257 |
226 /* If the two loops are merged, there would be situations where | 258 /* If the two loops are merged, there would be situations where |
227 » a new entry needs to allocated and data copied into it from | 259 » a new entry needs to allocated and data copied into it from |
228 the main table. So instead, we run through the array twice, first | 260 the main table. So instead, we run through the array twice, first |
229 copying all the elements in the main array (where we can't get | 261 copying all the elements in the main array (where we can't get |
230 conflicts) and then the rest, so we only free (and don't allocate) | 262 conflicts) and then the rest, so we only free (and don't allocate) |
231 */ | 263 */ |
232 for (i = 0; i < oldsize; i++) { | 264 for (i = 0; i < oldsize; i++) { |
233 » if (oldtable[i].valid == 0) | 265 » if (oldtable[i].valid == 0) |
234 continue; | 266 continue; |
235 key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2, | 267 key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2, |
236 oldtable[i].name3); | 268 oldtable[i].name3); |
237 memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry)); | 269 memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry)); |
238 table->table[key].next = NULL; | 270 table->table[key].next = NULL; |
239 } | 271 } |
240 | 272 |
241 for (i = 0; i < oldsize; i++) { | 273 for (i = 0; i < oldsize; i++) { |
242 iter = oldtable[i].next; | 274 iter = oldtable[i].next; |
243 while (iter) { | 275 while (iter) { |
244 next = iter->next; | 276 next = iter->next; |
245 | 277 |
246 /* | 278 /* |
247 * put back the entry in the new table | 279 * put back the entry in the new table |
248 */ | 280 */ |
249 | 281 |
250 key = xmlHashComputeKey(table, iter->name, iter->name2, | 282 key = xmlHashComputeKey(table, iter->name, iter->name2, |
251 iter->name3); | 283 iter->name3); |
252 if (table->table[key].valid == 0) { | 284 if (table->table[key].valid == 0) { |
253 memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry)); | 285 memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry)); |
254 table->table[key].next = NULL; | 286 table->table[key].next = NULL; |
255 xmlFree(iter); | 287 xmlFree(iter); |
256 } else { | 288 } else { |
257 » » iter->next = table->table[key].next; | 289 » » iter->next = table->table[key].next; |
258 » » table->table[key].next = iter; | 290 » » table->table[key].next = iter; |
259 } | 291 } |
260 | 292 |
261 #ifdef DEBUG_GROW | 293 #ifdef DEBUG_GROW |
262 nbElem++; | 294 nbElem++; |
263 #endif | 295 #endif |
264 | 296 |
265 iter = next; | 297 iter = next; |
266 } | 298 } |
267 } | 299 } |
268 | 300 |
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
564 } else { | 596 } else { |
565 entry->name = xmlStrdup(name); | 597 entry->name = xmlStrdup(name); |
566 entry->name2 = xmlStrdup(name2); | 598 entry->name2 = xmlStrdup(name2); |
567 entry->name3 = xmlStrdup(name3); | 599 entry->name3 = xmlStrdup(name3); |
568 } | 600 } |
569 entry->payload = userdata; | 601 entry->payload = userdata; |
570 entry->next = NULL; | 602 entry->next = NULL; |
571 entry->valid = 1; | 603 entry->valid = 1; |
572 | 604 |
573 | 605 |
574 if (insert != NULL) | 606 if (insert != NULL) |
575 insert->next = entry; | 607 insert->next = entry; |
576 | 608 |
577 table->nbElems++; | 609 table->nbElems++; |
578 | 610 |
579 if (len > MAX_HASH_LEN) | 611 if (len > MAX_HASH_LEN) |
580 xmlHashGrow(table, MAX_HASH_LEN * table->size); | 612 xmlHashGrow(table, MAX_HASH_LEN * table->size); |
581 | 613 |
582 return(0); | 614 return(0); |
583 } | 615 } |
584 | 616 |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
713 * @table: the hash table | 745 * @table: the hash table |
714 * @name: the name of the userdata | 746 * @name: the name of the userdata |
715 * @name2: a second name of the userdata | 747 * @name2: a second name of the userdata |
716 * @name3: a third name of the userdata | 748 * @name3: a third name of the userdata |
717 * | 749 * |
718 * Find the userdata specified by the (@name, @name2, @name3) tuple. | 750 * Find the userdata specified by the (@name, @name2, @name3) tuple. |
719 * | 751 * |
720 * Returns the a pointer to the userdata | 752 * Returns the a pointer to the userdata |
721 */ | 753 */ |
722 void * | 754 void * |
723 xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, | 755 xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, |
724 const xmlChar *name2, const xmlChar *name3) { | 756 const xmlChar *name2, const xmlChar *name3) { |
725 unsigned long key; | 757 unsigned long key; |
726 xmlHashEntryPtr entry; | 758 xmlHashEntryPtr entry; |
727 | 759 |
728 if (table == NULL) | 760 if (table == NULL) |
729 return(NULL); | 761 return(NULL); |
730 if (name == NULL) | 762 if (name == NULL) |
731 return(NULL); | 763 return(NULL); |
732 key = xmlHashComputeKey(table, name, name2, name3); | 764 key = xmlHashComputeKey(table, name, name2, name3); |
733 if (table->table[key].valid == 0) | 765 if (table->table[key].valid == 0) |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
786 return(entry->payload); | 818 return(entry->payload); |
787 } | 819 } |
788 return(NULL); | 820 return(NULL); |
789 } | 821 } |
790 | 822 |
791 typedef struct { | 823 typedef struct { |
792 xmlHashScanner hashscanner; | 824 xmlHashScanner hashscanner; |
793 void *data; | 825 void *data; |
794 } stubData; | 826 } stubData; |
795 | 827 |
796 static void | 828 static void |
797 stubHashScannerFull (void *payload, void *data, const xmlChar *name, | 829 stubHashScannerFull (void *payload, void *data, const xmlChar *name, |
798 const xmlChar *name2 ATTRIBUTE_UNUSED, | 830 const xmlChar *name2 ATTRIBUTE_UNUSED, |
799 const xmlChar *name3 ATTRIBUTE_UNUSED) { | 831 const xmlChar *name3 ATTRIBUTE_UNUSED) { |
800 stubData *stubdata = (stubData *) data; | 832 stubData *stubdata = (stubData *) data; |
801 stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name); | 833 stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name); |
802 } | 834 } |
803 | 835 |
804 /** | 836 /** |
805 * xmlHashScan: | 837 * xmlHashScan: |
806 * @table: the hash table | 838 * @table: the hash table |
807 * @f: the scanner function for items in the hash | 839 * @f: the scanner function for items in the hash |
808 * @data: extra data passed to f | 840 * @data: extra data passed to f |
809 * | 841 * |
810 * Scan the hash @table and applied @f to each value. | 842 * Scan the hash @table and applied @f to each value. |
811 */ | 843 */ |
812 void | 844 void |
813 xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) { | 845 xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) { |
814 stubData stubdata; | 846 stubData stubdata; |
815 stubdata.data = data; | 847 stubdata.data = data; |
816 stubdata.hashscanner = f; | 848 stubdata.hashscanner = f; |
817 xmlHashScanFull (table, stubHashScannerFull, &stubdata); | 849 xmlHashScanFull (table, stubHashScannerFull, &stubdata); |
818 } | 850 } |
819 | 851 |
820 /** | 852 /** |
821 * xmlHashScanFull: | 853 * xmlHashScanFull: |
822 * @table: the hash table | 854 * @table: the hash table |
823 * @f: the scanner function for items in the hash | 855 * @f: the scanner function for items in the hash |
824 * @data: extra data passed to f | 856 * @data: extra data passed to f |
825 * | 857 * |
826 * Scan the hash @table and applied @f to each value. | 858 * Scan the hash @table and applied @f to each value. |
827 */ | 859 */ |
828 void | 860 void |
829 xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) { | 861 xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) { |
830 int i, nb; | 862 int i, nb; |
831 xmlHashEntryPtr iter; | 863 xmlHashEntryPtr iter; |
832 xmlHashEntryPtr next; | 864 xmlHashEntryPtr next; |
833 | 865 |
834 if (table == NULL) | 866 if (table == NULL) |
835 return; | 867 return; |
836 if (f == NULL) | 868 if (f == NULL) |
837 return; | 869 return; |
838 | 870 |
839 if (table->table) { | 871 if (table->table) { |
840 for(i = 0; i < table->size; i++) { | 872 for(i = 0; i < table->size; i++) { |
841 » if (table->table[i].valid == 0) | 873 » if (table->table[i].valid == 0) |
842 continue; | 874 continue; |
843 iter = &(table->table[i]); | 875 iter = &(table->table[i]); |
844 while (iter) { | 876 while (iter) { |
845 next = iter->next; | 877 next = iter->next; |
846 nb = table->nbElems; | 878 nb = table->nbElems; |
847 if ((f != NULL) && (iter->payload != NULL)) | 879 if ((f != NULL) && (iter->payload != NULL)) |
848 f(iter->payload, data, iter->name, | 880 f(iter->payload, data, iter->name, |
849 iter->name2, iter->name3); | 881 iter->name2, iter->name3); |
850 if (nb != table->nbElems) { | 882 if (nb != table->nbElems) { |
851 /* table was modified by the callback, be careful */ | 883 /* table was modified by the callback, be careful */ |
(...skipping 18 matching lines...) Expand all Loading... |
870 * @name2: a second name of the userdata or NULL | 902 * @name2: a second name of the userdata or NULL |
871 * @name3: a third name of the userdata or NULL | 903 * @name3: a third name of the userdata or NULL |
872 * @f: the scanner function for items in the hash | 904 * @f: the scanner function for items in the hash |
873 * @data: extra data passed to f | 905 * @data: extra data passed to f |
874 * | 906 * |
875 * Scan the hash @table and applied @f to each value matching | 907 * Scan the hash @table and applied @f to each value matching |
876 * (@name, @name2, @name3) tuple. If one of the names is null, | 908 * (@name, @name2, @name3) tuple. If one of the names is null, |
877 * the comparison is considered to match. | 909 * the comparison is considered to match. |
878 */ | 910 */ |
879 void | 911 void |
880 xmlHashScan3(xmlHashTablePtr table, const xmlChar *name, | 912 xmlHashScan3(xmlHashTablePtr table, const xmlChar *name, |
881 const xmlChar *name2, const xmlChar *name3, | 913 const xmlChar *name2, const xmlChar *name3, |
882 xmlHashScanner f, void *data) { | 914 xmlHashScanner f, void *data) { |
883 xmlHashScanFull3 (table, name, name2, name3, | 915 xmlHashScanFull3 (table, name, name2, name3, |
884 (xmlHashScannerFull) f, data); | 916 (xmlHashScannerFull) f, data); |
885 } | 917 } |
886 | 918 |
887 /** | 919 /** |
888 * xmlHashScanFull3: | 920 * xmlHashScanFull3: |
889 * @table: the hash table | 921 * @table: the hash table |
890 * @name: the name of the userdata or NULL | 922 * @name: the name of the userdata or NULL |
891 * @name2: a second name of the userdata or NULL | 923 * @name2: a second name of the userdata or NULL |
892 * @name3: a third name of the userdata or NULL | 924 * @name3: a third name of the userdata or NULL |
893 * @f: the scanner function for items in the hash | 925 * @f: the scanner function for items in the hash |
894 * @data: extra data passed to f | 926 * @data: extra data passed to f |
895 * | 927 * |
896 * Scan the hash @table and applied @f to each value matching | 928 * Scan the hash @table and applied @f to each value matching |
897 * (@name, @name2, @name3) tuple. If one of the names is null, | 929 * (@name, @name2, @name3) tuple. If one of the names is null, |
898 * the comparison is considered to match. | 930 * the comparison is considered to match. |
899 */ | 931 */ |
900 void | 932 void |
901 xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name, | 933 xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name, |
902 const xmlChar *name2, const xmlChar *name3, | 934 const xmlChar *name2, const xmlChar *name3, |
903 xmlHashScannerFull f, void *data) { | 935 xmlHashScannerFull f, void *data) { |
904 int i; | 936 int i; |
905 xmlHashEntryPtr iter; | 937 xmlHashEntryPtr iter; |
906 xmlHashEntryPtr next; | 938 xmlHashEntryPtr next; |
907 | 939 |
908 if (table == NULL) | 940 if (table == NULL) |
909 return; | 941 return; |
910 if (f == NULL) | 942 if (f == NULL) |
911 return; | 943 return; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
945 xmlHashEntryPtr iter; | 977 xmlHashEntryPtr iter; |
946 xmlHashEntryPtr next; | 978 xmlHashEntryPtr next; |
947 xmlHashTablePtr ret; | 979 xmlHashTablePtr ret; |
948 | 980 |
949 if (table == NULL) | 981 if (table == NULL) |
950 return(NULL); | 982 return(NULL); |
951 if (f == NULL) | 983 if (f == NULL) |
952 return(NULL); | 984 return(NULL); |
953 | 985 |
954 ret = xmlHashCreate(table->size); | 986 ret = xmlHashCreate(table->size); |
| 987 if (ret == NULL) |
| 988 return(NULL); |
| 989 |
955 if (table->table) { | 990 if (table->table) { |
956 for(i = 0; i < table->size; i++) { | 991 for(i = 0; i < table->size; i++) { |
957 if (table->table[i].valid == 0) | 992 if (table->table[i].valid == 0) |
958 continue; | 993 continue; |
959 iter = &(table->table[i]); | 994 iter = &(table->table[i]); |
960 while (iter) { | 995 while (iter) { |
961 next = iter->next; | 996 next = iter->next; |
962 xmlHashAddEntry3(ret, iter->name, iter->name2, | 997 xmlHashAddEntry3(ret, iter->name, iter->name2, |
963 iter->name3, f(iter->payload, iter->name)); | 998 iter->name3, f(iter->payload, iter->name)); |
964 iter = next; | 999 iter = next; |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1080 return(0); | 1115 return(0); |
1081 } | 1116 } |
1082 prev = entry; | 1117 prev = entry; |
1083 } | 1118 } |
1084 return(-1); | 1119 return(-1); |
1085 } | 1120 } |
1086 } | 1121 } |
1087 | 1122 |
1088 #define bottom_hash | 1123 #define bottom_hash |
1089 #include "elfgcchack.h" | 1124 #include "elfgcchack.h" |
OLD | NEW |