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