blob: b0b4abc92e47827a55539fc504bbf0652142d6b8 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * hash.c: chained hash tables
3 *
4 * Reference: Your favorite introductory book on algorithms
5 *
Daniel Veillard8973d582012-02-04 19:07:44 +08006 * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard.
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
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 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000017 * Author: breese@users.sourceforge.net
Owen Taylor3473f882001-02-23 17:55:21 +000018 */
19
Daniel Veillard34ce8be2002-03-18 19:37:11 +000020#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000021#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000022
23#include <string.h>
Daniel Veillard8973d582012-02-04 19:07:44 +080024#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
Daniel Veillarde57ec792003-09-10 10:50:59 +000040#include <libxml/parser.h>
Owen Taylor3473f882001-02-23 17:55:21 +000041#include <libxml/hash.h>
42#include <libxml/xmlmemory.h>
Daniel Veillarda10efa82001-04-18 13:09:01 +000043#include <libxml/xmlerror.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000044#include <libxml/globals.h>
Daniel Veillarda10efa82001-04-18 13:09:01 +000045
46#define MAX_HASH_LEN 8
47
48/* #define DEBUG_GROW */
Owen Taylor3473f882001-02-23 17:55:21 +000049
50/*
51 * A single entry in the hash table
52 */
53typedef struct _xmlHashEntry xmlHashEntry;
54typedef xmlHashEntry *xmlHashEntryPtr;
55struct _xmlHashEntry {
56 struct _xmlHashEntry *next;
57 xmlChar *name;
58 xmlChar *name2;
59 xmlChar *name3;
60 void *payload;
Daniel Veillardfdc91562002-07-01 21:52:03 +000061 int valid;
Owen Taylor3473f882001-02-23 17:55:21 +000062};
63
64/*
65 * The entire hash table
66 */
67struct _xmlHashTable {
Daniel Veillardfdc91562002-07-01 21:52:03 +000068 struct _xmlHashEntry *table;
Owen Taylor3473f882001-02-23 17:55:21 +000069 int size;
70 int nbElems;
Daniel Veillard316a5c32005-01-23 22:56:39 +000071 xmlDictPtr dict;
Daniel Veillard8973d582012-02-04 19:07:44 +080072#ifdef HASH_RANDOMIZATION
73 int random_seed;
74#endif
Owen Taylor3473f882001-02-23 17:55:21 +000075};
76
77/*
78 * xmlHashComputeKey:
79 * Calculate the hash key
80 */
81static unsigned long
Daniel Veillarda10efa82001-04-18 13:09:01 +000082xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
83 const xmlChar *name2, const xmlChar *name3) {
Owen Taylor3473f882001-02-23 17:55:21 +000084 unsigned long value = 0L;
85 char ch;
Daniel Veillardf8e3db02012-09-11 13:26:36 +080086
Daniel Veillard8973d582012-02-04 19:07:44 +080087#ifdef HASH_RANDOMIZATION
88 value = table->random_seed;
89#endif
Daniel Veillarda10efa82001-04-18 13:09:01 +000090 if (name != NULL) {
91 value += 30 * (*name);
92 while ((ch = *name++) != 0) {
Daniel Veillard5f7f9912002-06-17 17:03:00 +000093 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +000094 }
95 }
Daniel Frankeb1237112013-04-12 18:53:53 +080096 value = value ^ ((value << 5) + (value >> 3));
Daniel Veillarda10efa82001-04-18 13:09:01 +000097 if (name2 != NULL) {
98 while ((ch = *name2++) != 0) {
Daniel Veillard5f7f9912002-06-17 17:03:00 +000099 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000100 }
101 }
Daniel Frankeb1237112013-04-12 18:53:53 +0800102 value = value ^ ((value << 5) + (value >> 3));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000103 if (name3 != NULL) {
104 while ((ch = *name3++) != 0) {
Daniel Veillard5f7f9912002-06-17 17:03:00 +0000105 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000106 }
Owen Taylor3473f882001-02-23 17:55:21 +0000107 }
108 return (value % table->size);
109}
110
Daniel Veillarde57ec792003-09-10 10:50:59 +0000111static unsigned long
112xmlHashComputeQKey(xmlHashTablePtr table,
Daniel Veillard8e36e6a2003-09-10 10:50:59 +0000113 const xmlChar *prefix, const xmlChar *name,
114 const xmlChar *prefix2, const xmlChar *name2,
115 const xmlChar *prefix3, const xmlChar *name3) {
Daniel Veillarde57ec792003-09-10 10:50:59 +0000116 unsigned long value = 0L;
117 char ch;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800118
Daniel Veillard8973d582012-02-04 19:07:44 +0800119#ifdef HASH_RANDOMIZATION
120 value = table->random_seed;
121#endif
Daniel Veillarde57ec792003-09-10 10:50:59 +0000122 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 }
Daniel Frankeb1237112013-04-12 18:53:53 +0800138 value = value ^ ((value << 5) + (value >> 3));
Daniel Veillarde57ec792003-09-10 10:50:59 +0000139 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 }
Daniel Frankeb1237112013-04-12 18:53:53 +0800150 value = value ^ ((value << 5) + (value >> 3));
Daniel Veillarde57ec792003-09-10 10:50:59 +0000151 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
Owen Taylor3473f882001-02-23 17:55:21 +0000165/**
166 * xmlHashCreate:
167 * @size: the size of the hash table
168 *
169 * Create a new xmlHashTablePtr.
170 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200171 * Returns the newly created object, or NULL if an error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000172 */
173xmlHashTablePtr
174xmlHashCreate(int size) {
175 xmlHashTablePtr table;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800176
Owen Taylor3473f882001-02-23 17:55:21 +0000177 if (size <= 0)
178 size = 256;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800179
Owen Taylor3473f882001-02-23 17:55:21 +0000180 table = xmlMalloc(sizeof(xmlHashTable));
181 if (table) {
Daniel Veillard316a5c32005-01-23 22:56:39 +0000182 table->dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000183 table->size = size;
184 table->nbElems = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000185 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
Owen Taylor3473f882001-02-23 17:55:21 +0000186 if (table->table) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800187 memset(table->table, 0, size * sizeof(xmlHashEntry));
Daniel Veillard8973d582012-02-04 19:07:44 +0800188#ifdef HASH_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800189 table->random_seed = __xmlRandom();
Daniel Veillard8973d582012-02-04 19:07:44 +0800190#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800191 return(table);
Owen Taylor3473f882001-02-23 17:55:21 +0000192 }
193 xmlFree(table);
194 }
195 return(NULL);
196}
197
198/**
Daniel Veillard316a5c32005-01-23 22:56:39 +0000199 * 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 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200205 * Returns the newly created object, or NULL if an error occurred.
Daniel Veillard316a5c32005-01-23 22:56:39 +0000206 */
207xmlHashTablePtr
208xmlHashCreateDict(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/**
Daniel Veillarda10efa82001-04-18 13:09:01 +0000220 * 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 */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000228static int
Daniel Veillarda10efa82001-04-18 13:09:01 +0000229xmlHashGrow(xmlHashTablePtr table, int size) {
230 unsigned long key;
231 int oldsize, i;
232 xmlHashEntryPtr iter, next;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000233 struct _xmlHashEntry *oldtable;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000234#ifdef DEBUG_GROW
235 unsigned long nbElem = 0;
236#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800237
Daniel Veillarda10efa82001-04-18 13:09:01 +0000238 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);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800249
Daniel Veillardfdc91562002-07-01 21:52:03 +0000250 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000251 if (table->table == NULL) {
252 table->table = oldtable;
253 return(-1);
254 }
Daniel Veillardfdc91562002-07-01 21:52:03 +0000255 memset(table->table, 0, size * sizeof(xmlHashEntry));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000256 table->size = size;
257
Daniel Veillardfdc91562002-07-01 21:52:03 +0000258 /* If the two loops are merged, there would be situations where
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800259 a new entry needs to allocated and data copied into it from
Daniel Veillardfdc91562002-07-01 21:52:03 +0000260 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 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000264 for (i = 0; i < oldsize; i++) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800265 if (oldtable[i].valid == 0)
Daniel Veillardfdc91562002-07-01 21:52:03 +0000266 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;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000275 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);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000284 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 {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800289 iter->next = table->table[key].next;
290 table->table[key].next = iter;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000291 }
Daniel Veillarda10efa82001-04-18 13:09:01 +0000292
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/**
Owen Taylor3473f882001-02-23 17:55:21 +0000312 * xmlHashFree:
313 * @table: the hash table
314 * @f: the deallocator function for items in the hash
315 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000316 * Free the hash @table and its contents. The userdata is
317 * deallocated with @f if provided.
Owen Taylor3473f882001-02-23 17:55:21 +0000318 */
319void
320xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
321 int i;
322 xmlHashEntryPtr iter;
323 xmlHashEntryPtr next;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000324 int inside_table = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000325 int nbElems;
Owen Taylor3473f882001-02-23 17:55:21 +0000326
327 if (table == NULL)
328 return;
329 if (table->table) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000330 nbElems = table->nbElems;
331 for(i = 0; (i < table->size) && (nbElems > 0); i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000332 iter = &(table->table[i]);
333 if (iter->valid == 0)
334 continue;
335 inside_table = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000336 while (iter) {
337 next = iter->next;
Daniel Veillarde991fe92003-10-29 11:18:37 +0000338 if ((f != NULL) && (iter->payload != NULL))
Daniel Veillarda10efa82001-04-18 13:09:01 +0000339 f(iter->payload, iter->name);
Daniel Veillard316a5c32005-01-23 22:56:39 +0000340 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 }
Owen Taylor3473f882001-02-23 17:55:21 +0000348 iter->payload = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000349 if (!inside_table)
350 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000351 nbElems--;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000352 inside_table = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000353 iter = next;
354 }
Owen Taylor3473f882001-02-23 17:55:21 +0000355 }
356 xmlFree(table->table);
357 }
Daniel Veillard316a5c32005-01-23 22:56:39 +0000358 if (table->dict)
359 xmlDictFree(table->dict);
Owen Taylor3473f882001-02-23 17:55:21 +0000360 xmlFree(table);
361}
362
363/**
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100364 * xmlHashDefaultDeallocator:
365 * @entry: the hash table entry
366 * @name: the entry's name
367 *
368 * Free a hash table entry with xmlFree.
369 */
370void
371xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
372 xmlFree(entry);
373}
374
375/**
Owen Taylor3473f882001-02-23 17:55:21 +0000376 * xmlHashAddEntry:
377 * @table: the hash table
378 * @name: the name of the userdata
379 * @userdata: a pointer to the userdata
380 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000381 * Add the @userdata to the hash @table. This can later be retrieved
382 * by using the @name. Duplicate names generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000383 *
384 * Returns 0 the addition succeeded and -1 in case of error.
385 */
386int
387xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
388 return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
389}
390
391/**
392 * xmlHashAddEntry2:
393 * @table: the hash table
394 * @name: the name of the userdata
395 * @name2: a second name of the userdata
396 * @userdata: a pointer to the userdata
397 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000398 * Add the @userdata to the hash @table. This can later be retrieved
399 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000400 *
401 * Returns 0 the addition succeeded and -1 in case of error.
402 */
403int
404xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
405 const xmlChar *name2, void *userdata) {
406 return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
407}
408
409/**
410 * xmlHashUpdateEntry:
411 * @table: the hash table
412 * @name: the name of the userdata
413 * @userdata: a pointer to the userdata
414 * @f: the deallocator function for replaced item (if any)
415 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000416 * Add the @userdata to the hash @table. This can later be retrieved
417 * by using the @name. Existing entry for this @name will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000418 * and freed with @f if found.
419 *
420 * Returns 0 the addition succeeded and -1 in case of error.
421 */
422int
423xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
424 void *userdata, xmlHashDeallocator f) {
425 return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
426}
427
428/**
429 * xmlHashUpdateEntry2:
430 * @table: the hash table
431 * @name: the name of the userdata
432 * @name2: a second name of the userdata
433 * @userdata: a pointer to the userdata
434 * @f: the deallocator function for replaced item (if any)
435 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000436 * Add the @userdata to the hash @table. This can later be retrieved
437 * by using the (@name, @name2) tuple. Existing entry for this tuple will
Owen Taylor3473f882001-02-23 17:55:21 +0000438 * be removed and freed with @f if found.
439 *
440 * Returns 0 the addition succeeded and -1 in case of error.
441 */
442int
443xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
444 const xmlChar *name2, void *userdata,
445 xmlHashDeallocator f) {
446 return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
447}
448
449/**
450 * xmlHashLookup:
451 * @table: the hash table
452 * @name: the name of the userdata
453 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000454 * Find the userdata specified by the @name.
Owen Taylor3473f882001-02-23 17:55:21 +0000455 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000456 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000457 */
458void *
459xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
460 return(xmlHashLookup3(table, name, NULL, NULL));
461}
462
463/**
464 * xmlHashLookup2:
465 * @table: the hash table
466 * @name: the name of the userdata
467 * @name2: a second name of the userdata
468 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000469 * Find the userdata specified by the (@name, @name2) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000470 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000471 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000472 */
473void *
474xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
475 const xmlChar *name2) {
476 return(xmlHashLookup3(table, name, name2, NULL));
477}
478
479/**
Daniel Veillarde57ec792003-09-10 10:50:59 +0000480 * xmlHashQLookup:
481 * @table: the hash table
482 * @prefix: the prefix of the userdata
483 * @name: the name of the userdata
484 *
485 * Find the userdata specified by the QName @prefix:@name/@name.
486 *
487 * Returns the pointer to the userdata
488 */
489void *
490xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
491 const xmlChar *name) {
492 return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
493}
494
495/**
Daniel Veillard7a02cfe2003-09-25 12:18:34 +0000496 * xmlHashQLookup2:
Daniel Veillarde57ec792003-09-10 10:50:59 +0000497 * @table: the hash table
498 * @prefix: the prefix of the userdata
499 * @name: the name of the userdata
Daniel Veillard092643b2003-09-25 14:29:29 +0000500 * @prefix2: the second prefix of the userdata
Daniel Veillarde57ec792003-09-10 10:50:59 +0000501 * @name2: a second name of the userdata
502 *
503 * Find the userdata specified by the QNames tuple
504 *
505 * Returns the pointer to the userdata
506 */
507void *
508xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix,
509 const xmlChar *name, const xmlChar *prefix2,
510 const xmlChar *name2) {
511 return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
512}
513
514/**
Owen Taylor3473f882001-02-23 17:55:21 +0000515 * xmlHashAddEntry3:
516 * @table: the hash table
517 * @name: the name of the userdata
518 * @name2: a second name of the userdata
519 * @name3: a third name of the userdata
520 * @userdata: a pointer to the userdata
521 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000522 * Add the @userdata to the hash @table. This can later be retrieved
523 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
Owen Taylor3473f882001-02-23 17:55:21 +0000524 * errors.
525 *
526 * Returns 0 the addition succeeded and -1 in case of error.
527 */
528int
529xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
530 const xmlChar *name2, const xmlChar *name3,
531 void *userdata) {
Daniel Veillarda10efa82001-04-18 13:09:01 +0000532 unsigned long key, len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000533 xmlHashEntryPtr entry;
534 xmlHashEntryPtr insert;
535
Daniel Veillard316a5c32005-01-23 22:56:39 +0000536 if ((table == NULL) || (name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +0000537 return(-1);
538
539 /*
Daniel Veillard316a5c32005-01-23 22:56:39 +0000540 * If using a dict internalize if needed
541 */
542 if (table->dict) {
543 if (!xmlDictOwns(table->dict, name)) {
544 name = xmlDictLookup(table->dict, name, -1);
545 if (name == NULL)
546 return(-1);
547 }
548 if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
549 name2 = xmlDictLookup(table->dict, name2, -1);
550 if (name2 == NULL)
551 return(-1);
552 }
553 if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
554 name3 = xmlDictLookup(table->dict, name3, -1);
555 if (name3 == NULL)
556 return(-1);
557 }
558 }
559
560 /*
Owen Taylor3473f882001-02-23 17:55:21 +0000561 * Check for duplicate and insertion location.
562 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000563 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000564 if (table->table[key].valid == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000565 insert = NULL;
566 } else {
Daniel Veillard316a5c32005-01-23 22:56:39 +0000567 if (table->dict) {
568 for (insert = &(table->table[key]); insert->next != NULL;
569 insert = insert->next) {
570 if ((insert->name == name) &&
571 (insert->name2 == name2) &&
572 (insert->name3 == name3))
573 return(-1);
574 len++;
575 }
576 if ((insert->name == name) &&
577 (insert->name2 == name2) &&
578 (insert->name3 == name3))
579 return(-1);
580 } else {
581 for (insert = &(table->table[key]); insert->next != NULL;
582 insert = insert->next) {
583 if ((xmlStrEqual(insert->name, name)) &&
584 (xmlStrEqual(insert->name2, name2)) &&
585 (xmlStrEqual(insert->name3, name3)))
586 return(-1);
587 len++;
588 }
Owen Taylor3473f882001-02-23 17:55:21 +0000589 if ((xmlStrEqual(insert->name, name)) &&
590 (xmlStrEqual(insert->name2, name2)) &&
591 (xmlStrEqual(insert->name3, name3)))
592 return(-1);
593 }
Owen Taylor3473f882001-02-23 17:55:21 +0000594 }
595
Daniel Veillardfdc91562002-07-01 21:52:03 +0000596 if (insert == NULL) {
597 entry = &(table->table[key]);
598 } else {
599 entry = xmlMalloc(sizeof(xmlHashEntry));
600 if (entry == NULL)
601 return(-1);
602 }
603
Daniel Veillard316a5c32005-01-23 22:56:39 +0000604 if (table->dict != NULL) {
605 entry->name = (xmlChar *) name;
606 entry->name2 = (xmlChar *) name2;
607 entry->name3 = (xmlChar *) name3;
608 } else {
609 entry->name = xmlStrdup(name);
610 entry->name2 = xmlStrdup(name2);
611 entry->name3 = xmlStrdup(name3);
612 }
Owen Taylor3473f882001-02-23 17:55:21 +0000613 entry->payload = userdata;
614 entry->next = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000615 entry->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000616
617
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800618 if (insert != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +0000619 insert->next = entry;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000620
Owen Taylor3473f882001-02-23 17:55:21 +0000621 table->nbElems++;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000622
623 if (len > MAX_HASH_LEN)
624 xmlHashGrow(table, MAX_HASH_LEN * table->size);
625
Owen Taylor3473f882001-02-23 17:55:21 +0000626 return(0);
627}
628
629/**
630 * xmlHashUpdateEntry3:
631 * @table: the hash table
632 * @name: the name of the userdata
633 * @name2: a second name of the userdata
634 * @name3: a third name of the userdata
635 * @userdata: a pointer to the userdata
636 * @f: the deallocator function for replaced item (if any)
637 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000638 * Add the @userdata to the hash @table. This can later be retrieved
639 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
Owen Taylor3473f882001-02-23 17:55:21 +0000640 * will be removed and freed with @f if found.
641 *
642 * Returns 0 the addition succeeded and -1 in case of error.
643 */
644int
645xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
646 const xmlChar *name2, const xmlChar *name3,
647 void *userdata, xmlHashDeallocator f) {
648 unsigned long key;
649 xmlHashEntryPtr entry;
650 xmlHashEntryPtr insert;
651
652 if ((table == NULL) || name == NULL)
653 return(-1);
654
655 /*
Daniel Veillard316a5c32005-01-23 22:56:39 +0000656 * If using a dict internalize if needed
657 */
658 if (table->dict) {
659 if (!xmlDictOwns(table->dict, name)) {
660 name = xmlDictLookup(table->dict, name, -1);
661 if (name == NULL)
662 return(-1);
663 }
664 if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
665 name2 = xmlDictLookup(table->dict, name2, -1);
666 if (name2 == NULL)
667 return(-1);
668 }
669 if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
670 name3 = xmlDictLookup(table->dict, name3, -1);
671 if (name3 == NULL)
672 return(-1);
673 }
674 }
675
676 /*
Owen Taylor3473f882001-02-23 17:55:21 +0000677 * Check for duplicate and insertion location.
678 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000679 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000680 if (table->table[key].valid == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000681 insert = NULL;
682 } else {
Daniel Veillard316a5c32005-01-23 22:56:39 +0000683 if (table ->dict) {
684 for (insert = &(table->table[key]); insert->next != NULL;
685 insert = insert->next) {
686 if ((insert->name == name) &&
687 (insert->name2 == name2) &&
688 (insert->name3 == name3)) {
689 if (f)
690 f(insert->payload, insert->name);
691 insert->payload = userdata;
692 return(0);
693 }
694 }
695 if ((insert->name == name) &&
696 (insert->name2 == name2) &&
697 (insert->name3 == name3)) {
698 if (f)
699 f(insert->payload, insert->name);
700 insert->payload = userdata;
701 return(0);
702 }
703 } else {
704 for (insert = &(table->table[key]); insert->next != NULL;
705 insert = insert->next) {
706 if ((xmlStrEqual(insert->name, name)) &&
707 (xmlStrEqual(insert->name2, name2)) &&
708 (xmlStrEqual(insert->name3, name3))) {
709 if (f)
710 f(insert->payload, insert->name);
711 insert->payload = userdata;
712 return(0);
713 }
714 }
Owen Taylor3473f882001-02-23 17:55:21 +0000715 if ((xmlStrEqual(insert->name, name)) &&
716 (xmlStrEqual(insert->name2, name2)) &&
717 (xmlStrEqual(insert->name3, name3))) {
718 if (f)
719 f(insert->payload, insert->name);
720 insert->payload = userdata;
721 return(0);
722 }
723 }
Owen Taylor3473f882001-02-23 17:55:21 +0000724 }
725
Daniel Veillardfdc91562002-07-01 21:52:03 +0000726 if (insert == NULL) {
727 entry = &(table->table[key]);
728 } else {
729 entry = xmlMalloc(sizeof(xmlHashEntry));
730 if (entry == NULL)
731 return(-1);
732 }
733
Daniel Veillard316a5c32005-01-23 22:56:39 +0000734 if (table->dict != NULL) {
735 entry->name = (xmlChar *) name;
736 entry->name2 = (xmlChar *) name2;
737 entry->name3 = (xmlChar *) name3;
738 } else {
739 entry->name = xmlStrdup(name);
740 entry->name2 = xmlStrdup(name2);
741 entry->name3 = xmlStrdup(name3);
742 }
Owen Taylor3473f882001-02-23 17:55:21 +0000743 entry->payload = userdata;
744 entry->next = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000745 entry->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000746 table->nbElems++;
747
748
Daniel Veillardfdc91562002-07-01 21:52:03 +0000749 if (insert != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000750 insert->next = entry;
751 }
752 return(0);
753}
754
755/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000756 * xmlHashLookup3:
Owen Taylor3473f882001-02-23 17:55:21 +0000757 * @table: the hash table
758 * @name: the name of the userdata
759 * @name2: a second name of the userdata
760 * @name3: a third name of the userdata
761 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000762 * Find the userdata specified by the (@name, @name2, @name3) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000763 *
764 * Returns the a pointer to the userdata
765 */
766void *
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800767xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +0000768 const xmlChar *name2, const xmlChar *name3) {
769 unsigned long key;
770 xmlHashEntryPtr entry;
771
772 if (table == NULL)
773 return(NULL);
774 if (name == NULL)
775 return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000776 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000777 if (table->table[key].valid == 0)
778 return(NULL);
Daniel Veillard316a5c32005-01-23 22:56:39 +0000779 if (table->dict) {
780 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
781 if ((entry->name == name) &&
782 (entry->name2 == name2) &&
783 (entry->name3 == name3))
784 return(entry->payload);
785 }
786 }
Daniel Veillardfdc91562002-07-01 21:52:03 +0000787 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Owen Taylor3473f882001-02-23 17:55:21 +0000788 if ((xmlStrEqual(entry->name, name)) &&
789 (xmlStrEqual(entry->name2, name2)) &&
790 (xmlStrEqual(entry->name3, name3)))
791 return(entry->payload);
792 }
793 return(NULL);
794}
795
Daniel Veillarde57ec792003-09-10 10:50:59 +0000796/**
797 * xmlHashQLookup3:
798 * @table: the hash table
799 * @prefix: the prefix of the userdata
800 * @name: the name of the userdata
801 * @prefix2: the second prefix of the userdata
802 * @name2: a second name of the userdata
803 * @prefix3: the third prefix of the userdata
804 * @name3: a third name of the userdata
805 *
806 * Find the userdata specified by the (@name, @name2, @name3) tuple.
807 *
808 * Returns the a pointer to the userdata
809 */
810void *
811xmlHashQLookup3(xmlHashTablePtr table,
812 const xmlChar *prefix, const xmlChar *name,
813 const xmlChar *prefix2, const xmlChar *name2,
814 const xmlChar *prefix3, const xmlChar *name3) {
815 unsigned long key;
816 xmlHashEntryPtr entry;
817
818 if (table == NULL)
819 return(NULL);
820 if (name == NULL)
821 return(NULL);
822 key = xmlHashComputeQKey(table, prefix, name, prefix2,
823 name2, prefix3, name3);
824 if (table->table[key].valid == 0)
825 return(NULL);
826 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
827 if ((xmlStrQEqual(prefix, name, entry->name)) &&
828 (xmlStrQEqual(prefix2, name2, entry->name2)) &&
829 (xmlStrQEqual(prefix3, name3, entry->name3)))
830 return(entry->payload);
831 }
832 return(NULL);
833}
834
Daniel Veillard153120c2002-06-18 07:58:35 +0000835typedef struct {
836 xmlHashScanner hashscanner;
837 void *data;
838} stubData;
839
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800840static void
841stubHashScannerFull (void *payload, void *data, const xmlChar *name,
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000842 const xmlChar *name2 ATTRIBUTE_UNUSED,
843 const xmlChar *name3 ATTRIBUTE_UNUSED) {
Daniel Veillard153120c2002-06-18 07:58:35 +0000844 stubData *stubdata = (stubData *) data;
845 stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800846}
847
Daniel Veillard01c13b52002-12-10 15:19:08 +0000848/**
849 * xmlHashScan:
850 * @table: the hash table
851 * @f: the scanner function for items in the hash
852 * @data: extra data passed to f
853 *
854 * Scan the hash @table and applied @f to each value.
855 */
Owen Taylor3473f882001-02-23 17:55:21 +0000856void
857xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
Daniel Veillard153120c2002-06-18 07:58:35 +0000858 stubData stubdata;
859 stubdata.data = data;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800860 stubdata.hashscanner = f;
Daniel Veillard153120c2002-06-18 07:58:35 +0000861 xmlHashScanFull (table, stubHashScannerFull, &stubdata);
Thomas Broyere8126242001-07-22 03:54:15 +0000862}
863
864/**
865 * xmlHashScanFull:
866 * @table: the hash table
867 * @f: the scanner function for items in the hash
868 * @data: extra data passed to f
869 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000870 * Scan the hash @table and applied @f to each value.
Thomas Broyere8126242001-07-22 03:54:15 +0000871 */
872void
873xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
Daniel Veillardac4118d2008-01-11 05:27:32 +0000874 int i, nb;
Owen Taylor3473f882001-02-23 17:55:21 +0000875 xmlHashEntryPtr iter;
876 xmlHashEntryPtr next;
877
878 if (table == NULL)
879 return;
880 if (f == NULL)
881 return;
882
883 if (table->table) {
884 for(i = 0; i < table->size; i++) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800885 if (table->table[i].valid == 0)
Daniel Veillardfdc91562002-07-01 21:52:03 +0000886 continue;
887 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000888 while (iter) {
889 next = iter->next;
Daniel Veillardac4118d2008-01-11 05:27:32 +0000890 nb = table->nbElems;
Daniel Veillarde991fe92003-10-29 11:18:37 +0000891 if ((f != NULL) && (iter->payload != NULL))
Thomas Broyere8126242001-07-22 03:54:15 +0000892 f(iter->payload, data, iter->name,
893 iter->name2, iter->name3);
Daniel Veillardac4118d2008-01-11 05:27:32 +0000894 if (nb != table->nbElems) {
895 /* table was modified by the callback, be careful */
896 if (iter == &(table->table[i])) {
897 if (table->table[i].valid == 0)
898 iter = NULL;
899 if (table->table[i].next != next)
900 iter = &(table->table[i]);
901 } else
902 iter = next;
903 } else
904 iter = next;
Owen Taylor3473f882001-02-23 17:55:21 +0000905 }
906 }
907 }
908}
909
910/**
911 * xmlHashScan3:
912 * @table: the hash table
913 * @name: the name of the userdata or NULL
914 * @name2: a second name of the userdata or NULL
915 * @name3: a third name of the userdata or NULL
916 * @f: the scanner function for items in the hash
917 * @data: extra data passed to f
918 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000919 * Scan the hash @table and applied @f to each value matching
920 * (@name, @name2, @name3) tuple. If one of the names is null,
Owen Taylor3473f882001-02-23 17:55:21 +0000921 * the comparison is considered to match.
922 */
923void
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800924xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +0000925 const xmlChar *name2, const xmlChar *name3,
926 xmlHashScanner f, void *data) {
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100927 stubData stubdata;
928 stubdata.data = data;
929 stubdata.hashscanner = f;
930 xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
931 &stubdata);
Thomas Broyere8126242001-07-22 03:54:15 +0000932}
933
934/**
935 * xmlHashScanFull3:
936 * @table: the hash table
937 * @name: the name of the userdata or NULL
938 * @name2: a second name of the userdata or NULL
939 * @name3: a third name of the userdata or NULL
940 * @f: the scanner function for items in the hash
941 * @data: extra data passed to f
942 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000943 * Scan the hash @table and applied @f to each value matching
944 * (@name, @name2, @name3) tuple. If one of the names is null,
Thomas Broyere8126242001-07-22 03:54:15 +0000945 * the comparison is considered to match.
946 */
947void
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800948xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
Thomas Broyere8126242001-07-22 03:54:15 +0000949 const xmlChar *name2, const xmlChar *name3,
950 xmlHashScannerFull f, void *data) {
Owen Taylor3473f882001-02-23 17:55:21 +0000951 int i;
952 xmlHashEntryPtr iter;
953 xmlHashEntryPtr next;
954
955 if (table == NULL)
956 return;
957 if (f == NULL)
958 return;
959
960 if (table->table) {
961 for(i = 0; i < table->size; i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000962 if (table->table[i].valid == 0)
963 continue;
964 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000965 while (iter) {
966 next = iter->next;
967 if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
968 ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
Daniel Veillarde991fe92003-10-29 11:18:37 +0000969 ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
970 (iter->payload != NULL)) {
Thomas Broyere8126242001-07-22 03:54:15 +0000971 f(iter->payload, data, iter->name,
972 iter->name2, iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000973 }
974 iter = next;
975 }
976 }
977 }
978}
979
980/**
981 * xmlHashCopy:
982 * @table: the hash table
983 * @f: the copier function for items in the hash
984 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000985 * Scan the hash @table and applied @f to each value.
Owen Taylor3473f882001-02-23 17:55:21 +0000986 *
987 * Returns the new table or NULL in case of error.
988 */
989xmlHashTablePtr
990xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
991 int i;
992 xmlHashEntryPtr iter;
993 xmlHashEntryPtr next;
994 xmlHashTablePtr ret;
995
996 if (table == NULL)
997 return(NULL);
998 if (f == NULL)
999 return(NULL);
1000
1001 ret = xmlHashCreate(table->size);
Gaurav Gupta1811add2014-07-14 17:50:27 +08001002 if (ret == NULL)
1003 return(NULL);
1004
Owen Taylor3473f882001-02-23 17:55:21 +00001005 if (table->table) {
1006 for(i = 0; i < table->size; i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +00001007 if (table->table[i].valid == 0)
1008 continue;
1009 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001010 while (iter) {
1011 next = iter->next;
1012 xmlHashAddEntry3(ret, iter->name, iter->name2,
1013 iter->name3, f(iter->payload, iter->name));
1014 iter = next;
1015 }
1016 }
1017 }
1018 ret->nbElems = table->nbElems;
1019 return(ret);
1020}
1021
1022/**
1023 * xmlHashSize:
1024 * @table: the hash table
1025 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001026 * Query the number of elements installed in the hash @table.
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001027 *
Owen Taylor3473f882001-02-23 17:55:21 +00001028 * Returns the number of elements in the hash table or
1029 * -1 in case of error
1030 */
1031int
1032xmlHashSize(xmlHashTablePtr table) {
1033 if (table == NULL)
1034 return(-1);
1035 return(table->nbElems);
1036}
1037
1038/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00001039 * xmlHashRemoveEntry:
Owen Taylor3473f882001-02-23 17:55:21 +00001040 * @table: the hash table
1041 * @name: the name of the userdata
1042 * @f: the deallocator function for removed item (if any)
1043 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001044 * Find the userdata specified by the @name and remove
1045 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +00001046 * and freed with @f.
1047 *
1048 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1049 */
1050int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001051 xmlHashDeallocator f) {
1052 return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +00001053}
1054
1055/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00001056 * xmlHashRemoveEntry2:
Owen Taylor3473f882001-02-23 17:55:21 +00001057 * @table: the hash table
1058 * @name: the name of the userdata
1059 * @name2: a second name of the userdata
1060 * @f: the deallocator function for removed item (if any)
1061 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001062 * Find the userdata specified by the (@name, @name2) tuple and remove
1063 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +00001064 * and freed with @f.
1065 *
1066 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1067 */
Daniel Veillard01c13b52002-12-10 15:19:08 +00001068int
1069xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001070 const xmlChar *name2, xmlHashDeallocator f) {
1071 return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +00001072}
1073
1074/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001075 * xmlHashRemoveEntry3:
Owen Taylor3473f882001-02-23 17:55:21 +00001076 * @table: the hash table
1077 * @name: the name of the userdata
1078 * @name2: a second name of the userdata
1079 * @name3: a third name of the userdata
1080 * @f: the deallocator function for removed item (if any)
1081 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001082 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
1083 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +00001084 * and freed with @f.
1085 *
1086 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1087 */
Daniel Veillard01c13b52002-12-10 15:19:08 +00001088int
1089xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001090 const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1091 unsigned long key;
1092 xmlHashEntryPtr entry;
1093 xmlHashEntryPtr prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001094
Daniel Veillarda10efa82001-04-18 13:09:01 +00001095 if (table == NULL || name == NULL)
1096 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001097
Daniel Veillarda10efa82001-04-18 13:09:01 +00001098 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001099 if (table->table[key].valid == 0) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00001100 return(-1);
1101 } else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00001102 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00001103 if (xmlStrEqual(entry->name, name) &&
1104 xmlStrEqual(entry->name2, name2) &&
1105 xmlStrEqual(entry->name3, name3)) {
Daniel Veillarde991fe92003-10-29 11:18:37 +00001106 if ((f != NULL) && (entry->payload != NULL))
Daniel Veillarda10efa82001-04-18 13:09:01 +00001107 f(entry->payload, entry->name);
1108 entry->payload = NULL;
Daniel Veillard316a5c32005-01-23 22:56:39 +00001109 if (table->dict == NULL) {
1110 if(entry->name)
1111 xmlFree(entry->name);
1112 if(entry->name2)
1113 xmlFree(entry->name2);
1114 if(entry->name3)
1115 xmlFree(entry->name3);
1116 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001117 if(prev) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00001118 prev->next = entry->next;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001119 xmlFree(entry);
1120 } else {
1121 if (entry->next == NULL) {
1122 entry->valid = 0;
1123 } else {
1124 entry = entry->next;
1125 memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1126 xmlFree(entry);
1127 }
1128 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001129 table->nbElems--;
1130 return(0);
1131 }
1132 prev = entry;
1133 }
1134 return(-1);
1135 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001136}
1137
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001138#define bottom_hash
1139#include "elfgcchack.h"