/src/libxml2-2.10.3/hash.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * hash.c: chained hash tables |
3 | | * |
4 | | * Reference: Your favorite introductory book on algorithms |
5 | | * |
6 | | * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard. |
7 | | * |
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. |
11 | | * |
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. |
16 | | * |
17 | | * Author: breese@users.sourceforge.net |
18 | | */ |
19 | | |
20 | | #define IN_LIBXML |
21 | | #include "libxml.h" |
22 | | |
23 | | #include <string.h> |
24 | | #include <stdlib.h> |
25 | | #include <time.h> |
26 | | |
27 | | /* |
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 |
31 | | */ |
32 | | #if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) |
33 | | #define HASH_RANDOMIZATION |
34 | | #endif |
35 | | |
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> |
41 | | |
42 | 18.7k | #define MAX_HASH_LEN 8 |
43 | | |
44 | | /* #define DEBUG_GROW */ |
45 | | |
46 | | /* |
47 | | * A single entry in the hash table |
48 | | */ |
49 | | typedef struct _xmlHashEntry xmlHashEntry; |
50 | | typedef xmlHashEntry *xmlHashEntryPtr; |
51 | | struct _xmlHashEntry { |
52 | | struct _xmlHashEntry *next; |
53 | | xmlChar *name; |
54 | | xmlChar *name2; |
55 | | xmlChar *name3; |
56 | | void *payload; |
57 | | int valid; |
58 | | }; |
59 | | |
60 | | /* |
61 | | * The entire hash table |
62 | | */ |
63 | | struct _xmlHashTable { |
64 | | struct _xmlHashEntry *table; |
65 | | int size; |
66 | | int nbElems; |
67 | | xmlDictPtr dict; |
68 | | #ifdef HASH_RANDOMIZATION |
69 | | int random_seed; |
70 | | #endif |
71 | | }; |
72 | | |
73 | | /* |
74 | | * xmlHashComputeKey: |
75 | | * Calculate the hash key |
76 | | */ |
77 | | #ifdef __clang__ |
78 | | ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow") |
79 | | #endif |
80 | | static unsigned long |
81 | | xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name, |
82 | 106k | const xmlChar *name2, const xmlChar *name3) { |
83 | 106k | unsigned long value = 0L; |
84 | 106k | unsigned long ch; |
85 | | |
86 | | #ifdef HASH_RANDOMIZATION |
87 | | value = table->random_seed; |
88 | | #endif |
89 | 106k | if (name != NULL) { |
90 | 106k | value += 30 * (*name); |
91 | 1.59M | while ((ch = *name++) != 0) { |
92 | 1.49M | value = value ^ ((value << 5) + (value >> 3) + ch); |
93 | 1.49M | } |
94 | 106k | } |
95 | 106k | value = value ^ ((value << 5) + (value >> 3)); |
96 | 106k | if (name2 != NULL) { |
97 | 151M | while ((ch = *name2++) != 0) { |
98 | 151M | value = value ^ ((value << 5) + (value >> 3) + ch); |
99 | 151M | } |
100 | 80.0k | } |
101 | 106k | value = value ^ ((value << 5) + (value >> 3)); |
102 | 106k | if (name3 != NULL) { |
103 | 0 | while ((ch = *name3++) != 0) { |
104 | 0 | value = value ^ ((value << 5) + (value >> 3) + ch); |
105 | 0 | } |
106 | 0 | } |
107 | 106k | return (value % table->size); |
108 | 106k | } |
109 | | |
110 | | #ifdef __clang__ |
111 | | ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow") |
112 | | #endif |
113 | | static unsigned long |
114 | | xmlHashComputeQKey(xmlHashTablePtr table, |
115 | | const xmlChar *prefix, const xmlChar *name, |
116 | | const xmlChar *prefix2, const xmlChar *name2, |
117 | 153k | const xmlChar *prefix3, const xmlChar *name3) { |
118 | 153k | unsigned long value = 0L; |
119 | 153k | unsigned long ch; |
120 | | |
121 | | #ifdef HASH_RANDOMIZATION |
122 | | value = table->random_seed; |
123 | | #endif |
124 | 153k | if (prefix != NULL) |
125 | 4.15k | value += 30 * (*prefix); |
126 | 149k | else |
127 | 149k | value += 30 * (*name); |
128 | | |
129 | 153k | if (prefix != NULL) { |
130 | 33.2k | while ((ch = *prefix++) != 0) { |
131 | 29.0k | value = value ^ ((value << 5) + (value >> 3) + ch); |
132 | 29.0k | } |
133 | 4.15k | value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); |
134 | 4.15k | } |
135 | 153k | if (name != NULL) { |
136 | 344k | while ((ch = *name++) != 0) { |
137 | 191k | value = value ^ ((value << 5) + (value >> 3) + ch); |
138 | 191k | } |
139 | 153k | } |
140 | 153k | value = value ^ ((value << 5) + (value >> 3)); |
141 | 153k | if (prefix2 != NULL) { |
142 | 42.4k | while ((ch = *prefix2++) != 0) { |
143 | 35.3k | value = value ^ ((value << 5) + (value >> 3) + ch); |
144 | 35.3k | } |
145 | 7.11k | value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); |
146 | 7.11k | } |
147 | 153k | if (name2 != NULL) { |
148 | 345k | while ((ch = *name2++) != 0) { |
149 | 192k | value = value ^ ((value << 5) + (value >> 3) + ch); |
150 | 192k | } |
151 | 153k | } |
152 | 153k | value = value ^ ((value << 5) + (value >> 3)); |
153 | 153k | if (prefix3 != NULL) { |
154 | 0 | while ((ch = *prefix3++) != 0) { |
155 | 0 | value = value ^ ((value << 5) + (value >> 3) + ch); |
156 | 0 | } |
157 | 0 | value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); |
158 | 0 | } |
159 | 153k | if (name3 != NULL) { |
160 | 0 | while ((ch = *name3++) != 0) { |
161 | 0 | value = value ^ ((value << 5) + (value >> 3) + ch); |
162 | 0 | } |
163 | 0 | } |
164 | 153k | return (value % table->size); |
165 | 153k | } |
166 | | |
167 | | /** |
168 | | * xmlHashCreate: |
169 | | * @size: the size of the hash table |
170 | | * |
171 | | * Create a new xmlHashTablePtr. |
172 | | * |
173 | | * Returns the newly created object, or NULL if an error occurred. |
174 | | */ |
175 | | xmlHashTablePtr |
176 | 3.36k | xmlHashCreate(int size) { |
177 | 3.36k | xmlHashTablePtr table; |
178 | | |
179 | 3.36k | if (size <= 0) |
180 | 861 | size = 256; |
181 | | |
182 | 3.36k | table = xmlMalloc(sizeof(xmlHashTable)); |
183 | 3.36k | if (table) { |
184 | 3.36k | table->dict = NULL; |
185 | 3.36k | table->size = size; |
186 | 3.36k | table->nbElems = 0; |
187 | 3.36k | table->table = xmlMalloc(size * sizeof(xmlHashEntry)); |
188 | 3.36k | if (table->table) { |
189 | 3.36k | memset(table->table, 0, size * sizeof(xmlHashEntry)); |
190 | | #ifdef HASH_RANDOMIZATION |
191 | | table->random_seed = __xmlRandom(); |
192 | | #endif |
193 | 3.36k | return(table); |
194 | 3.36k | } |
195 | 0 | xmlFree(table); |
196 | 0 | } |
197 | 0 | return(NULL); |
198 | 3.36k | } |
199 | | |
200 | | /** |
201 | | * xmlHashCreateDict: |
202 | | * @size: the size of the hash table |
203 | | * @dict: a dictionary to use for the hash |
204 | | * |
205 | | * Create a new xmlHashTablePtr which will use @dict as the internal dictionary |
206 | | * |
207 | | * Returns the newly created object, or NULL if an error occurred. |
208 | | */ |
209 | | xmlHashTablePtr |
210 | 3.36k | xmlHashCreateDict(int size, xmlDictPtr dict) { |
211 | 3.36k | xmlHashTablePtr table; |
212 | | |
213 | 3.36k | table = xmlHashCreate(size); |
214 | 3.36k | if (table != NULL) { |
215 | 3.36k | table->dict = dict; |
216 | 3.36k | xmlDictReference(dict); |
217 | 3.36k | } |
218 | 3.36k | return(table); |
219 | 3.36k | } |
220 | | |
221 | | /** |
222 | | * xmlHashGrow: |
223 | | * @table: the hash table |
224 | | * @size: the new size of the hash table |
225 | | * |
226 | | * resize the hash table |
227 | | * |
228 | | * Returns 0 in case of success, -1 in case of failure |
229 | | */ |
230 | | static int |
231 | 137 | xmlHashGrow(xmlHashTablePtr table, int size) { |
232 | 137 | unsigned long key; |
233 | 137 | int oldsize, i; |
234 | 137 | xmlHashEntryPtr iter, next; |
235 | 137 | struct _xmlHashEntry *oldtable; |
236 | | #ifdef DEBUG_GROW |
237 | | unsigned long nbElem = 0; |
238 | | #endif |
239 | | |
240 | 137 | if (table == NULL) |
241 | 0 | return(-1); |
242 | 137 | if (size < 8) |
243 | 0 | return(-1); |
244 | 137 | if (size > 8 * 2048) |
245 | 0 | return(-1); |
246 | | |
247 | 137 | oldsize = table->size; |
248 | 137 | oldtable = table->table; |
249 | 137 | if (oldtable == NULL) |
250 | 0 | return(-1); |
251 | | |
252 | 137 | table->table = xmlMalloc(size * sizeof(xmlHashEntry)); |
253 | 137 | if (table->table == NULL) { |
254 | 0 | table->table = oldtable; |
255 | 0 | return(-1); |
256 | 0 | } |
257 | 137 | memset(table->table, 0, size * sizeof(xmlHashEntry)); |
258 | 137 | table->size = size; |
259 | | |
260 | | /* If the two loops are merged, there would be situations where |
261 | | a new entry needs to allocated and data copied into it from |
262 | | the main table. So instead, we run through the array twice, first |
263 | | copying all the elements in the main array (where we can't get |
264 | | conflicts) and then the rest, so we only free (and don't allocate) |
265 | | */ |
266 | 2.97k | for (i = 0; i < oldsize; i++) { |
267 | 2.84k | if (oldtable[i].valid == 0) |
268 | 650 | continue; |
269 | 2.19k | key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2, |
270 | 2.19k | oldtable[i].name3); |
271 | 2.19k | memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry)); |
272 | 2.19k | table->table[key].next = NULL; |
273 | 2.19k | } |
274 | | |
275 | 2.97k | for (i = 0; i < oldsize; i++) { |
276 | 2.84k | iter = oldtable[i].next; |
277 | 10.4k | while (iter) { |
278 | 7.58k | next = iter->next; |
279 | | |
280 | | /* |
281 | | * put back the entry in the new table |
282 | | */ |
283 | | |
284 | 7.58k | key = xmlHashComputeKey(table, iter->name, iter->name2, |
285 | 7.58k | iter->name3); |
286 | 7.58k | if (table->table[key].valid == 0) { |
287 | 4.78k | memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry)); |
288 | 4.78k | table->table[key].next = NULL; |
289 | 4.78k | xmlFree(iter); |
290 | 4.78k | } else { |
291 | 2.80k | iter->next = table->table[key].next; |
292 | 2.80k | table->table[key].next = iter; |
293 | 2.80k | } |
294 | | |
295 | | #ifdef DEBUG_GROW |
296 | | nbElem++; |
297 | | #endif |
298 | | |
299 | 7.58k | iter = next; |
300 | 7.58k | } |
301 | 2.84k | } |
302 | | |
303 | 137 | xmlFree(oldtable); |
304 | | |
305 | | #ifdef DEBUG_GROW |
306 | | xmlGenericError(xmlGenericErrorContext, |
307 | | "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem); |
308 | | #endif |
309 | | |
310 | 137 | return(0); |
311 | 137 | } |
312 | | |
313 | | /** |
314 | | * xmlHashFree: |
315 | | * @table: the hash table |
316 | | * @f: the deallocator function for items in the hash |
317 | | * |
318 | | * Free the hash @table and its contents. The userdata is |
319 | | * deallocated with @f if provided. |
320 | | */ |
321 | | void |
322 | 3.36k | xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) { |
323 | 3.36k | int i; |
324 | 3.36k | xmlHashEntryPtr iter; |
325 | 3.36k | xmlHashEntryPtr next; |
326 | 3.36k | int inside_table = 0; |
327 | 3.36k | int nbElems; |
328 | | |
329 | 3.36k | if (table == NULL) |
330 | 0 | return; |
331 | 3.36k | if (table->table) { |
332 | 3.36k | nbElems = table->nbElems; |
333 | 193k | for(i = 0; (i < table->size) && (nbElems > 0); i++) { |
334 | 190k | iter = &(table->table[i]); |
335 | 190k | if (iter->valid == 0) |
336 | 177k | continue; |
337 | 12.9k | inside_table = 1; |
338 | 33.1k | while (iter) { |
339 | 20.2k | next = iter->next; |
340 | 20.2k | if ((f != NULL) && (iter->payload != NULL)) |
341 | 3.90k | f(iter->payload, iter->name); |
342 | 20.2k | if (table->dict == NULL) { |
343 | 1.39k | if (iter->name) |
344 | 1.39k | xmlFree(iter->name); |
345 | 1.39k | if (iter->name2) |
346 | 0 | xmlFree(iter->name2); |
347 | 1.39k | if (iter->name3) |
348 | 0 | xmlFree(iter->name3); |
349 | 1.39k | } |
350 | 20.2k | iter->payload = NULL; |
351 | 20.2k | if (!inside_table) |
352 | 7.35k | xmlFree(iter); |
353 | 20.2k | nbElems--; |
354 | 20.2k | inside_table = 0; |
355 | 20.2k | iter = next; |
356 | 20.2k | } |
357 | 12.9k | } |
358 | 3.36k | xmlFree(table->table); |
359 | 3.36k | } |
360 | 3.36k | if (table->dict) |
361 | 2.50k | xmlDictFree(table->dict); |
362 | 3.36k | xmlFree(table); |
363 | 3.36k | } |
364 | | |
365 | | /** |
366 | | * xmlHashDefaultDeallocator: |
367 | | * @entry: the hash table entry |
368 | | * @name: the entry's name |
369 | | * |
370 | | * Free a hash table entry with xmlFree. |
371 | | */ |
372 | | void |
373 | 2.50k | xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) { |
374 | 2.50k | xmlFree(entry); |
375 | 2.50k | } |
376 | | |
377 | | /** |
378 | | * xmlHashAddEntry: |
379 | | * @table: the hash table |
380 | | * @name: the name of the userdata |
381 | | * @userdata: a pointer to the userdata |
382 | | * |
383 | | * Add the @userdata to the hash @table. This can later be retrieved |
384 | | * by using the @name. Duplicate names generate errors. |
385 | | * |
386 | | * Returns 0 the addition succeeded and -1 in case of error. |
387 | | */ |
388 | | int |
389 | 7.77k | xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) { |
390 | 7.77k | return(xmlHashAddEntry3(table, name, NULL, NULL, userdata)); |
391 | 7.77k | } |
392 | | |
393 | | /** |
394 | | * xmlHashAddEntry2: |
395 | | * @table: the hash table |
396 | | * @name: the name of the userdata |
397 | | * @name2: a second name of the userdata |
398 | | * @userdata: a pointer to the userdata |
399 | | * |
400 | | * Add the @userdata to the hash @table. This can later be retrieved |
401 | | * by using the (@name, @name2) tuple. Duplicate tuples generate errors. |
402 | | * |
403 | | * Returns 0 the addition succeeded and -1 in case of error. |
404 | | */ |
405 | | int |
406 | | xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name, |
407 | 17.2k | const xmlChar *name2, void *userdata) { |
408 | 17.2k | return(xmlHashAddEntry3(table, name, name2, NULL, userdata)); |
409 | 17.2k | } |
410 | | |
411 | | /** |
412 | | * xmlHashUpdateEntry: |
413 | | * @table: the hash table |
414 | | * @name: the name of the userdata |
415 | | * @userdata: a pointer to the userdata |
416 | | * @f: the deallocator function for replaced item (if any) |
417 | | * |
418 | | * Add the @userdata to the hash @table. This can later be retrieved |
419 | | * by using the @name. Existing entry for this @name will be removed |
420 | | * and freed with @f if found. |
421 | | * |
422 | | * Returns 0 the addition succeeded and -1 in case of error. |
423 | | */ |
424 | | int |
425 | | xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name, |
426 | 0 | void *userdata, xmlHashDeallocator f) { |
427 | 0 | return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f)); |
428 | 0 | } |
429 | | |
430 | | /** |
431 | | * xmlHashUpdateEntry2: |
432 | | * @table: the hash table |
433 | | * @name: the name of the userdata |
434 | | * @name2: a second name of the userdata |
435 | | * @userdata: a pointer to the userdata |
436 | | * @f: the deallocator function for replaced item (if any) |
437 | | * |
438 | | * Add the @userdata to the hash @table. This can later be retrieved |
439 | | * by using the (@name, @name2) tuple. Existing entry for this tuple will |
440 | | * be removed and freed with @f if found. |
441 | | * |
442 | | * Returns 0 the addition succeeded and -1 in case of error. |
443 | | */ |
444 | | int |
445 | | xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name, |
446 | | const xmlChar *name2, void *userdata, |
447 | 4.54k | xmlHashDeallocator f) { |
448 | 4.54k | return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f)); |
449 | 4.54k | } |
450 | | |
451 | | /** |
452 | | * xmlHashLookup: |
453 | | * @table: the hash table |
454 | | * @name: the name of the userdata |
455 | | * |
456 | | * Find the userdata specified by the @name. |
457 | | * |
458 | | * Returns the pointer to the userdata |
459 | | */ |
460 | | void * |
461 | 0 | xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) { |
462 | 0 | return(xmlHashLookup3(table, name, NULL, NULL)); |
463 | 0 | } |
464 | | |
465 | | /** |
466 | | * xmlHashLookup2: |
467 | | * @table: the hash table |
468 | | * @name: the name of the userdata |
469 | | * @name2: a second name of the userdata |
470 | | * |
471 | | * Find the userdata specified by the (@name, @name2) tuple. |
472 | | * |
473 | | * Returns the pointer to the userdata |
474 | | */ |
475 | | void * |
476 | | xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name, |
477 | 66.5k | const xmlChar *name2) { |
478 | 66.5k | return(xmlHashLookup3(table, name, name2, NULL)); |
479 | 66.5k | } |
480 | | |
481 | | /** |
482 | | * xmlHashQLookup: |
483 | | * @table: the hash table |
484 | | * @prefix: the prefix of the userdata |
485 | | * @name: the name of the userdata |
486 | | * |
487 | | * Find the userdata specified by the QName @prefix:@name/@name. |
488 | | * |
489 | | * Returns the pointer to the userdata |
490 | | */ |
491 | | void * |
492 | | xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix, |
493 | 0 | const xmlChar *name) { |
494 | 0 | return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL)); |
495 | 0 | } |
496 | | |
497 | | /** |
498 | | * xmlHashQLookup2: |
499 | | * @table: the hash table |
500 | | * @prefix: the prefix of the userdata |
501 | | * @name: the name of the userdata |
502 | | * @prefix2: the second prefix of the userdata |
503 | | * @name2: a second name of the userdata |
504 | | * |
505 | | * Find the userdata specified by the QNames tuple |
506 | | * |
507 | | * Returns the pointer to the userdata |
508 | | */ |
509 | | void * |
510 | | xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix, |
511 | | const xmlChar *name, const xmlChar *prefix2, |
512 | 153k | const xmlChar *name2) { |
513 | 153k | return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL)); |
514 | 153k | } |
515 | | |
516 | | /** |
517 | | * xmlHashAddEntry3: |
518 | | * @table: the hash table |
519 | | * @name: the name of the userdata |
520 | | * @name2: a second name of the userdata |
521 | | * @name3: a third name of the userdata |
522 | | * @userdata: a pointer to the userdata |
523 | | * |
524 | | * Add the @userdata to the hash @table. This can later be retrieved |
525 | | * by using the tuple (@name, @name2, @name3). Duplicate entries generate |
526 | | * errors. |
527 | | * |
528 | | * Returns 0 the addition succeeded and -1 in case of error. |
529 | | */ |
530 | | int |
531 | | xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name, |
532 | | const xmlChar *name2, const xmlChar *name3, |
533 | 25.0k | void *userdata) { |
534 | 25.0k | unsigned long key, len = 0; |
535 | 25.0k | xmlHashEntryPtr entry; |
536 | 25.0k | xmlHashEntryPtr insert; |
537 | | |
538 | 25.0k | if ((table == NULL) || (name == NULL)) |
539 | 0 | return(-1); |
540 | | |
541 | | /* |
542 | | * If using a dict internalize if needed |
543 | | */ |
544 | 25.0k | if (table->dict) { |
545 | 17.2k | if (!xmlDictOwns(table->dict, name)) { |
546 | 0 | name = xmlDictLookup(table->dict, name, -1); |
547 | 0 | if (name == NULL) |
548 | 0 | return(-1); |
549 | 0 | } |
550 | 17.2k | if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) { |
551 | 0 | name2 = xmlDictLookup(table->dict, name2, -1); |
552 | 0 | if (name2 == NULL) |
553 | 0 | return(-1); |
554 | 0 | } |
555 | 17.2k | if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) { |
556 | 0 | name3 = xmlDictLookup(table->dict, name3, -1); |
557 | 0 | if (name3 == NULL) |
558 | 0 | return(-1); |
559 | 0 | } |
560 | 17.2k | } |
561 | | |
562 | | /* |
563 | | * Check for duplicate and insertion location. |
564 | | */ |
565 | 25.0k | key = xmlHashComputeKey(table, name, name2, name3); |
566 | 25.0k | if (table->table[key].valid == 0) { |
567 | 6.61k | insert = NULL; |
568 | 18.3k | } else { |
569 | 18.3k | if (table->dict) { |
570 | 36.8k | for (insert = &(table->table[key]); insert->next != NULL; |
571 | 24.8k | insert = insert->next) { |
572 | 24.8k | if ((insert->name == name) && |
573 | 24.8k | (insert->name2 == name2) && |
574 | 24.8k | (insert->name3 == name3)) |
575 | 0 | return(-1); |
576 | 24.8k | len++; |
577 | 24.8k | } |
578 | 11.9k | if ((insert->name == name) && |
579 | 11.9k | (insert->name2 == name2) && |
580 | 11.9k | (insert->name3 == name3)) |
581 | 0 | return(-1); |
582 | 11.9k | } else { |
583 | 7.29k | for (insert = &(table->table[key]); insert->next != NULL; |
584 | 6.46k | insert = insert->next) { |
585 | 1.36k | if ((xmlStrEqual(insert->name, name)) && |
586 | 1.36k | (xmlStrEqual(insert->name2, name2)) && |
587 | 1.36k | (xmlStrEqual(insert->name3, name3))) |
588 | 532 | return(-1); |
589 | 833 | len++; |
590 | 833 | } |
591 | 5.93k | if ((xmlStrEqual(insert->name, name)) && |
592 | 5.93k | (xmlStrEqual(insert->name2, name2)) && |
593 | 5.93k | (xmlStrEqual(insert->name3, name3))) |
594 | 5.84k | return(-1); |
595 | 5.93k | } |
596 | 18.3k | } |
597 | | |
598 | 18.6k | if (insert == NULL) { |
599 | 6.61k | entry = &(table->table[key]); |
600 | 12.0k | } else { |
601 | 12.0k | entry = xmlMalloc(sizeof(xmlHashEntry)); |
602 | 12.0k | if (entry == NULL) |
603 | 0 | return(-1); |
604 | 12.0k | } |
605 | | |
606 | 18.6k | if (table->dict != NULL) { |
607 | 17.2k | entry->name = (xmlChar *) name; |
608 | 17.2k | entry->name2 = (xmlChar *) name2; |
609 | 17.2k | entry->name3 = (xmlChar *) name3; |
610 | 17.2k | } else { |
611 | 1.39k | entry->name = xmlStrdup(name); |
612 | 1.39k | entry->name2 = xmlStrdup(name2); |
613 | 1.39k | entry->name3 = xmlStrdup(name3); |
614 | 1.39k | } |
615 | 18.6k | entry->payload = userdata; |
616 | 18.6k | entry->next = NULL; |
617 | 18.6k | entry->valid = 1; |
618 | | |
619 | | |
620 | 18.6k | if (insert != NULL) |
621 | 12.0k | insert->next = entry; |
622 | | |
623 | 18.6k | table->nbElems++; |
624 | | |
625 | 18.6k | if (len > MAX_HASH_LEN) |
626 | 137 | xmlHashGrow(table, MAX_HASH_LEN * table->size); |
627 | | |
628 | 18.6k | return(0); |
629 | 18.6k | } |
630 | | |
631 | | /** |
632 | | * xmlHashUpdateEntry3: |
633 | | * @table: the hash table |
634 | | * @name: the name of the userdata |
635 | | * @name2: a second name of the userdata |
636 | | * @name3: a third name of the userdata |
637 | | * @userdata: a pointer to the userdata |
638 | | * @f: the deallocator function for replaced item (if any) |
639 | | * |
640 | | * Add the @userdata to the hash @table. This can later be retrieved |
641 | | * by using the tuple (@name, @name2, @name3). Existing entry for this tuple |
642 | | * will be removed and freed with @f if found. |
643 | | * |
644 | | * Returns 0 the addition succeeded and -1 in case of error. |
645 | | */ |
646 | | int |
647 | | xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name, |
648 | | const xmlChar *name2, const xmlChar *name3, |
649 | 4.54k | void *userdata, xmlHashDeallocator f) { |
650 | 4.54k | unsigned long key; |
651 | 4.54k | xmlHashEntryPtr entry; |
652 | 4.54k | xmlHashEntryPtr insert; |
653 | | |
654 | 4.54k | if ((table == NULL) || name == NULL) |
655 | 0 | return(-1); |
656 | | |
657 | | /* |
658 | | * If using a dict internalize if needed |
659 | | */ |
660 | 4.54k | if (table->dict) { |
661 | 4.54k | if (!xmlDictOwns(table->dict, name)) { |
662 | 0 | name = xmlDictLookup(table->dict, name, -1); |
663 | 0 | if (name == NULL) |
664 | 0 | return(-1); |
665 | 0 | } |
666 | 4.54k | if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) { |
667 | 0 | name2 = xmlDictLookup(table->dict, name2, -1); |
668 | 0 | if (name2 == NULL) |
669 | 0 | return(-1); |
670 | 0 | } |
671 | 4.54k | if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) { |
672 | 0 | name3 = xmlDictLookup(table->dict, name3, -1); |
673 | 0 | if (name3 == NULL) |
674 | 0 | return(-1); |
675 | 0 | } |
676 | 4.54k | } |
677 | | |
678 | | /* |
679 | | * Check for duplicate and insertion location. |
680 | | */ |
681 | 4.54k | key = xmlHashComputeKey(table, name, name2, name3); |
682 | 4.54k | if (table->table[key].valid == 0) { |
683 | 1.85k | insert = NULL; |
684 | 2.69k | } else { |
685 | 2.69k | if (table ->dict) { |
686 | 4.44k | for (insert = &(table->table[key]); insert->next != NULL; |
687 | 2.69k | insert = insert->next) { |
688 | 1.76k | if ((insert->name == name) && |
689 | 1.76k | (insert->name2 == name2) && |
690 | 1.76k | (insert->name3 == name3)) { |
691 | 10 | if (f) |
692 | 0 | f(insert->payload, insert->name); |
693 | 10 | insert->payload = userdata; |
694 | 10 | return(0); |
695 | 10 | } |
696 | 1.76k | } |
697 | 2.68k | if ((insert->name == name) && |
698 | 2.68k | (insert->name2 == name2) && |
699 | 2.68k | (insert->name3 == name3)) { |
700 | 2.02k | if (f) |
701 | 0 | f(insert->payload, insert->name); |
702 | 2.02k | insert->payload = userdata; |
703 | 2.02k | return(0); |
704 | 2.02k | } |
705 | 2.68k | } else { |
706 | 0 | for (insert = &(table->table[key]); insert->next != NULL; |
707 | 0 | insert = insert->next) { |
708 | 0 | if ((xmlStrEqual(insert->name, name)) && |
709 | 0 | (xmlStrEqual(insert->name2, name2)) && |
710 | 0 | (xmlStrEqual(insert->name3, name3))) { |
711 | 0 | if (f) |
712 | 0 | f(insert->payload, insert->name); |
713 | 0 | insert->payload = userdata; |
714 | 0 | return(0); |
715 | 0 | } |
716 | 0 | } |
717 | 0 | if ((xmlStrEqual(insert->name, name)) && |
718 | 0 | (xmlStrEqual(insert->name2, name2)) && |
719 | 0 | (xmlStrEqual(insert->name3, name3))) { |
720 | 0 | if (f) |
721 | 0 | f(insert->payload, insert->name); |
722 | 0 | insert->payload = userdata; |
723 | 0 | return(0); |
724 | 0 | } |
725 | 0 | } |
726 | 2.69k | } |
727 | | |
728 | 2.50k | if (insert == NULL) { |
729 | 1.85k | entry = &(table->table[key]); |
730 | 1.85k | } else { |
731 | 656 | entry = xmlMalloc(sizeof(xmlHashEntry)); |
732 | 656 | if (entry == NULL) |
733 | 0 | return(-1); |
734 | 656 | } |
735 | | |
736 | 2.50k | if (table->dict != NULL) { |
737 | 2.50k | entry->name = (xmlChar *) name; |
738 | 2.50k | entry->name2 = (xmlChar *) name2; |
739 | 2.50k | entry->name3 = (xmlChar *) name3; |
740 | 2.50k | } else { |
741 | 0 | entry->name = xmlStrdup(name); |
742 | 0 | entry->name2 = xmlStrdup(name2); |
743 | 0 | entry->name3 = xmlStrdup(name3); |
744 | 0 | } |
745 | 2.50k | entry->payload = userdata; |
746 | 2.50k | entry->next = NULL; |
747 | 2.50k | entry->valid = 1; |
748 | 2.50k | table->nbElems++; |
749 | | |
750 | | |
751 | 2.50k | if (insert != NULL) { |
752 | 656 | insert->next = entry; |
753 | 656 | } |
754 | 2.50k | return(0); |
755 | 2.50k | } |
756 | | |
757 | | /** |
758 | | * xmlHashLookup3: |
759 | | * @table: the hash table |
760 | | * @name: the name of the userdata |
761 | | * @name2: a second name of the userdata |
762 | | * @name3: a third name of the userdata |
763 | | * |
764 | | * Find the userdata specified by the (@name, @name2, @name3) tuple. |
765 | | * |
766 | | * Returns the a pointer to the userdata |
767 | | */ |
768 | | void * |
769 | | xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, |
770 | 66.5k | const xmlChar *name2, const xmlChar *name3) { |
771 | 66.5k | unsigned long key; |
772 | 66.5k | xmlHashEntryPtr entry; |
773 | | |
774 | 66.5k | if (table == NULL) |
775 | 0 | return(NULL); |
776 | 66.5k | if (name == NULL) |
777 | 0 | return(NULL); |
778 | 66.5k | key = xmlHashComputeKey(table, name, name2, name3); |
779 | 66.5k | if (table->table[key].valid == 0) |
780 | 12.1k | return(NULL); |
781 | 54.3k | if (table->dict) { |
782 | 138k | for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { |
783 | 113k | if ((entry->name == name) && |
784 | 113k | (entry->name2 == name2) && |
785 | 113k | (entry->name3 == name3)) |
786 | 29.3k | return(entry->payload); |
787 | 113k | } |
788 | 54.3k | } |
789 | 100k | for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { |
790 | 75.7k | if ((xmlStrEqual(entry->name, name)) && |
791 | 75.7k | (xmlStrEqual(entry->name2, name2)) && |
792 | 75.7k | (xmlStrEqual(entry->name3, name3))) |
793 | 0 | return(entry->payload); |
794 | 75.7k | } |
795 | 24.9k | return(NULL); |
796 | 24.9k | } |
797 | | |
798 | | /** |
799 | | * xmlHashQLookup3: |
800 | | * @table: the hash table |
801 | | * @prefix: the prefix of the userdata |
802 | | * @name: the name of the userdata |
803 | | * @prefix2: the second prefix of the userdata |
804 | | * @name2: a second name of the userdata |
805 | | * @prefix3: the third prefix of the userdata |
806 | | * @name3: a third name of the userdata |
807 | | * |
808 | | * Find the userdata specified by the (@name, @name2, @name3) tuple. |
809 | | * |
810 | | * Returns the a pointer to the userdata |
811 | | */ |
812 | | void * |
813 | | xmlHashQLookup3(xmlHashTablePtr table, |
814 | | const xmlChar *prefix, const xmlChar *name, |
815 | | const xmlChar *prefix2, const xmlChar *name2, |
816 | 153k | const xmlChar *prefix3, const xmlChar *name3) { |
817 | 153k | unsigned long key; |
818 | 153k | xmlHashEntryPtr entry; |
819 | | |
820 | 153k | if (table == NULL) |
821 | 0 | return(NULL); |
822 | 153k | if (name == NULL) |
823 | 0 | return(NULL); |
824 | 153k | key = xmlHashComputeQKey(table, prefix, name, prefix2, |
825 | 153k | name2, prefix3, name3); |
826 | 153k | if (table->table[key].valid == 0) |
827 | 131k | return(NULL); |
828 | 38.9k | for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { |
829 | 23.2k | if ((xmlStrQEqual(prefix, name, entry->name)) && |
830 | 23.2k | (xmlStrQEqual(prefix2, name2, entry->name2)) && |
831 | 23.2k | (xmlStrQEqual(prefix3, name3, entry->name3))) |
832 | 5.65k | return(entry->payload); |
833 | 23.2k | } |
834 | 15.6k | return(NULL); |
835 | 21.2k | } |
836 | | |
837 | | typedef struct { |
838 | | xmlHashScanner hashscanner; |
839 | | void *data; |
840 | | } stubData; |
841 | | |
842 | | static void |
843 | | stubHashScannerFull (void *payload, void *data, const xmlChar *name, |
844 | | const xmlChar *name2 ATTRIBUTE_UNUSED, |
845 | 0 | const xmlChar *name3 ATTRIBUTE_UNUSED) { |
846 | 0 | stubData *stubdata = (stubData *) data; |
847 | 0 | stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name); |
848 | 0 | } |
849 | | |
850 | | /** |
851 | | * xmlHashScan: |
852 | | * @table: the hash table |
853 | | * @f: the scanner function for items in the hash |
854 | | * @data: extra data passed to f |
855 | | * |
856 | | * Scan the hash @table and applied @f to each value. |
857 | | */ |
858 | | void |
859 | 0 | xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) { |
860 | 0 | stubData stubdata; |
861 | 0 | stubdata.data = data; |
862 | 0 | stubdata.hashscanner = f; |
863 | 0 | xmlHashScanFull (table, stubHashScannerFull, &stubdata); |
864 | 0 | } |
865 | | |
866 | | /** |
867 | | * xmlHashScanFull: |
868 | | * @table: the hash table |
869 | | * @f: the scanner function for items in the hash |
870 | | * @data: extra data passed to f |
871 | | * |
872 | | * Scan the hash @table and applied @f to each value. |
873 | | */ |
874 | | void |
875 | 1.31k | xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) { |
876 | 1.31k | int i, nb; |
877 | 1.31k | xmlHashEntryPtr iter; |
878 | 1.31k | xmlHashEntryPtr next; |
879 | | |
880 | 1.31k | if (table == NULL) |
881 | 0 | return; |
882 | 1.31k | if (f == NULL) |
883 | 0 | return; |
884 | | |
885 | 1.31k | if (table->table) { |
886 | 34.3k | for(i = 0; i < table->size; i++) { |
887 | 33.0k | if (table->table[i].valid == 0) |
888 | 22.9k | continue; |
889 | 10.0k | iter = &(table->table[i]); |
890 | 27.2k | while (iter) { |
891 | 17.2k | next = iter->next; |
892 | 17.2k | nb = table->nbElems; |
893 | 17.2k | if ((f != NULL) && (iter->payload != NULL)) |
894 | 17.2k | f(iter->payload, data, iter->name, |
895 | 17.2k | iter->name2, iter->name3); |
896 | 17.2k | if (nb != table->nbElems) { |
897 | | /* table was modified by the callback, be careful */ |
898 | 874 | if (iter == &(table->table[i])) { |
899 | 563 | if (table->table[i].valid == 0) |
900 | 341 | iter = NULL; |
901 | 563 | if (table->table[i].next != next) |
902 | 222 | iter = &(table->table[i]); |
903 | 563 | } else |
904 | 311 | iter = next; |
905 | 874 | } else |
906 | 16.3k | iter = next; |
907 | 17.2k | } |
908 | 10.0k | } |
909 | 1.31k | } |
910 | 1.31k | } |
911 | | |
912 | | /** |
913 | | * xmlHashScan3: |
914 | | * @table: the hash table |
915 | | * @name: the name of the userdata or NULL |
916 | | * @name2: a second name of the userdata or NULL |
917 | | * @name3: a third name of the userdata or NULL |
918 | | * @f: the scanner function for items in the hash |
919 | | * @data: extra data passed to f |
920 | | * |
921 | | * Scan the hash @table and applied @f to each value matching |
922 | | * (@name, @name2, @name3) tuple. If one of the names is null, |
923 | | * the comparison is considered to match. |
924 | | */ |
925 | | void |
926 | | xmlHashScan3(xmlHashTablePtr table, const xmlChar *name, |
927 | | const xmlChar *name2, const xmlChar *name3, |
928 | 0 | xmlHashScanner f, void *data) { |
929 | 0 | stubData stubdata; |
930 | 0 | stubdata.data = data; |
931 | 0 | stubdata.hashscanner = f; |
932 | 0 | xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull, |
933 | 0 | &stubdata); |
934 | 0 | } |
935 | | |
936 | | /** |
937 | | * xmlHashScanFull3: |
938 | | * @table: the hash table |
939 | | * @name: the name of the userdata or NULL |
940 | | * @name2: a second name of the userdata or NULL |
941 | | * @name3: a third name of the userdata or NULL |
942 | | * @f: the scanner function for items in the hash |
943 | | * @data: extra data passed to f |
944 | | * |
945 | | * Scan the hash @table and applied @f to each value matching |
946 | | * (@name, @name2, @name3) tuple. If one of the names is null, |
947 | | * the comparison is considered to match. |
948 | | */ |
949 | | void |
950 | | xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name, |
951 | | const xmlChar *name2, const xmlChar *name3, |
952 | 0 | xmlHashScannerFull f, void *data) { |
953 | 0 | int i; |
954 | 0 | xmlHashEntryPtr iter; |
955 | 0 | xmlHashEntryPtr next; |
956 | |
|
957 | 0 | if (table == NULL) |
958 | 0 | return; |
959 | 0 | if (f == NULL) |
960 | 0 | return; |
961 | | |
962 | 0 | if (table->table) { |
963 | 0 | for(i = 0; i < table->size; i++) { |
964 | 0 | if (table->table[i].valid == 0) |
965 | 0 | continue; |
966 | 0 | iter = &(table->table[i]); |
967 | 0 | while (iter) { |
968 | 0 | next = iter->next; |
969 | 0 | if (((name == NULL) || (xmlStrEqual(name, iter->name))) && |
970 | 0 | ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) && |
971 | 0 | ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) && |
972 | 0 | (iter->payload != NULL)) { |
973 | 0 | f(iter->payload, data, iter->name, |
974 | 0 | iter->name2, iter->name3); |
975 | 0 | } |
976 | 0 | iter = next; |
977 | 0 | } |
978 | 0 | } |
979 | 0 | } |
980 | 0 | } |
981 | | |
982 | | /** |
983 | | * xmlHashCopy: |
984 | | * @table: the hash table |
985 | | * @f: the copier function for items in the hash |
986 | | * |
987 | | * Scan the hash @table and applied @f to each value. |
988 | | * |
989 | | * Returns the new table or NULL in case of error. |
990 | | */ |
991 | | xmlHashTablePtr |
992 | 0 | xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) { |
993 | 0 | int i; |
994 | 0 | xmlHashEntryPtr iter; |
995 | 0 | xmlHashEntryPtr next; |
996 | 0 | xmlHashTablePtr ret; |
997 | |
|
998 | 0 | if (table == NULL) |
999 | 0 | return(NULL); |
1000 | 0 | if (f == NULL) |
1001 | 0 | return(NULL); |
1002 | | |
1003 | 0 | ret = xmlHashCreate(table->size); |
1004 | 0 | if (ret == NULL) |
1005 | 0 | return(NULL); |
1006 | | |
1007 | 0 | if (table->table) { |
1008 | 0 | for(i = 0; i < table->size; i++) { |
1009 | 0 | if (table->table[i].valid == 0) |
1010 | 0 | continue; |
1011 | 0 | iter = &(table->table[i]); |
1012 | 0 | while (iter) { |
1013 | 0 | next = iter->next; |
1014 | 0 | xmlHashAddEntry3(ret, iter->name, iter->name2, |
1015 | 0 | iter->name3, f(iter->payload, iter->name)); |
1016 | 0 | iter = next; |
1017 | 0 | } |
1018 | 0 | } |
1019 | 0 | } |
1020 | 0 | ret->nbElems = table->nbElems; |
1021 | 0 | return(ret); |
1022 | 0 | } |
1023 | | |
1024 | | /** |
1025 | | * xmlHashSize: |
1026 | | * @table: the hash table |
1027 | | * |
1028 | | * Query the number of elements installed in the hash @table. |
1029 | | * |
1030 | | * Returns the number of elements in the hash table or |
1031 | | * -1 in case of error |
1032 | | */ |
1033 | | int |
1034 | 1.31k | xmlHashSize(xmlHashTablePtr table) { |
1035 | 1.31k | if (table == NULL) |
1036 | 0 | return(-1); |
1037 | 1.31k | return(table->nbElems); |
1038 | 1.31k | } |
1039 | | |
1040 | | /** |
1041 | | * xmlHashRemoveEntry: |
1042 | | * @table: the hash table |
1043 | | * @name: the name of the userdata |
1044 | | * @f: the deallocator function for removed item (if any) |
1045 | | * |
1046 | | * Find the userdata specified by the @name and remove |
1047 | | * it from the hash @table. Existing userdata for this tuple will be removed |
1048 | | * and freed with @f. |
1049 | | * |
1050 | | * Returns 0 if the removal succeeded and -1 in case of error or not found. |
1051 | | */ |
1052 | | int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name, |
1053 | 0 | xmlHashDeallocator f) { |
1054 | 0 | return(xmlHashRemoveEntry3(table, name, NULL, NULL, f)); |
1055 | 0 | } |
1056 | | |
1057 | | /** |
1058 | | * xmlHashRemoveEntry2: |
1059 | | * @table: the hash table |
1060 | | * @name: the name of the userdata |
1061 | | * @name2: a second name of the userdata |
1062 | | * @f: the deallocator function for removed item (if any) |
1063 | | * |
1064 | | * Find the userdata specified by the (@name, @name2) tuple and remove |
1065 | | * it from the hash @table. Existing userdata for this tuple will be removed |
1066 | | * and freed with @f. |
1067 | | * |
1068 | | * Returns 0 if the removal succeeded and -1 in case of error or not found. |
1069 | | */ |
1070 | | int |
1071 | | xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name, |
1072 | 874 | const xmlChar *name2, xmlHashDeallocator f) { |
1073 | 874 | return(xmlHashRemoveEntry3(table, name, name2, NULL, f)); |
1074 | 874 | } |
1075 | | |
1076 | | /** |
1077 | | * xmlHashRemoveEntry3: |
1078 | | * @table: the hash table |
1079 | | * @name: the name of the userdata |
1080 | | * @name2: a second name of the userdata |
1081 | | * @name3: a third name of the userdata |
1082 | | * @f: the deallocator function for removed item (if any) |
1083 | | * |
1084 | | * Find the userdata specified by the (@name, @name2, @name3) tuple and remove |
1085 | | * it from the hash @table. Existing userdata for this tuple will be removed |
1086 | | * and freed with @f. |
1087 | | * |
1088 | | * Returns 0 if the removal succeeded and -1 in case of error or not found. |
1089 | | */ |
1090 | | int |
1091 | | xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name, |
1092 | 874 | const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) { |
1093 | 874 | unsigned long key; |
1094 | 874 | xmlHashEntryPtr entry; |
1095 | 874 | xmlHashEntryPtr prev = NULL; |
1096 | | |
1097 | 874 | if (table == NULL || name == NULL) |
1098 | 0 | return(-1); |
1099 | | |
1100 | 874 | key = xmlHashComputeKey(table, name, name2, name3); |
1101 | 874 | if (table->table[key].valid == 0) { |
1102 | 0 | return(-1); |
1103 | 874 | } else { |
1104 | 1.38k | for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { |
1105 | 1.38k | if (xmlStrEqual(entry->name, name) && |
1106 | 1.38k | xmlStrEqual(entry->name2, name2) && |
1107 | 1.38k | xmlStrEqual(entry->name3, name3)) { |
1108 | 874 | if ((f != NULL) && (entry->payload != NULL)) |
1109 | 0 | f(entry->payload, entry->name); |
1110 | 874 | entry->payload = NULL; |
1111 | 874 | if (table->dict == NULL) { |
1112 | 0 | if(entry->name) |
1113 | 0 | xmlFree(entry->name); |
1114 | 0 | if(entry->name2) |
1115 | 0 | xmlFree(entry->name2); |
1116 | 0 | if(entry->name3) |
1117 | 0 | xmlFree(entry->name3); |
1118 | 0 | } |
1119 | 874 | if(prev) { |
1120 | 311 | prev->next = entry->next; |
1121 | 311 | xmlFree(entry); |
1122 | 563 | } else { |
1123 | 563 | if (entry->next == NULL) { |
1124 | 341 | entry->valid = 0; |
1125 | 341 | } else { |
1126 | 222 | entry = entry->next; |
1127 | 222 | memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry)); |
1128 | 222 | xmlFree(entry); |
1129 | 222 | } |
1130 | 563 | } |
1131 | 874 | table->nbElems--; |
1132 | 874 | return(0); |
1133 | 874 | } |
1134 | 512 | prev = entry; |
1135 | 512 | } |
1136 | 0 | return(-1); |
1137 | 874 | } |
1138 | 874 | } |
1139 | | |