| OLD | NEW |
| 1 /* | 1 /* |
| 2 * hash.c: chained hash tables | 2 * hash.c: chained hash tables |
| 3 * | 3 * |
| 4 * Reference: Your favorite introductory book on algorithms | 4 * Reference: Your favorite introductory book on algorithms |
| 5 * | 5 * |
| 6 * Copyright (C) 2000 Bjorn Reese and Daniel Veillard. | 6 * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard. |
| 7 * | 7 * |
| 8 * Permission to use, copy, modify, and distribute this software for any | 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 | 9 * purpose with or without fee is hereby granted, provided that the above |
| 10 * copyright notice and this permission notice appear in all copies. | 10 * copyright notice and this permission notice appear in all copies. |
| 11 * | 11 * |
| 12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED | 12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
| 13 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | 13 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
| 14 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND | 14 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND |
| 15 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. | 15 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. |
| 16 * | 16 * |
| 17 * Author: breese@users.sourceforge.net | 17 * Author: breese@users.sourceforge.net |
| 18 */ | 18 */ |
| 19 | 19 |
| 20 #define IN_LIBXML | 20 #define IN_LIBXML |
| 21 #include "libxml.h" | 21 #include "libxml.h" |
| 22 | 22 |
| 23 #include <string.h> | 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 |
| 24 #include <libxml/parser.h> | 40 #include <libxml/parser.h> |
| 25 #include <libxml/hash.h> | 41 #include <libxml/hash.h> |
| 26 #include <libxml/xmlmemory.h> | 42 #include <libxml/xmlmemory.h> |
| 27 #include <libxml/xmlerror.h> | 43 #include <libxml/xmlerror.h> |
| 28 #include <libxml/globals.h> | 44 #include <libxml/globals.h> |
| 29 | 45 |
| 30 #define MAX_HASH_LEN 8 | 46 #define MAX_HASH_LEN 8 |
| 31 | 47 |
| 32 /* #define DEBUG_GROW */ | 48 /* #define DEBUG_GROW */ |
| 33 | 49 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 46 }; | 62 }; |
| 47 | 63 |
| 48 /* | 64 /* |
| 49 * The entire hash table | 65 * The entire hash table |
| 50 */ | 66 */ |
| 51 struct _xmlHashTable { | 67 struct _xmlHashTable { |
| 52 struct _xmlHashEntry *table; | 68 struct _xmlHashEntry *table; |
| 53 int size; | 69 int size; |
| 54 int nbElems; | 70 int nbElems; |
| 55 xmlDictPtr dict; | 71 xmlDictPtr dict; |
| 72 #ifdef HASH_RANDOMIZATION |
| 73 int random_seed; |
| 74 #endif |
| 56 }; | 75 }; |
| 57 | 76 |
| 58 /* | 77 /* |
| 59 * xmlHashComputeKey: | 78 * xmlHashComputeKey: |
| 60 * Calculate the hash key | 79 * Calculate the hash key |
| 61 */ | 80 */ |
| 62 static unsigned long | 81 static unsigned long |
| 63 xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name, | 82 xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name, |
| 64 const xmlChar *name2, const xmlChar *name3) { | 83 const xmlChar *name2, const xmlChar *name3) { |
| 65 unsigned long value = 0L; | 84 unsigned long value = 0L; |
| 66 char ch; | 85 char ch; |
| 67 | 86 |
| 87 #ifdef HASH_RANDOMIZATION |
| 88 value = table->random_seed; |
| 89 #endif |
| 68 if (name != NULL) { | 90 if (name != NULL) { |
| 69 value += 30 * (*name); | 91 value += 30 * (*name); |
| 70 while ((ch = *name++) != 0) { | 92 while ((ch = *name++) != 0) { |
| 71 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 93 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
| 72 } | 94 } |
| 73 } | 95 } |
| 96 value = value ^ ((value << 5) + (value >> 3)); |
| 74 if (name2 != NULL) { | 97 if (name2 != NULL) { |
| 75 while ((ch = *name2++) != 0) { | 98 while ((ch = *name2++) != 0) { |
| 76 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 99 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
| 77 } | 100 } |
| 78 } | 101 } |
| 102 value = value ^ ((value << 5) + (value >> 3)); |
| 79 if (name3 != NULL) { | 103 if (name3 != NULL) { |
| 80 while ((ch = *name3++) != 0) { | 104 while ((ch = *name3++) != 0) { |
| 81 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 105 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
| 82 } | 106 } |
| 83 } | 107 } |
| 84 return (value % table->size); | 108 return (value % table->size); |
| 85 } | 109 } |
| 86 | 110 |
| 87 static unsigned long | 111 static unsigned long |
| 88 xmlHashComputeQKey(xmlHashTablePtr table, | 112 xmlHashComputeQKey(xmlHashTablePtr table, |
| 89 const xmlChar *prefix, const xmlChar *name, | 113 const xmlChar *prefix, const xmlChar *name, |
| 90 const xmlChar *prefix2, const xmlChar *name2, | 114 const xmlChar *prefix2, const xmlChar *name2, |
| 91 const xmlChar *prefix3, const xmlChar *name3) { | 115 const xmlChar *prefix3, const xmlChar *name3) { |
| 92 unsigned long value = 0L; | 116 unsigned long value = 0L; |
| 93 char ch; | 117 char ch; |
| 94 | 118 |
| 119 #ifdef HASH_RANDOMIZATION |
| 120 value = table->random_seed; |
| 121 #endif |
| 95 if (prefix != NULL) | 122 if (prefix != NULL) |
| 96 value += 30 * (*prefix); | 123 value += 30 * (*prefix); |
| 97 else | 124 else |
| 98 value += 30 * (*name); | 125 value += 30 * (*name); |
| 99 | 126 |
| 100 if (prefix != NULL) { | 127 if (prefix != NULL) { |
| 101 while ((ch = *prefix++) != 0) { | 128 while ((ch = *prefix++) != 0) { |
| 102 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 129 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
| 103 } | 130 } |
| 104 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); | 131 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); |
| 105 } | 132 } |
| 106 if (name != NULL) { | 133 if (name != NULL) { |
| 107 while ((ch = *name++) != 0) { | 134 while ((ch = *name++) != 0) { |
| 108 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 135 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
| 109 } | 136 } |
| 110 } | 137 } |
| 138 value = value ^ ((value << 5) + (value >> 3)); |
| 111 if (prefix2 != NULL) { | 139 if (prefix2 != NULL) { |
| 112 while ((ch = *prefix2++) != 0) { | 140 while ((ch = *prefix2++) != 0) { |
| 113 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 141 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
| 114 } | 142 } |
| 115 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); | 143 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); |
| 116 } | 144 } |
| 117 if (name2 != NULL) { | 145 if (name2 != NULL) { |
| 118 while ((ch = *name2++) != 0) { | 146 while ((ch = *name2++) != 0) { |
| 119 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 147 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
| 120 } | 148 } |
| 121 } | 149 } |
| 150 value = value ^ ((value << 5) + (value >> 3)); |
| 122 if (prefix3 != NULL) { | 151 if (prefix3 != NULL) { |
| 123 while ((ch = *prefix3++) != 0) { | 152 while ((ch = *prefix3++) != 0) { |
| 124 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 153 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
| 125 } | 154 } |
| 126 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); | 155 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); |
| 127 } | 156 } |
| 128 if (name3 != NULL) { | 157 if (name3 != NULL) { |
| 129 while ((ch = *name3++) != 0) { | 158 while ((ch = *name3++) != 0) { |
| 130 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); | 159 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); |
| 131 } | 160 } |
| 132 } | 161 } |
| 133 return (value % table->size); | 162 return (value % table->size); |
| 134 } | 163 } |
| 135 | 164 |
| 136 /** | 165 /** |
| 137 * xmlHashCreate: | 166 * xmlHashCreate: |
| 138 * @size: the size of the hash table | 167 * @size: the size of the hash table |
| 139 * | 168 * |
| 140 * Create a new xmlHashTablePtr. | 169 * Create a new xmlHashTablePtr. |
| 141 * | 170 * |
| 142 * Returns the newly created object, or NULL if an error occured. | 171 * Returns the newly created object, or NULL if an error occured. |
| 143 */ | 172 */ |
| 144 xmlHashTablePtr | 173 xmlHashTablePtr |
| 145 xmlHashCreate(int size) { | 174 xmlHashCreate(int size) { |
| 146 xmlHashTablePtr table; | 175 xmlHashTablePtr table; |
| 147 | 176 |
| 148 if (size <= 0) | 177 if (size <= 0) |
| 149 size = 256; | 178 size = 256; |
| 150 | 179 |
| 151 table = xmlMalloc(sizeof(xmlHashTable)); | 180 table = xmlMalloc(sizeof(xmlHashTable)); |
| 152 if (table) { | 181 if (table) { |
| 153 table->dict = NULL; | 182 table->dict = NULL; |
| 154 table->size = size; | 183 table->size = size; |
| 155 table->nbElems = 0; | 184 table->nbElems = 0; |
| 156 table->table = xmlMalloc(size * sizeof(xmlHashEntry)); | 185 table->table = xmlMalloc(size * sizeof(xmlHashEntry)); |
| 157 if (table->table) { | 186 if (table->table) { |
| 158 » memset(table->table, 0, size * sizeof(xmlHashEntry)); | 187 » memset(table->table, 0, size * sizeof(xmlHashEntry)); |
| 159 » return(table); | 188 #ifdef HASH_RANDOMIZATION |
| 189 table->random_seed = __xmlRandom(); |
| 190 #endif |
| 191 » return(table); |
| 160 } | 192 } |
| 161 xmlFree(table); | 193 xmlFree(table); |
| 162 } | 194 } |
| 163 return(NULL); | 195 return(NULL); |
| 164 } | 196 } |
| 165 | 197 |
| 166 /** | 198 /** |
| 167 * xmlHashCreateDict: | 199 * xmlHashCreateDict: |
| 168 * @size: the size of the hash table | 200 * @size: the size of the hash table |
| 169 * @dict: a dictionary to use for the hash | 201 * @dict: a dictionary to use for the hash |
| (...skipping 25 matching lines...) Expand all Loading... |
| 195 */ | 227 */ |
| 196 static int | 228 static int |
| 197 xmlHashGrow(xmlHashTablePtr table, int size) { | 229 xmlHashGrow(xmlHashTablePtr table, int size) { |
| 198 unsigned long key; | 230 unsigned long key; |
| 199 int oldsize, i; | 231 int oldsize, i; |
| 200 xmlHashEntryPtr iter, next; | 232 xmlHashEntryPtr iter, next; |
| 201 struct _xmlHashEntry *oldtable; | 233 struct _xmlHashEntry *oldtable; |
| 202 #ifdef DEBUG_GROW | 234 #ifdef DEBUG_GROW |
| 203 unsigned long nbElem = 0; | 235 unsigned long nbElem = 0; |
| 204 #endif | 236 #endif |
| 205 | 237 |
| 206 if (table == NULL) | 238 if (table == NULL) |
| 207 return(-1); | 239 return(-1); |
| 208 if (size < 8) | 240 if (size < 8) |
| 209 return(-1); | 241 return(-1); |
| 210 if (size > 8 * 2048) | 242 if (size > 8 * 2048) |
| 211 return(-1); | 243 return(-1); |
| 212 | 244 |
| 213 oldsize = table->size; | 245 oldsize = table->size; |
| 214 oldtable = table->table; | 246 oldtable = table->table; |
| 215 if (oldtable == NULL) | 247 if (oldtable == NULL) |
| 216 return(-1); | 248 return(-1); |
| 217 | 249 |
| 218 table->table = xmlMalloc(size * sizeof(xmlHashEntry)); | 250 table->table = xmlMalloc(size * sizeof(xmlHashEntry)); |
| 219 if (table->table == NULL) { | 251 if (table->table == NULL) { |
| 220 table->table = oldtable; | 252 table->table = oldtable; |
| 221 return(-1); | 253 return(-1); |
| 222 } | 254 } |
| 223 memset(table->table, 0, size * sizeof(xmlHashEntry)); | 255 memset(table->table, 0, size * sizeof(xmlHashEntry)); |
| 224 table->size = size; | 256 table->size = size; |
| 225 | 257 |
| 226 /* If the two loops are merged, there would be situations where | 258 /* If the two loops are merged, there would be situations where |
| 227 » a new entry needs to allocated and data copied into it from | 259 » a new entry needs to allocated and data copied into it from |
| 228 the main table. So instead, we run through the array twice, first | 260 the main table. So instead, we run through the array twice, first |
| 229 copying all the elements in the main array (where we can't get | 261 copying all the elements in the main array (where we can't get |
| 230 conflicts) and then the rest, so we only free (and don't allocate) | 262 conflicts) and then the rest, so we only free (and don't allocate) |
| 231 */ | 263 */ |
| 232 for (i = 0; i < oldsize; i++) { | 264 for (i = 0; i < oldsize; i++) { |
| 233 » if (oldtable[i].valid == 0) | 265 » if (oldtable[i].valid == 0) |
| 234 continue; | 266 continue; |
| 235 key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2, | 267 key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2, |
| 236 oldtable[i].name3); | 268 oldtable[i].name3); |
| 237 memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry)); | 269 memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry)); |
| 238 table->table[key].next = NULL; | 270 table->table[key].next = NULL; |
| 239 } | 271 } |
| 240 | 272 |
| 241 for (i = 0; i < oldsize; i++) { | 273 for (i = 0; i < oldsize; i++) { |
| 242 iter = oldtable[i].next; | 274 iter = oldtable[i].next; |
| 243 while (iter) { | 275 while (iter) { |
| 244 next = iter->next; | 276 next = iter->next; |
| 245 | 277 |
| 246 /* | 278 /* |
| 247 * put back the entry in the new table | 279 * put back the entry in the new table |
| 248 */ | 280 */ |
| 249 | 281 |
| 250 key = xmlHashComputeKey(table, iter->name, iter->name2, | 282 key = xmlHashComputeKey(table, iter->name, iter->name2, |
| 251 iter->name3); | 283 iter->name3); |
| 252 if (table->table[key].valid == 0) { | 284 if (table->table[key].valid == 0) { |
| 253 memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry)); | 285 memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry)); |
| 254 table->table[key].next = NULL; | 286 table->table[key].next = NULL; |
| 255 xmlFree(iter); | 287 xmlFree(iter); |
| 256 } else { | 288 } else { |
| 257 » » iter->next = table->table[key].next; | 289 » » iter->next = table->table[key].next; |
| 258 » » table->table[key].next = iter; | 290 » » table->table[key].next = iter; |
| 259 } | 291 } |
| 260 | 292 |
| 261 #ifdef DEBUG_GROW | 293 #ifdef DEBUG_GROW |
| 262 nbElem++; | 294 nbElem++; |
| 263 #endif | 295 #endif |
| 264 | 296 |
| 265 iter = next; | 297 iter = next; |
| 266 } | 298 } |
| 267 } | 299 } |
| 268 | 300 |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 564 } else { | 596 } else { |
| 565 entry->name = xmlStrdup(name); | 597 entry->name = xmlStrdup(name); |
| 566 entry->name2 = xmlStrdup(name2); | 598 entry->name2 = xmlStrdup(name2); |
| 567 entry->name3 = xmlStrdup(name3); | 599 entry->name3 = xmlStrdup(name3); |
| 568 } | 600 } |
| 569 entry->payload = userdata; | 601 entry->payload = userdata; |
| 570 entry->next = NULL; | 602 entry->next = NULL; |
| 571 entry->valid = 1; | 603 entry->valid = 1; |
| 572 | 604 |
| 573 | 605 |
| 574 if (insert != NULL) | 606 if (insert != NULL) |
| 575 insert->next = entry; | 607 insert->next = entry; |
| 576 | 608 |
| 577 table->nbElems++; | 609 table->nbElems++; |
| 578 | 610 |
| 579 if (len > MAX_HASH_LEN) | 611 if (len > MAX_HASH_LEN) |
| 580 xmlHashGrow(table, MAX_HASH_LEN * table->size); | 612 xmlHashGrow(table, MAX_HASH_LEN * table->size); |
| 581 | 613 |
| 582 return(0); | 614 return(0); |
| 583 } | 615 } |
| 584 | 616 |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 713 * @table: the hash table | 745 * @table: the hash table |
| 714 * @name: the name of the userdata | 746 * @name: the name of the userdata |
| 715 * @name2: a second name of the userdata | 747 * @name2: a second name of the userdata |
| 716 * @name3: a third name of the userdata | 748 * @name3: a third name of the userdata |
| 717 * | 749 * |
| 718 * Find the userdata specified by the (@name, @name2, @name3) tuple. | 750 * Find the userdata specified by the (@name, @name2, @name3) tuple. |
| 719 * | 751 * |
| 720 * Returns the a pointer to the userdata | 752 * Returns the a pointer to the userdata |
| 721 */ | 753 */ |
| 722 void * | 754 void * |
| 723 xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, | 755 xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, |
| 724 const xmlChar *name2, const xmlChar *name3) { | 756 const xmlChar *name2, const xmlChar *name3) { |
| 725 unsigned long key; | 757 unsigned long key; |
| 726 xmlHashEntryPtr entry; | 758 xmlHashEntryPtr entry; |
| 727 | 759 |
| 728 if (table == NULL) | 760 if (table == NULL) |
| 729 return(NULL); | 761 return(NULL); |
| 730 if (name == NULL) | 762 if (name == NULL) |
| 731 return(NULL); | 763 return(NULL); |
| 732 key = xmlHashComputeKey(table, name, name2, name3); | 764 key = xmlHashComputeKey(table, name, name2, name3); |
| 733 if (table->table[key].valid == 0) | 765 if (table->table[key].valid == 0) |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 786 return(entry->payload); | 818 return(entry->payload); |
| 787 } | 819 } |
| 788 return(NULL); | 820 return(NULL); |
| 789 } | 821 } |
| 790 | 822 |
| 791 typedef struct { | 823 typedef struct { |
| 792 xmlHashScanner hashscanner; | 824 xmlHashScanner hashscanner; |
| 793 void *data; | 825 void *data; |
| 794 } stubData; | 826 } stubData; |
| 795 | 827 |
| 796 static void | 828 static void |
| 797 stubHashScannerFull (void *payload, void *data, const xmlChar *name, | 829 stubHashScannerFull (void *payload, void *data, const xmlChar *name, |
| 798 const xmlChar *name2 ATTRIBUTE_UNUSED, | 830 const xmlChar *name2 ATTRIBUTE_UNUSED, |
| 799 const xmlChar *name3 ATTRIBUTE_UNUSED) { | 831 const xmlChar *name3 ATTRIBUTE_UNUSED) { |
| 800 stubData *stubdata = (stubData *) data; | 832 stubData *stubdata = (stubData *) data; |
| 801 stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name); | 833 stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name); |
| 802 } | 834 } |
| 803 | 835 |
| 804 /** | 836 /** |
| 805 * xmlHashScan: | 837 * xmlHashScan: |
| 806 * @table: the hash table | 838 * @table: the hash table |
| 807 * @f: the scanner function for items in the hash | 839 * @f: the scanner function for items in the hash |
| 808 * @data: extra data passed to f | 840 * @data: extra data passed to f |
| 809 * | 841 * |
| 810 * Scan the hash @table and applied @f to each value. | 842 * Scan the hash @table and applied @f to each value. |
| 811 */ | 843 */ |
| 812 void | 844 void |
| 813 xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) { | 845 xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) { |
| 814 stubData stubdata; | 846 stubData stubdata; |
| 815 stubdata.data = data; | 847 stubdata.data = data; |
| 816 stubdata.hashscanner = f; | 848 stubdata.hashscanner = f; |
| 817 xmlHashScanFull (table, stubHashScannerFull, &stubdata); | 849 xmlHashScanFull (table, stubHashScannerFull, &stubdata); |
| 818 } | 850 } |
| 819 | 851 |
| 820 /** | 852 /** |
| 821 * xmlHashScanFull: | 853 * xmlHashScanFull: |
| 822 * @table: the hash table | 854 * @table: the hash table |
| 823 * @f: the scanner function for items in the hash | 855 * @f: the scanner function for items in the hash |
| 824 * @data: extra data passed to f | 856 * @data: extra data passed to f |
| 825 * | 857 * |
| 826 * Scan the hash @table and applied @f to each value. | 858 * Scan the hash @table and applied @f to each value. |
| 827 */ | 859 */ |
| 828 void | 860 void |
| 829 xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) { | 861 xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) { |
| 830 int i, nb; | 862 int i, nb; |
| 831 xmlHashEntryPtr iter; | 863 xmlHashEntryPtr iter; |
| 832 xmlHashEntryPtr next; | 864 xmlHashEntryPtr next; |
| 833 | 865 |
| 834 if (table == NULL) | 866 if (table == NULL) |
| 835 return; | 867 return; |
| 836 if (f == NULL) | 868 if (f == NULL) |
| 837 return; | 869 return; |
| 838 | 870 |
| 839 if (table->table) { | 871 if (table->table) { |
| 840 for(i = 0; i < table->size; i++) { | 872 for(i = 0; i < table->size; i++) { |
| 841 » if (table->table[i].valid == 0) | 873 » if (table->table[i].valid == 0) |
| 842 continue; | 874 continue; |
| 843 iter = &(table->table[i]); | 875 iter = &(table->table[i]); |
| 844 while (iter) { | 876 while (iter) { |
| 845 next = iter->next; | 877 next = iter->next; |
| 846 nb = table->nbElems; | 878 nb = table->nbElems; |
| 847 if ((f != NULL) && (iter->payload != NULL)) | 879 if ((f != NULL) && (iter->payload != NULL)) |
| 848 f(iter->payload, data, iter->name, | 880 f(iter->payload, data, iter->name, |
| 849 iter->name2, iter->name3); | 881 iter->name2, iter->name3); |
| 850 if (nb != table->nbElems) { | 882 if (nb != table->nbElems) { |
| 851 /* table was modified by the callback, be careful */ | 883 /* table was modified by the callback, be careful */ |
| (...skipping 18 matching lines...) Expand all Loading... |
| 870 * @name2: a second name of the userdata or NULL | 902 * @name2: a second name of the userdata or NULL |
| 871 * @name3: a third name of the userdata or NULL | 903 * @name3: a third name of the userdata or NULL |
| 872 * @f: the scanner function for items in the hash | 904 * @f: the scanner function for items in the hash |
| 873 * @data: extra data passed to f | 905 * @data: extra data passed to f |
| 874 * | 906 * |
| 875 * Scan the hash @table and applied @f to each value matching | 907 * Scan the hash @table and applied @f to each value matching |
| 876 * (@name, @name2, @name3) tuple. If one of the names is null, | 908 * (@name, @name2, @name3) tuple. If one of the names is null, |
| 877 * the comparison is considered to match. | 909 * the comparison is considered to match. |
| 878 */ | 910 */ |
| 879 void | 911 void |
| 880 xmlHashScan3(xmlHashTablePtr table, const xmlChar *name, | 912 xmlHashScan3(xmlHashTablePtr table, const xmlChar *name, |
| 881 const xmlChar *name2, const xmlChar *name3, | 913 const xmlChar *name2, const xmlChar *name3, |
| 882 xmlHashScanner f, void *data) { | 914 xmlHashScanner f, void *data) { |
| 883 xmlHashScanFull3 (table, name, name2, name3, | 915 xmlHashScanFull3 (table, name, name2, name3, |
| 884 (xmlHashScannerFull) f, data); | 916 (xmlHashScannerFull) f, data); |
| 885 } | 917 } |
| 886 | 918 |
| 887 /** | 919 /** |
| 888 * xmlHashScanFull3: | 920 * xmlHashScanFull3: |
| 889 * @table: the hash table | 921 * @table: the hash table |
| 890 * @name: the name of the userdata or NULL | 922 * @name: the name of the userdata or NULL |
| 891 * @name2: a second name of the userdata or NULL | 923 * @name2: a second name of the userdata or NULL |
| 892 * @name3: a third name of the userdata or NULL | 924 * @name3: a third name of the userdata or NULL |
| 893 * @f: the scanner function for items in the hash | 925 * @f: the scanner function for items in the hash |
| 894 * @data: extra data passed to f | 926 * @data: extra data passed to f |
| 895 * | 927 * |
| 896 * Scan the hash @table and applied @f to each value matching | 928 * Scan the hash @table and applied @f to each value matching |
| 897 * (@name, @name2, @name3) tuple. If one of the names is null, | 929 * (@name, @name2, @name3) tuple. If one of the names is null, |
| 898 * the comparison is considered to match. | 930 * the comparison is considered to match. |
| 899 */ | 931 */ |
| 900 void | 932 void |
| 901 xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name, | 933 xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name, |
| 902 const xmlChar *name2, const xmlChar *name3, | 934 const xmlChar *name2, const xmlChar *name3, |
| 903 xmlHashScannerFull f, void *data) { | 935 xmlHashScannerFull f, void *data) { |
| 904 int i; | 936 int i; |
| 905 xmlHashEntryPtr iter; | 937 xmlHashEntryPtr iter; |
| 906 xmlHashEntryPtr next; | 938 xmlHashEntryPtr next; |
| 907 | 939 |
| 908 if (table == NULL) | 940 if (table == NULL) |
| 909 return; | 941 return; |
| 910 if (f == NULL) | 942 if (f == NULL) |
| 911 return; | 943 return; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 945 xmlHashEntryPtr iter; | 977 xmlHashEntryPtr iter; |
| 946 xmlHashEntryPtr next; | 978 xmlHashEntryPtr next; |
| 947 xmlHashTablePtr ret; | 979 xmlHashTablePtr ret; |
| 948 | 980 |
| 949 if (table == NULL) | 981 if (table == NULL) |
| 950 return(NULL); | 982 return(NULL); |
| 951 if (f == NULL) | 983 if (f == NULL) |
| 952 return(NULL); | 984 return(NULL); |
| 953 | 985 |
| 954 ret = xmlHashCreate(table->size); | 986 ret = xmlHashCreate(table->size); |
| 987 if (ret == NULL) |
| 988 return(NULL); |
| 989 |
| 955 if (table->table) { | 990 if (table->table) { |
| 956 for(i = 0; i < table->size; i++) { | 991 for(i = 0; i < table->size; i++) { |
| 957 if (table->table[i].valid == 0) | 992 if (table->table[i].valid == 0) |
| 958 continue; | 993 continue; |
| 959 iter = &(table->table[i]); | 994 iter = &(table->table[i]); |
| 960 while (iter) { | 995 while (iter) { |
| 961 next = iter->next; | 996 next = iter->next; |
| 962 xmlHashAddEntry3(ret, iter->name, iter->name2, | 997 xmlHashAddEntry3(ret, iter->name, iter->name2, |
| 963 iter->name3, f(iter->payload, iter->name)); | 998 iter->name3, f(iter->payload, iter->name)); |
| 964 iter = next; | 999 iter = next; |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1080 return(0); | 1115 return(0); |
| 1081 } | 1116 } |
| 1082 prev = entry; | 1117 prev = entry; |
| 1083 } | 1118 } |
| 1084 return(-1); | 1119 return(-1); |
| 1085 } | 1120 } |
| 1086 } | 1121 } |
| 1087 | 1122 |
| 1088 #define bottom_hash | 1123 #define bottom_hash |
| 1089 #include "elfgcchack.h" | 1124 #include "elfgcchack.h" |
| OLD | NEW |