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