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