VirtualBox

source: vbox/trunk/src/libs/libxml2-2.9.14/hash.c@ 102340

Last change on this file since 102340 was 95312, checked in by vboxsync, 2 years ago

libs/{curl,libxml2}: OSE export fixes, bugref:8515

  • Property svn:eol-style set to native
File size: 29.4 KB
Line 
1/*
2 * hash.c: chained hash tables
3 *
4 * Reference: Your favorite introductory book on algorithms
5 *
6 * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard.
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
13 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
15 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
16 *
17 * Author: breese@users.sourceforge.net
18 */
19
20#define IN_LIBXML
21#include "libxml.h"
22
23#include <string.h>
24#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 */
54typedef struct _xmlHashEntry xmlHashEntry;
55typedef xmlHashEntry *xmlHashEntryPtr;
56struct _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 */
68struct _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__
83ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
84#endif
85static unsigned long
86xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
87 const xmlChar *name2, const xmlChar *name3) {
88 unsigned long value = 0L;
89 unsigned long 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) + 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) + 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) + ch);
110 }
111 }
112 return (value % table->size);
113}
114
115#ifdef __clang__
116ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
117#endif
118static unsigned long
119xmlHashComputeQKey(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 unsigned long 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) + 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) + 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) + 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) + 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) + 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) + 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 */
180xmlHashTablePtr
181xmlHashCreate(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 */
214xmlHashTablePtr
215xmlHashCreateDict(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 */
235static int
236xmlHashGrow(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 */
326void
327xmlHashFree(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 */
377void
378xmlHashDefaultDeallocator(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 */
393int
394xmlHashAddEntry(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 */
410int
411xmlHashAddEntry2(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 */
429int
430xmlHashUpdateEntry(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 */
449int
450xmlHashUpdateEntry2(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 */
465void *
466xmlHashLookup(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 */
480void *
481xmlHashLookup2(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 */
496void *
497xmlHashQLookup(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 */
514void *
515xmlHashQLookup2(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 */
535int
536xmlHashAddEntry3(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 */
651int
652xmlHashUpdateEntry3(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 */
773void *
774xmlHashLookup3(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 */
817void *
818xmlHashQLookup3(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
842typedef struct {
843 xmlHashScanner hashscanner;
844 void *data;
845} stubData;
846
847static void
848stubHashScannerFull (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 */
863void
864xmlHashScan(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 */
879void
880xmlHashScanFull(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 */
930void
931xmlHashScan3(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 */
954void
955xmlHashScanFull3(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 */
996xmlHashTablePtr
997xmlHashCopy(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 */
1038int
1039xmlHashSize(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 */
1057int 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 */
1075int
1076xmlHashRemoveEntry2(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 */
1095int
1096xmlHashRemoveEntry3(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"
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use