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