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