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