blob: f9a201722445f17a297414fc222106b0ea40f39f [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 *
171 * Returns the newly created object, or NULL if an error occured.
172 */
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 *
205 * Returns the newly created object, or NULL if an error occured.
206 */
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/**
364 * xmlHashAddEntry:
365 * @table: the hash table
366 * @name: the name of the userdata
367 * @userdata: a pointer to the userdata
368 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000369 * Add the @userdata to the hash @table. This can later be retrieved
370 * by using the @name. Duplicate names generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000371 *
372 * Returns 0 the addition succeeded and -1 in case of error.
373 */
374int
375xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
376 return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
377}
378
379/**
380 * xmlHashAddEntry2:
381 * @table: the hash table
382 * @name: the name of the userdata
383 * @name2: a second name of the userdata
384 * @userdata: a pointer to the userdata
385 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000386 * Add the @userdata to the hash @table. This can later be retrieved
387 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000388 *
389 * Returns 0 the addition succeeded and -1 in case of error.
390 */
391int
392xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
393 const xmlChar *name2, void *userdata) {
394 return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
395}
396
397/**
398 * xmlHashUpdateEntry:
399 * @table: the hash table
400 * @name: the name of the userdata
401 * @userdata: a pointer to the userdata
402 * @f: the deallocator function for replaced item (if any)
403 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000404 * Add the @userdata to the hash @table. This can later be retrieved
405 * by using the @name. Existing entry for this @name will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000406 * and freed with @f if found.
407 *
408 * Returns 0 the addition succeeded and -1 in case of error.
409 */
410int
411xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
412 void *userdata, xmlHashDeallocator f) {
413 return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
414}
415
416/**
417 * xmlHashUpdateEntry2:
418 * @table: the hash table
419 * @name: the name of the userdata
420 * @name2: a second name of the userdata
421 * @userdata: a pointer to the userdata
422 * @f: the deallocator function for replaced item (if any)
423 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000424 * Add the @userdata to the hash @table. This can later be retrieved
425 * by using the (@name, @name2) tuple. Existing entry for this tuple will
Owen Taylor3473f882001-02-23 17:55:21 +0000426 * be removed and freed with @f if found.
427 *
428 * Returns 0 the addition succeeded and -1 in case of error.
429 */
430int
431xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
432 const xmlChar *name2, void *userdata,
433 xmlHashDeallocator f) {
434 return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
435}
436
437/**
438 * xmlHashLookup:
439 * @table: the hash table
440 * @name: the name of the userdata
441 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000442 * Find the userdata specified by the @name.
Owen Taylor3473f882001-02-23 17:55:21 +0000443 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000444 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000445 */
446void *
447xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
448 return(xmlHashLookup3(table, name, NULL, NULL));
449}
450
451/**
452 * xmlHashLookup2:
453 * @table: the hash table
454 * @name: the name of the userdata
455 * @name2: a second name of the userdata
456 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000457 * Find the userdata specified by the (@name, @name2) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000458 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000459 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000460 */
461void *
462xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
463 const xmlChar *name2) {
464 return(xmlHashLookup3(table, name, name2, NULL));
465}
466
467/**
Daniel Veillarde57ec792003-09-10 10:50:59 +0000468 * xmlHashQLookup:
469 * @table: the hash table
470 * @prefix: the prefix of the userdata
471 * @name: the name of the userdata
472 *
473 * Find the userdata specified by the QName @prefix:@name/@name.
474 *
475 * Returns the pointer to the userdata
476 */
477void *
478xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
479 const xmlChar *name) {
480 return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
481}
482
483/**
Daniel Veillard7a02cfe2003-09-25 12:18:34 +0000484 * xmlHashQLookup2:
Daniel Veillarde57ec792003-09-10 10:50:59 +0000485 * @table: the hash table
486 * @prefix: the prefix of the userdata
487 * @name: the name of the userdata
Daniel Veillard092643b2003-09-25 14:29:29 +0000488 * @prefix2: the second prefix of the userdata
Daniel Veillarde57ec792003-09-10 10:50:59 +0000489 * @name2: a second name of the userdata
490 *
491 * Find the userdata specified by the QNames tuple
492 *
493 * Returns the pointer to the userdata
494 */
495void *
496xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix,
497 const xmlChar *name, const xmlChar *prefix2,
498 const xmlChar *name2) {
499 return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
500}
501
502/**
Owen Taylor3473f882001-02-23 17:55:21 +0000503 * xmlHashAddEntry3:
504 * @table: the hash table
505 * @name: the name of the userdata
506 * @name2: a second name of the userdata
507 * @name3: a third name of the userdata
508 * @userdata: a pointer to the userdata
509 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000510 * Add the @userdata to the hash @table. This can later be retrieved
511 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
Owen Taylor3473f882001-02-23 17:55:21 +0000512 * errors.
513 *
514 * Returns 0 the addition succeeded and -1 in case of error.
515 */
516int
517xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
518 const xmlChar *name2, const xmlChar *name3,
519 void *userdata) {
Daniel Veillarda10efa82001-04-18 13:09:01 +0000520 unsigned long key, len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000521 xmlHashEntryPtr entry;
522 xmlHashEntryPtr insert;
523
Daniel Veillard316a5c32005-01-23 22:56:39 +0000524 if ((table == NULL) || (name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +0000525 return(-1);
526
527 /*
Daniel Veillard316a5c32005-01-23 22:56:39 +0000528 * If using a dict internalize if needed
529 */
530 if (table->dict) {
531 if (!xmlDictOwns(table->dict, name)) {
532 name = xmlDictLookup(table->dict, name, -1);
533 if (name == NULL)
534 return(-1);
535 }
536 if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
537 name2 = xmlDictLookup(table->dict, name2, -1);
538 if (name2 == NULL)
539 return(-1);
540 }
541 if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
542 name3 = xmlDictLookup(table->dict, name3, -1);
543 if (name3 == NULL)
544 return(-1);
545 }
546 }
547
548 /*
Owen Taylor3473f882001-02-23 17:55:21 +0000549 * Check for duplicate and insertion location.
550 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000551 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000552 if (table->table[key].valid == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000553 insert = NULL;
554 } else {
Daniel Veillard316a5c32005-01-23 22:56:39 +0000555 if (table->dict) {
556 for (insert = &(table->table[key]); insert->next != NULL;
557 insert = insert->next) {
558 if ((insert->name == name) &&
559 (insert->name2 == name2) &&
560 (insert->name3 == name3))
561 return(-1);
562 len++;
563 }
564 if ((insert->name == name) &&
565 (insert->name2 == name2) &&
566 (insert->name3 == name3))
567 return(-1);
568 } else {
569 for (insert = &(table->table[key]); insert->next != NULL;
570 insert = insert->next) {
571 if ((xmlStrEqual(insert->name, name)) &&
572 (xmlStrEqual(insert->name2, name2)) &&
573 (xmlStrEqual(insert->name3, name3)))
574 return(-1);
575 len++;
576 }
Owen Taylor3473f882001-02-23 17:55:21 +0000577 if ((xmlStrEqual(insert->name, name)) &&
578 (xmlStrEqual(insert->name2, name2)) &&
579 (xmlStrEqual(insert->name3, name3)))
580 return(-1);
581 }
Owen Taylor3473f882001-02-23 17:55:21 +0000582 }
583
Daniel Veillardfdc91562002-07-01 21:52:03 +0000584 if (insert == NULL) {
585 entry = &(table->table[key]);
586 } else {
587 entry = xmlMalloc(sizeof(xmlHashEntry));
588 if (entry == NULL)
589 return(-1);
590 }
591
Daniel Veillard316a5c32005-01-23 22:56:39 +0000592 if (table->dict != NULL) {
593 entry->name = (xmlChar *) name;
594 entry->name2 = (xmlChar *) name2;
595 entry->name3 = (xmlChar *) name3;
596 } else {
597 entry->name = xmlStrdup(name);
598 entry->name2 = xmlStrdup(name2);
599 entry->name3 = xmlStrdup(name3);
600 }
Owen Taylor3473f882001-02-23 17:55:21 +0000601 entry->payload = userdata;
602 entry->next = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000603 entry->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000604
605
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800606 if (insert != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +0000607 insert->next = entry;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000608
Owen Taylor3473f882001-02-23 17:55:21 +0000609 table->nbElems++;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000610
611 if (len > MAX_HASH_LEN)
612 xmlHashGrow(table, MAX_HASH_LEN * table->size);
613
Owen Taylor3473f882001-02-23 17:55:21 +0000614 return(0);
615}
616
617/**
618 * xmlHashUpdateEntry3:
619 * @table: the hash table
620 * @name: the name of the userdata
621 * @name2: a second name of the userdata
622 * @name3: a third name of the userdata
623 * @userdata: a pointer to the userdata
624 * @f: the deallocator function for replaced item (if any)
625 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000626 * Add the @userdata to the hash @table. This can later be retrieved
627 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
Owen Taylor3473f882001-02-23 17:55:21 +0000628 * will be removed and freed with @f if found.
629 *
630 * Returns 0 the addition succeeded and -1 in case of error.
631 */
632int
633xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
634 const xmlChar *name2, const xmlChar *name3,
635 void *userdata, xmlHashDeallocator f) {
636 unsigned long key;
637 xmlHashEntryPtr entry;
638 xmlHashEntryPtr insert;
639
640 if ((table == NULL) || name == NULL)
641 return(-1);
642
643 /*
Daniel Veillard316a5c32005-01-23 22:56:39 +0000644 * If using a dict internalize if needed
645 */
646 if (table->dict) {
647 if (!xmlDictOwns(table->dict, name)) {
648 name = xmlDictLookup(table->dict, name, -1);
649 if (name == NULL)
650 return(-1);
651 }
652 if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
653 name2 = xmlDictLookup(table->dict, name2, -1);
654 if (name2 == NULL)
655 return(-1);
656 }
657 if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
658 name3 = xmlDictLookup(table->dict, name3, -1);
659 if (name3 == NULL)
660 return(-1);
661 }
662 }
663
664 /*
Owen Taylor3473f882001-02-23 17:55:21 +0000665 * Check for duplicate and insertion location.
666 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000667 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000668 if (table->table[key].valid == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000669 insert = NULL;
670 } else {
Daniel Veillard316a5c32005-01-23 22:56:39 +0000671 if (table ->dict) {
672 for (insert = &(table->table[key]); insert->next != NULL;
673 insert = insert->next) {
674 if ((insert->name == name) &&
675 (insert->name2 == name2) &&
676 (insert->name3 == name3)) {
677 if (f)
678 f(insert->payload, insert->name);
679 insert->payload = userdata;
680 return(0);
681 }
682 }
683 if ((insert->name == name) &&
684 (insert->name2 == name2) &&
685 (insert->name3 == name3)) {
686 if (f)
687 f(insert->payload, insert->name);
688 insert->payload = userdata;
689 return(0);
690 }
691 } else {
692 for (insert = &(table->table[key]); insert->next != NULL;
693 insert = insert->next) {
694 if ((xmlStrEqual(insert->name, name)) &&
695 (xmlStrEqual(insert->name2, name2)) &&
696 (xmlStrEqual(insert->name3, name3))) {
697 if (f)
698 f(insert->payload, insert->name);
699 insert->payload = userdata;
700 return(0);
701 }
702 }
Owen Taylor3473f882001-02-23 17:55:21 +0000703 if ((xmlStrEqual(insert->name, name)) &&
704 (xmlStrEqual(insert->name2, name2)) &&
705 (xmlStrEqual(insert->name3, name3))) {
706 if (f)
707 f(insert->payload, insert->name);
708 insert->payload = userdata;
709 return(0);
710 }
711 }
Owen Taylor3473f882001-02-23 17:55:21 +0000712 }
713
Daniel Veillardfdc91562002-07-01 21:52:03 +0000714 if (insert == NULL) {
715 entry = &(table->table[key]);
716 } else {
717 entry = xmlMalloc(sizeof(xmlHashEntry));
718 if (entry == NULL)
719 return(-1);
720 }
721
Daniel Veillard316a5c32005-01-23 22:56:39 +0000722 if (table->dict != NULL) {
723 entry->name = (xmlChar *) name;
724 entry->name2 = (xmlChar *) name2;
725 entry->name3 = (xmlChar *) name3;
726 } else {
727 entry->name = xmlStrdup(name);
728 entry->name2 = xmlStrdup(name2);
729 entry->name3 = xmlStrdup(name3);
730 }
Owen Taylor3473f882001-02-23 17:55:21 +0000731 entry->payload = userdata;
732 entry->next = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000733 entry->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000734 table->nbElems++;
735
736
Daniel Veillardfdc91562002-07-01 21:52:03 +0000737 if (insert != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000738 insert->next = entry;
739 }
740 return(0);
741}
742
743/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000744 * xmlHashLookup3:
Owen Taylor3473f882001-02-23 17:55:21 +0000745 * @table: the hash table
746 * @name: the name of the userdata
747 * @name2: a second name of the userdata
748 * @name3: a third name of the userdata
749 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000750 * Find the userdata specified by the (@name, @name2, @name3) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000751 *
752 * Returns the a pointer to the userdata
753 */
754void *
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800755xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +0000756 const xmlChar *name2, const xmlChar *name3) {
757 unsigned long key;
758 xmlHashEntryPtr entry;
759
760 if (table == NULL)
761 return(NULL);
762 if (name == NULL)
763 return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000764 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000765 if (table->table[key].valid == 0)
766 return(NULL);
Daniel Veillard316a5c32005-01-23 22:56:39 +0000767 if (table->dict) {
768 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
769 if ((entry->name == name) &&
770 (entry->name2 == name2) &&
771 (entry->name3 == name3))
772 return(entry->payload);
773 }
774 }
Daniel Veillardfdc91562002-07-01 21:52:03 +0000775 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Owen Taylor3473f882001-02-23 17:55:21 +0000776 if ((xmlStrEqual(entry->name, name)) &&
777 (xmlStrEqual(entry->name2, name2)) &&
778 (xmlStrEqual(entry->name3, name3)))
779 return(entry->payload);
780 }
781 return(NULL);
782}
783
Daniel Veillarde57ec792003-09-10 10:50:59 +0000784/**
785 * xmlHashQLookup3:
786 * @table: the hash table
787 * @prefix: the prefix of the userdata
788 * @name: the name of the userdata
789 * @prefix2: the second prefix of the userdata
790 * @name2: a second name of the userdata
791 * @prefix3: the third prefix of the userdata
792 * @name3: a third name of the userdata
793 *
794 * Find the userdata specified by the (@name, @name2, @name3) tuple.
795 *
796 * Returns the a pointer to the userdata
797 */
798void *
799xmlHashQLookup3(xmlHashTablePtr table,
800 const xmlChar *prefix, const xmlChar *name,
801 const xmlChar *prefix2, const xmlChar *name2,
802 const xmlChar *prefix3, const xmlChar *name3) {
803 unsigned long key;
804 xmlHashEntryPtr entry;
805
806 if (table == NULL)
807 return(NULL);
808 if (name == NULL)
809 return(NULL);
810 key = xmlHashComputeQKey(table, prefix, name, prefix2,
811 name2, prefix3, name3);
812 if (table->table[key].valid == 0)
813 return(NULL);
814 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
815 if ((xmlStrQEqual(prefix, name, entry->name)) &&
816 (xmlStrQEqual(prefix2, name2, entry->name2)) &&
817 (xmlStrQEqual(prefix3, name3, entry->name3)))
818 return(entry->payload);
819 }
820 return(NULL);
821}
822
Daniel Veillard153120c2002-06-18 07:58:35 +0000823typedef struct {
824 xmlHashScanner hashscanner;
825 void *data;
826} stubData;
827
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800828static void
829stubHashScannerFull (void *payload, void *data, const xmlChar *name,
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000830 const xmlChar *name2 ATTRIBUTE_UNUSED,
831 const xmlChar *name3 ATTRIBUTE_UNUSED) {
Daniel Veillard153120c2002-06-18 07:58:35 +0000832 stubData *stubdata = (stubData *) data;
833 stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800834}
835
Daniel Veillard01c13b52002-12-10 15:19:08 +0000836/**
837 * xmlHashScan:
838 * @table: the hash table
839 * @f: the scanner function for items in the hash
840 * @data: extra data passed to f
841 *
842 * Scan the hash @table and applied @f to each value.
843 */
Owen Taylor3473f882001-02-23 17:55:21 +0000844void
845xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
Daniel Veillard153120c2002-06-18 07:58:35 +0000846 stubData stubdata;
847 stubdata.data = data;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800848 stubdata.hashscanner = f;
Daniel Veillard153120c2002-06-18 07:58:35 +0000849 xmlHashScanFull (table, stubHashScannerFull, &stubdata);
Thomas Broyere8126242001-07-22 03:54:15 +0000850}
851
852/**
853 * xmlHashScanFull:
854 * @table: the hash table
855 * @f: the scanner function for items in the hash
856 * @data: extra data passed to f
857 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000858 * Scan the hash @table and applied @f to each value.
Thomas Broyere8126242001-07-22 03:54:15 +0000859 */
860void
861xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
Daniel Veillardac4118d2008-01-11 05:27:32 +0000862 int i, nb;
Owen Taylor3473f882001-02-23 17:55:21 +0000863 xmlHashEntryPtr iter;
864 xmlHashEntryPtr next;
865
866 if (table == NULL)
867 return;
868 if (f == NULL)
869 return;
870
871 if (table->table) {
872 for(i = 0; i < table->size; i++) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800873 if (table->table[i].valid == 0)
Daniel Veillardfdc91562002-07-01 21:52:03 +0000874 continue;
875 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000876 while (iter) {
877 next = iter->next;
Daniel Veillardac4118d2008-01-11 05:27:32 +0000878 nb = table->nbElems;
Daniel Veillarde991fe92003-10-29 11:18:37 +0000879 if ((f != NULL) && (iter->payload != NULL))
Thomas Broyere8126242001-07-22 03:54:15 +0000880 f(iter->payload, data, iter->name,
881 iter->name2, iter->name3);
Daniel Veillardac4118d2008-01-11 05:27:32 +0000882 if (nb != table->nbElems) {
883 /* table was modified by the callback, be careful */
884 if (iter == &(table->table[i])) {
885 if (table->table[i].valid == 0)
886 iter = NULL;
887 if (table->table[i].next != next)
888 iter = &(table->table[i]);
889 } else
890 iter = next;
891 } else
892 iter = next;
Owen Taylor3473f882001-02-23 17:55:21 +0000893 }
894 }
895 }
896}
897
898/**
899 * xmlHashScan3:
900 * @table: the hash table
901 * @name: the name of the userdata or NULL
902 * @name2: a second name of the userdata or NULL
903 * @name3: a third name of the userdata or NULL
904 * @f: the scanner function for items in the hash
905 * @data: extra data passed to f
906 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000907 * Scan the hash @table and applied @f to each value matching
908 * (@name, @name2, @name3) tuple. If one of the names is null,
Owen Taylor3473f882001-02-23 17:55:21 +0000909 * the comparison is considered to match.
910 */
911void
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800912xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +0000913 const xmlChar *name2, const xmlChar *name3,
914 xmlHashScanner f, void *data) {
Thomas Broyere8126242001-07-22 03:54:15 +0000915 xmlHashScanFull3 (table, name, name2, name3,
916 (xmlHashScannerFull) f, data);
917}
918
919/**
920 * xmlHashScanFull3:
921 * @table: the hash table
922 * @name: the name of the userdata or NULL
923 * @name2: a second name of the userdata or NULL
924 * @name3: a third name of the userdata or NULL
925 * @f: the scanner function for items in the hash
926 * @data: extra data passed to f
927 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000928 * Scan the hash @table and applied @f to each value matching
929 * (@name, @name2, @name3) tuple. If one of the names is null,
Thomas Broyere8126242001-07-22 03:54:15 +0000930 * the comparison is considered to match.
931 */
932void
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800933xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
Thomas Broyere8126242001-07-22 03:54:15 +0000934 const xmlChar *name2, const xmlChar *name3,
935 xmlHashScannerFull f, void *data) {
Owen Taylor3473f882001-02-23 17:55:21 +0000936 int i;
937 xmlHashEntryPtr iter;
938 xmlHashEntryPtr next;
939
940 if (table == NULL)
941 return;
942 if (f == NULL)
943 return;
944
945 if (table->table) {
946 for(i = 0; i < table->size; i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000947 if (table->table[i].valid == 0)
948 continue;
949 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000950 while (iter) {
951 next = iter->next;
952 if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
953 ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
Daniel Veillarde991fe92003-10-29 11:18:37 +0000954 ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
955 (iter->payload != NULL)) {
Thomas Broyere8126242001-07-22 03:54:15 +0000956 f(iter->payload, data, iter->name,
957 iter->name2, iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000958 }
959 iter = next;
960 }
961 }
962 }
963}
964
965/**
966 * xmlHashCopy:
967 * @table: the hash table
968 * @f: the copier function for items in the hash
969 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000970 * Scan the hash @table and applied @f to each value.
Owen Taylor3473f882001-02-23 17:55:21 +0000971 *
972 * Returns the new table or NULL in case of error.
973 */
974xmlHashTablePtr
975xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
976 int i;
977 xmlHashEntryPtr iter;
978 xmlHashEntryPtr next;
979 xmlHashTablePtr ret;
980
981 if (table == NULL)
982 return(NULL);
983 if (f == NULL)
984 return(NULL);
985
986 ret = xmlHashCreate(table->size);
Gaurav Gupta1811add2014-07-14 17:50:27 +0800987 if (ret == NULL)
988 return(NULL);
989
Owen Taylor3473f882001-02-23 17:55:21 +0000990 if (table->table) {
991 for(i = 0; i < table->size; i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000992 if (table->table[i].valid == 0)
993 continue;
994 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000995 while (iter) {
996 next = iter->next;
997 xmlHashAddEntry3(ret, iter->name, iter->name2,
998 iter->name3, f(iter->payload, iter->name));
999 iter = next;
1000 }
1001 }
1002 }
1003 ret->nbElems = table->nbElems;
1004 return(ret);
1005}
1006
1007/**
1008 * xmlHashSize:
1009 * @table: the hash table
1010 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001011 * Query the number of elements installed in the hash @table.
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001012 *
Owen Taylor3473f882001-02-23 17:55:21 +00001013 * Returns the number of elements in the hash table or
1014 * -1 in case of error
1015 */
1016int
1017xmlHashSize(xmlHashTablePtr table) {
1018 if (table == NULL)
1019 return(-1);
1020 return(table->nbElems);
1021}
1022
1023/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00001024 * xmlHashRemoveEntry:
Owen Taylor3473f882001-02-23 17:55:21 +00001025 * @table: the hash table
1026 * @name: the name of the userdata
1027 * @f: the deallocator function for removed item (if any)
1028 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001029 * Find the userdata specified by the @name and remove
1030 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +00001031 * and freed with @f.
1032 *
1033 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1034 */
1035int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001036 xmlHashDeallocator f) {
1037 return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +00001038}
1039
1040/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00001041 * xmlHashRemoveEntry2:
Owen Taylor3473f882001-02-23 17:55:21 +00001042 * @table: the hash table
1043 * @name: the name of the userdata
1044 * @name2: a second name of the userdata
1045 * @f: the deallocator function for removed item (if any)
1046 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001047 * Find the userdata specified by the (@name, @name2) tuple and remove
1048 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +00001049 * and freed with @f.
1050 *
1051 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1052 */
Daniel Veillard01c13b52002-12-10 15:19:08 +00001053int
1054xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001055 const xmlChar *name2, xmlHashDeallocator f) {
1056 return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +00001057}
1058
1059/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001060 * xmlHashRemoveEntry3:
Owen Taylor3473f882001-02-23 17:55:21 +00001061 * @table: the hash table
1062 * @name: the name of the userdata
1063 * @name2: a second name of the userdata
1064 * @name3: a third name of the userdata
1065 * @f: the deallocator function for removed item (if any)
1066 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001067 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
1068 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +00001069 * and freed with @f.
1070 *
1071 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1072 */
Daniel Veillard01c13b52002-12-10 15:19:08 +00001073int
1074xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001075 const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1076 unsigned long key;
1077 xmlHashEntryPtr entry;
1078 xmlHashEntryPtr prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001079
Daniel Veillarda10efa82001-04-18 13:09:01 +00001080 if (table == NULL || name == NULL)
1081 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001082
Daniel Veillarda10efa82001-04-18 13:09:01 +00001083 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001084 if (table->table[key].valid == 0) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00001085 return(-1);
1086 } else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00001087 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00001088 if (xmlStrEqual(entry->name, name) &&
1089 xmlStrEqual(entry->name2, name2) &&
1090 xmlStrEqual(entry->name3, name3)) {
Daniel Veillarde991fe92003-10-29 11:18:37 +00001091 if ((f != NULL) && (entry->payload != NULL))
Daniel Veillarda10efa82001-04-18 13:09:01 +00001092 f(entry->payload, entry->name);
1093 entry->payload = NULL;
Daniel Veillard316a5c32005-01-23 22:56:39 +00001094 if (table->dict == NULL) {
1095 if(entry->name)
1096 xmlFree(entry->name);
1097 if(entry->name2)
1098 xmlFree(entry->name2);
1099 if(entry->name3)
1100 xmlFree(entry->name3);
1101 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001102 if(prev) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00001103 prev->next = entry->next;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001104 xmlFree(entry);
1105 } else {
1106 if (entry->next == NULL) {
1107 entry->valid = 0;
1108 } else {
1109 entry = entry->next;
1110 memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1111 xmlFree(entry);
1112 }
1113 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001114 table->nbElems--;
1115 return(0);
1116 }
1117 prev = entry;
1118 }
1119 return(-1);
1120 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001121}
1122
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001123#define bottom_hash
1124#include "elfgcchack.h"