blob: 005401b72b0e78c3b2fa27f10056a7a6832386f0 [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
Haibo Huangcfd91dc2020-07-30 23:01:33 -070014 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
Owen Taylor3473f882001-02-23 17:55:21 +000015 * 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 */
Haibo Huangcfd91dc2020-07-30 23:01:33 -070036#if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME) && \
37 !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
Daniel Veillard8973d582012-02-04 19:07:44 +080038#define HASH_RANDOMIZATION
39#endif
40
Daniel Veillarde57ec792003-09-10 10:50:59 +000041#include <libxml/parser.h>
Owen Taylor3473f882001-02-23 17:55:21 +000042#include <libxml/hash.h>
43#include <libxml/xmlmemory.h>
Daniel Veillarda10efa82001-04-18 13:09:01 +000044#include <libxml/xmlerror.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000045#include <libxml/globals.h>
Daniel Veillarda10efa82001-04-18 13:09:01 +000046
47#define MAX_HASH_LEN 8
48
49/* #define DEBUG_GROW */
Owen Taylor3473f882001-02-23 17:55:21 +000050
51/*
52 * A single entry in the hash table
53 */
54typedef struct _xmlHashEntry xmlHashEntry;
55typedef xmlHashEntry *xmlHashEntryPtr;
56struct _xmlHashEntry {
57 struct _xmlHashEntry *next;
58 xmlChar *name;
59 xmlChar *name2;
60 xmlChar *name3;
61 void *payload;
Daniel Veillardfdc91562002-07-01 21:52:03 +000062 int valid;
Owen Taylor3473f882001-02-23 17:55:21 +000063};
64
65/*
66 * The entire hash table
67 */
68struct _xmlHashTable {
Daniel Veillardfdc91562002-07-01 21:52:03 +000069 struct _xmlHashEntry *table;
Owen Taylor3473f882001-02-23 17:55:21 +000070 int size;
71 int nbElems;
Daniel Veillard316a5c32005-01-23 22:56:39 +000072 xmlDictPtr dict;
Daniel Veillard8973d582012-02-04 19:07:44 +080073#ifdef HASH_RANDOMIZATION
74 int random_seed;
75#endif
Owen Taylor3473f882001-02-23 17:55:21 +000076};
77
78/*
79 * xmlHashComputeKey:
80 * Calculate the hash key
81 */
Haibo Huangcfd91dc2020-07-30 23:01:33 -070082#ifdef __clang__
83ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
84#endif
Owen Taylor3473f882001-02-23 17:55:21 +000085static unsigned long
Daniel Veillarda10efa82001-04-18 13:09:01 +000086xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
87 const xmlChar *name2, const xmlChar *name3) {
Owen Taylor3473f882001-02-23 17:55:21 +000088 unsigned long value = 0L;
Elliott Hughesecdab2a2022-02-23 14:33:50 -080089 unsigned long ch;
Daniel Veillardf8e3db02012-09-11 13:26:36 +080090
Daniel Veillard8973d582012-02-04 19:07:44 +080091#ifdef HASH_RANDOMIZATION
92 value = table->random_seed;
93#endif
Daniel Veillarda10efa82001-04-18 13:09:01 +000094 if (name != NULL) {
95 value += 30 * (*name);
96 while ((ch = *name++) != 0) {
Elliott Hughesecdab2a2022-02-23 14:33:50 -080097 value = value ^ ((value << 5) + (value >> 3) + ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +000098 }
99 }
Daniel Frankeb1237112013-04-12 18:53:53 +0800100 value = value ^ ((value << 5) + (value >> 3));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000101 if (name2 != NULL) {
102 while ((ch = *name2++) != 0) {
Elliott Hughesecdab2a2022-02-23 14:33:50 -0800103 value = value ^ ((value << 5) + (value >> 3) + ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000104 }
105 }
Daniel Frankeb1237112013-04-12 18:53:53 +0800106 value = value ^ ((value << 5) + (value >> 3));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000107 if (name3 != NULL) {
108 while ((ch = *name3++) != 0) {
Elliott Hughesecdab2a2022-02-23 14:33:50 -0800109 value = value ^ ((value << 5) + (value >> 3) + ch);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000110 }
Owen Taylor3473f882001-02-23 17:55:21 +0000111 }
112 return (value % table->size);
113}
114
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700115#ifdef __clang__
116ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
117#endif
Daniel Veillarde57ec792003-09-10 10:50:59 +0000118static unsigned long
119xmlHashComputeQKey(xmlHashTablePtr table,
Daniel Veillard8e36e6a2003-09-10 10:50:59 +0000120 const xmlChar *prefix, const xmlChar *name,
121 const xmlChar *prefix2, const xmlChar *name2,
122 const xmlChar *prefix3, const xmlChar *name3) {
Daniel Veillarde57ec792003-09-10 10:50:59 +0000123 unsigned long value = 0L;
Elliott Hughesecdab2a2022-02-23 14:33:50 -0800124 unsigned long ch;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800125
Daniel Veillard8973d582012-02-04 19:07:44 +0800126#ifdef HASH_RANDOMIZATION
127 value = table->random_seed;
128#endif
Daniel Veillarde57ec792003-09-10 10:50:59 +0000129 if (prefix != NULL)
130 value += 30 * (*prefix);
131 else
132 value += 30 * (*name);
133
134 if (prefix != NULL) {
135 while ((ch = *prefix++) != 0) {
Elliott Hughesecdab2a2022-02-23 14:33:50 -0800136 value = value ^ ((value << 5) + (value >> 3) + ch);
Daniel Veillarde57ec792003-09-10 10:50:59 +0000137 }
138 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
139 }
140 if (name != NULL) {
141 while ((ch = *name++) != 0) {
Elliott Hughesecdab2a2022-02-23 14:33:50 -0800142 value = value ^ ((value << 5) + (value >> 3) + ch);
Daniel Veillarde57ec792003-09-10 10:50:59 +0000143 }
144 }
Daniel Frankeb1237112013-04-12 18:53:53 +0800145 value = value ^ ((value << 5) + (value >> 3));
Daniel Veillarde57ec792003-09-10 10:50:59 +0000146 if (prefix2 != NULL) {
147 while ((ch = *prefix2++) != 0) {
Elliott Hughesecdab2a2022-02-23 14:33:50 -0800148 value = value ^ ((value << 5) + (value >> 3) + ch);
Daniel Veillarde57ec792003-09-10 10:50:59 +0000149 }
150 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
151 }
152 if (name2 != NULL) {
153 while ((ch = *name2++) != 0) {
Elliott Hughesecdab2a2022-02-23 14:33:50 -0800154 value = value ^ ((value << 5) + (value >> 3) + ch);
Daniel Veillarde57ec792003-09-10 10:50:59 +0000155 }
156 }
Daniel Frankeb1237112013-04-12 18:53:53 +0800157 value = value ^ ((value << 5) + (value >> 3));
Daniel Veillarde57ec792003-09-10 10:50:59 +0000158 if (prefix3 != NULL) {
159 while ((ch = *prefix3++) != 0) {
Elliott Hughesecdab2a2022-02-23 14:33:50 -0800160 value = value ^ ((value << 5) + (value >> 3) + ch);
Daniel Veillarde57ec792003-09-10 10:50:59 +0000161 }
162 value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
163 }
164 if (name3 != NULL) {
165 while ((ch = *name3++) != 0) {
Elliott Hughesecdab2a2022-02-23 14:33:50 -0800166 value = value ^ ((value << 5) + (value >> 3) + ch);
Daniel Veillarde57ec792003-09-10 10:50:59 +0000167 }
168 }
169 return (value % table->size);
170}
171
Owen Taylor3473f882001-02-23 17:55:21 +0000172/**
173 * xmlHashCreate:
174 * @size: the size of the hash table
175 *
176 * Create a new xmlHashTablePtr.
177 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200178 * Returns the newly created object, or NULL if an error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000179 */
180xmlHashTablePtr
181xmlHashCreate(int size) {
182 xmlHashTablePtr table;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800183
Owen Taylor3473f882001-02-23 17:55:21 +0000184 if (size <= 0)
185 size = 256;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800186
Owen Taylor3473f882001-02-23 17:55:21 +0000187 table = xmlMalloc(sizeof(xmlHashTable));
188 if (table) {
Daniel Veillard316a5c32005-01-23 22:56:39 +0000189 table->dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000190 table->size = size;
191 table->nbElems = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000192 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
Owen Taylor3473f882001-02-23 17:55:21 +0000193 if (table->table) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800194 memset(table->table, 0, size * sizeof(xmlHashEntry));
Daniel Veillard8973d582012-02-04 19:07:44 +0800195#ifdef HASH_RANDOMIZATION
Daniel Veillard379ebc12012-05-18 15:41:31 +0800196 table->random_seed = __xmlRandom();
Daniel Veillard8973d582012-02-04 19:07:44 +0800197#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800198 return(table);
Owen Taylor3473f882001-02-23 17:55:21 +0000199 }
200 xmlFree(table);
201 }
202 return(NULL);
203}
204
205/**
Daniel Veillard316a5c32005-01-23 22:56:39 +0000206 * xmlHashCreateDict:
207 * @size: the size of the hash table
208 * @dict: a dictionary to use for the hash
209 *
210 * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
211 *
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +0200212 * Returns the newly created object, or NULL if an error occurred.
Daniel Veillard316a5c32005-01-23 22:56:39 +0000213 */
214xmlHashTablePtr
215xmlHashCreateDict(int size, xmlDictPtr dict) {
216 xmlHashTablePtr table;
217
218 table = xmlHashCreate(size);
219 if (table != NULL) {
220 table->dict = dict;
221 xmlDictReference(dict);
222 }
223 return(table);
224}
225
226/**
Daniel Veillarda10efa82001-04-18 13:09:01 +0000227 * xmlHashGrow:
228 * @table: the hash table
229 * @size: the new size of the hash table
230 *
231 * resize the hash table
232 *
233 * Returns 0 in case of success, -1 in case of failure
234 */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000235static int
Daniel Veillarda10efa82001-04-18 13:09:01 +0000236xmlHashGrow(xmlHashTablePtr table, int size) {
237 unsigned long key;
238 int oldsize, i;
239 xmlHashEntryPtr iter, next;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000240 struct _xmlHashEntry *oldtable;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000241#ifdef DEBUG_GROW
242 unsigned long nbElem = 0;
243#endif
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800244
Daniel Veillarda10efa82001-04-18 13:09:01 +0000245 if (table == NULL)
246 return(-1);
247 if (size < 8)
248 return(-1);
249 if (size > 8 * 2048)
250 return(-1);
251
252 oldsize = table->size;
253 oldtable = table->table;
254 if (oldtable == NULL)
255 return(-1);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800256
Daniel Veillardfdc91562002-07-01 21:52:03 +0000257 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000258 if (table->table == NULL) {
259 table->table = oldtable;
260 return(-1);
261 }
Daniel Veillardfdc91562002-07-01 21:52:03 +0000262 memset(table->table, 0, size * sizeof(xmlHashEntry));
Daniel Veillarda10efa82001-04-18 13:09:01 +0000263 table->size = size;
264
Daniel Veillardfdc91562002-07-01 21:52:03 +0000265 /* If the two loops are merged, there would be situations where
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800266 a new entry needs to allocated and data copied into it from
Daniel Veillardfdc91562002-07-01 21:52:03 +0000267 the main table. So instead, we run through the array twice, first
268 copying all the elements in the main array (where we can't get
269 conflicts) and then the rest, so we only free (and don't allocate)
270 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000271 for (i = 0; i < oldsize; i++) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800272 if (oldtable[i].valid == 0)
Daniel Veillardfdc91562002-07-01 21:52:03 +0000273 continue;
274 key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
275 oldtable[i].name3);
276 memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
277 table->table[key].next = NULL;
278 }
279
280 for (i = 0; i < oldsize; i++) {
281 iter = oldtable[i].next;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000282 while (iter) {
283 next = iter->next;
284
285 /*
286 * put back the entry in the new table
287 */
288
289 key = xmlHashComputeKey(table, iter->name, iter->name2,
290 iter->name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000291 if (table->table[key].valid == 0) {
292 memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
293 table->table[key].next = NULL;
294 xmlFree(iter);
295 } else {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800296 iter->next = table->table[key].next;
297 table->table[key].next = iter;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000298 }
Daniel Veillarda10efa82001-04-18 13:09:01 +0000299
300#ifdef DEBUG_GROW
301 nbElem++;
302#endif
303
304 iter = next;
305 }
306 }
307
308 xmlFree(oldtable);
309
310#ifdef DEBUG_GROW
311 xmlGenericError(xmlGenericErrorContext,
312 "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
313#endif
314
315 return(0);
316}
317
318/**
Owen Taylor3473f882001-02-23 17:55:21 +0000319 * xmlHashFree:
320 * @table: the hash table
321 * @f: the deallocator function for items in the hash
322 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000323 * Free the hash @table and its contents. The userdata is
324 * deallocated with @f if provided.
Owen Taylor3473f882001-02-23 17:55:21 +0000325 */
326void
327xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
328 int i;
329 xmlHashEntryPtr iter;
330 xmlHashEntryPtr next;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000331 int inside_table = 0;
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000332 int nbElems;
Owen Taylor3473f882001-02-23 17:55:21 +0000333
334 if (table == NULL)
335 return;
336 if (table->table) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000337 nbElems = table->nbElems;
338 for(i = 0; (i < table->size) && (nbElems > 0); i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000339 iter = &(table->table[i]);
340 if (iter->valid == 0)
341 continue;
342 inside_table = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000343 while (iter) {
344 next = iter->next;
Daniel Veillarde991fe92003-10-29 11:18:37 +0000345 if ((f != NULL) && (iter->payload != NULL))
Daniel Veillarda10efa82001-04-18 13:09:01 +0000346 f(iter->payload, iter->name);
Daniel Veillard316a5c32005-01-23 22:56:39 +0000347 if (table->dict == NULL) {
348 if (iter->name)
349 xmlFree(iter->name);
350 if (iter->name2)
351 xmlFree(iter->name2);
352 if (iter->name3)
353 xmlFree(iter->name3);
354 }
Owen Taylor3473f882001-02-23 17:55:21 +0000355 iter->payload = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000356 if (!inside_table)
357 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000358 nbElems--;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000359 inside_table = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000360 iter = next;
361 }
Owen Taylor3473f882001-02-23 17:55:21 +0000362 }
363 xmlFree(table->table);
364 }
Daniel Veillard316a5c32005-01-23 22:56:39 +0000365 if (table->dict)
366 xmlDictFree(table->dict);
Owen Taylor3473f882001-02-23 17:55:21 +0000367 xmlFree(table);
368}
369
370/**
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100371 * xmlHashDefaultDeallocator:
372 * @entry: the hash table entry
373 * @name: the entry's name
374 *
375 * Free a hash table entry with xmlFree.
376 */
377void
378xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
379 xmlFree(entry);
380}
381
382/**
Owen Taylor3473f882001-02-23 17:55:21 +0000383 * xmlHashAddEntry:
384 * @table: the hash table
385 * @name: the name of the userdata
386 * @userdata: a pointer to the userdata
387 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000388 * Add the @userdata to the hash @table. This can later be retrieved
389 * by using the @name. Duplicate names generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000390 *
391 * Returns 0 the addition succeeded and -1 in case of error.
392 */
393int
394xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
395 return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
396}
397
398/**
399 * xmlHashAddEntry2:
400 * @table: the hash table
401 * @name: the name of the userdata
402 * @name2: a second name of the userdata
403 * @userdata: a pointer to the userdata
404 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000405 * Add the @userdata to the hash @table. This can later be retrieved
406 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
Owen Taylor3473f882001-02-23 17:55:21 +0000407 *
408 * Returns 0 the addition succeeded and -1 in case of error.
409 */
410int
411xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
412 const xmlChar *name2, void *userdata) {
413 return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
414}
415
416/**
417 * xmlHashUpdateEntry:
418 * @table: the hash table
419 * @name: the name of the userdata
420 * @userdata: a pointer to the userdata
421 * @f: the deallocator function for replaced item (if any)
422 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000423 * Add the @userdata to the hash @table. This can later be retrieved
424 * by using the @name. Existing entry for this @name will be removed
Owen Taylor3473f882001-02-23 17:55:21 +0000425 * and freed with @f if found.
426 *
427 * Returns 0 the addition succeeded and -1 in case of error.
428 */
429int
430xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
431 void *userdata, xmlHashDeallocator f) {
432 return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
433}
434
435/**
436 * xmlHashUpdateEntry2:
437 * @table: the hash table
438 * @name: the name of the userdata
439 * @name2: a second name of the userdata
440 * @userdata: a pointer to the userdata
441 * @f: the deallocator function for replaced item (if any)
442 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000443 * Add the @userdata to the hash @table. This can later be retrieved
444 * by using the (@name, @name2) tuple. Existing entry for this tuple will
Owen Taylor3473f882001-02-23 17:55:21 +0000445 * be removed and freed with @f if found.
446 *
447 * Returns 0 the addition succeeded and -1 in case of error.
448 */
449int
450xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
451 const xmlChar *name2, void *userdata,
452 xmlHashDeallocator f) {
453 return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
454}
455
456/**
457 * xmlHashLookup:
458 * @table: the hash table
459 * @name: the name of the userdata
460 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000461 * Find the userdata specified by the @name.
Owen Taylor3473f882001-02-23 17:55:21 +0000462 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000463 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000464 */
465void *
466xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
467 return(xmlHashLookup3(table, name, NULL, NULL));
468}
469
470/**
471 * xmlHashLookup2:
472 * @table: the hash table
473 * @name: the name of the userdata
474 * @name2: a second name of the userdata
475 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000476 * Find the userdata specified by the (@name, @name2) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000477 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000478 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000479 */
480void *
481xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
482 const xmlChar *name2) {
483 return(xmlHashLookup3(table, name, name2, NULL));
484}
485
486/**
Daniel Veillarde57ec792003-09-10 10:50:59 +0000487 * xmlHashQLookup:
488 * @table: the hash table
489 * @prefix: the prefix of the userdata
490 * @name: the name of the userdata
491 *
492 * Find the userdata specified by the QName @prefix:@name/@name.
493 *
494 * Returns the pointer to the userdata
495 */
496void *
497xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
498 const xmlChar *name) {
499 return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
500}
501
502/**
Daniel Veillard7a02cfe2003-09-25 12:18:34 +0000503 * xmlHashQLookup2:
Daniel Veillarde57ec792003-09-10 10:50:59 +0000504 * @table: the hash table
505 * @prefix: the prefix of the userdata
506 * @name: the name of the userdata
Daniel Veillard092643b2003-09-25 14:29:29 +0000507 * @prefix2: the second prefix of the userdata
Daniel Veillarde57ec792003-09-10 10:50:59 +0000508 * @name2: a second name of the userdata
509 *
510 * Find the userdata specified by the QNames tuple
511 *
512 * Returns the pointer to the userdata
513 */
514void *
515xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix,
516 const xmlChar *name, const xmlChar *prefix2,
517 const xmlChar *name2) {
518 return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
519}
520
521/**
Owen Taylor3473f882001-02-23 17:55:21 +0000522 * xmlHashAddEntry3:
523 * @table: the hash table
524 * @name: the name of the userdata
525 * @name2: a second name of the userdata
526 * @name3: a third name of the userdata
527 * @userdata: a pointer to the userdata
528 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000529 * Add the @userdata to the hash @table. This can later be retrieved
530 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
Owen Taylor3473f882001-02-23 17:55:21 +0000531 * errors.
532 *
533 * Returns 0 the addition succeeded and -1 in case of error.
534 */
535int
536xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
537 const xmlChar *name2, const xmlChar *name3,
538 void *userdata) {
Daniel Veillarda10efa82001-04-18 13:09:01 +0000539 unsigned long key, len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000540 xmlHashEntryPtr entry;
541 xmlHashEntryPtr insert;
542
Daniel Veillard316a5c32005-01-23 22:56:39 +0000543 if ((table == NULL) || (name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +0000544 return(-1);
545
546 /*
Daniel Veillard316a5c32005-01-23 22:56:39 +0000547 * If using a dict internalize if needed
548 */
549 if (table->dict) {
550 if (!xmlDictOwns(table->dict, name)) {
551 name = xmlDictLookup(table->dict, name, -1);
552 if (name == NULL)
553 return(-1);
554 }
555 if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
556 name2 = xmlDictLookup(table->dict, name2, -1);
557 if (name2 == NULL)
558 return(-1);
559 }
560 if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
561 name3 = xmlDictLookup(table->dict, name3, -1);
562 if (name3 == NULL)
563 return(-1);
564 }
565 }
566
567 /*
Owen Taylor3473f882001-02-23 17:55:21 +0000568 * Check for duplicate and insertion location.
569 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000570 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000571 if (table->table[key].valid == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000572 insert = NULL;
573 } else {
Daniel Veillard316a5c32005-01-23 22:56:39 +0000574 if (table->dict) {
575 for (insert = &(table->table[key]); insert->next != NULL;
576 insert = insert->next) {
577 if ((insert->name == name) &&
578 (insert->name2 == name2) &&
579 (insert->name3 == name3))
580 return(-1);
581 len++;
582 }
583 if ((insert->name == name) &&
584 (insert->name2 == name2) &&
585 (insert->name3 == name3))
586 return(-1);
587 } else {
588 for (insert = &(table->table[key]); insert->next != NULL;
589 insert = insert->next) {
590 if ((xmlStrEqual(insert->name, name)) &&
591 (xmlStrEqual(insert->name2, name2)) &&
592 (xmlStrEqual(insert->name3, name3)))
593 return(-1);
594 len++;
595 }
Owen Taylor3473f882001-02-23 17:55:21 +0000596 if ((xmlStrEqual(insert->name, name)) &&
597 (xmlStrEqual(insert->name2, name2)) &&
598 (xmlStrEqual(insert->name3, name3)))
599 return(-1);
600 }
Owen Taylor3473f882001-02-23 17:55:21 +0000601 }
602
Daniel Veillardfdc91562002-07-01 21:52:03 +0000603 if (insert == NULL) {
604 entry = &(table->table[key]);
605 } else {
606 entry = xmlMalloc(sizeof(xmlHashEntry));
607 if (entry == NULL)
608 return(-1);
609 }
610
Daniel Veillard316a5c32005-01-23 22:56:39 +0000611 if (table->dict != NULL) {
612 entry->name = (xmlChar *) name;
613 entry->name2 = (xmlChar *) name2;
614 entry->name3 = (xmlChar *) name3;
615 } else {
616 entry->name = xmlStrdup(name);
617 entry->name2 = xmlStrdup(name2);
618 entry->name3 = xmlStrdup(name3);
619 }
Owen Taylor3473f882001-02-23 17:55:21 +0000620 entry->payload = userdata;
621 entry->next = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000622 entry->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000623
624
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800625 if (insert != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +0000626 insert->next = entry;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000627
Owen Taylor3473f882001-02-23 17:55:21 +0000628 table->nbElems++;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000629
630 if (len > MAX_HASH_LEN)
631 xmlHashGrow(table, MAX_HASH_LEN * table->size);
632
Owen Taylor3473f882001-02-23 17:55:21 +0000633 return(0);
634}
635
636/**
637 * xmlHashUpdateEntry3:
638 * @table: the hash table
639 * @name: the name of the userdata
640 * @name2: a second name of the userdata
641 * @name3: a third name of the userdata
642 * @userdata: a pointer to the userdata
643 * @f: the deallocator function for replaced item (if any)
644 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000645 * Add the @userdata to the hash @table. This can later be retrieved
646 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
Owen Taylor3473f882001-02-23 17:55:21 +0000647 * will be removed and freed with @f if found.
648 *
649 * Returns 0 the addition succeeded and -1 in case of error.
650 */
651int
652xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
653 const xmlChar *name2, const xmlChar *name3,
654 void *userdata, xmlHashDeallocator f) {
655 unsigned long key;
656 xmlHashEntryPtr entry;
657 xmlHashEntryPtr insert;
658
659 if ((table == NULL) || name == NULL)
660 return(-1);
661
662 /*
Daniel Veillard316a5c32005-01-23 22:56:39 +0000663 * If using a dict internalize if needed
664 */
665 if (table->dict) {
666 if (!xmlDictOwns(table->dict, name)) {
667 name = xmlDictLookup(table->dict, name, -1);
668 if (name == NULL)
669 return(-1);
670 }
671 if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
672 name2 = xmlDictLookup(table->dict, name2, -1);
673 if (name2 == NULL)
674 return(-1);
675 }
676 if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
677 name3 = xmlDictLookup(table->dict, name3, -1);
678 if (name3 == NULL)
679 return(-1);
680 }
681 }
682
683 /*
Owen Taylor3473f882001-02-23 17:55:21 +0000684 * Check for duplicate and insertion location.
685 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000686 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000687 if (table->table[key].valid == 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000688 insert = NULL;
689 } else {
Daniel Veillard316a5c32005-01-23 22:56:39 +0000690 if (table ->dict) {
691 for (insert = &(table->table[key]); insert->next != NULL;
692 insert = insert->next) {
693 if ((insert->name == name) &&
694 (insert->name2 == name2) &&
695 (insert->name3 == name3)) {
696 if (f)
697 f(insert->payload, insert->name);
698 insert->payload = userdata;
699 return(0);
700 }
701 }
702 if ((insert->name == name) &&
703 (insert->name2 == name2) &&
704 (insert->name3 == name3)) {
705 if (f)
706 f(insert->payload, insert->name);
707 insert->payload = userdata;
708 return(0);
709 }
710 } else {
711 for (insert = &(table->table[key]); insert->next != NULL;
712 insert = insert->next) {
713 if ((xmlStrEqual(insert->name, name)) &&
714 (xmlStrEqual(insert->name2, name2)) &&
715 (xmlStrEqual(insert->name3, name3))) {
716 if (f)
717 f(insert->payload, insert->name);
718 insert->payload = userdata;
719 return(0);
720 }
721 }
Owen Taylor3473f882001-02-23 17:55:21 +0000722 if ((xmlStrEqual(insert->name, name)) &&
723 (xmlStrEqual(insert->name2, name2)) &&
724 (xmlStrEqual(insert->name3, name3))) {
725 if (f)
726 f(insert->payload, insert->name);
727 insert->payload = userdata;
728 return(0);
729 }
730 }
Owen Taylor3473f882001-02-23 17:55:21 +0000731 }
732
Daniel Veillardfdc91562002-07-01 21:52:03 +0000733 if (insert == NULL) {
734 entry = &(table->table[key]);
735 } else {
736 entry = xmlMalloc(sizeof(xmlHashEntry));
737 if (entry == NULL)
738 return(-1);
739 }
740
Daniel Veillard316a5c32005-01-23 22:56:39 +0000741 if (table->dict != NULL) {
742 entry->name = (xmlChar *) name;
743 entry->name2 = (xmlChar *) name2;
744 entry->name3 = (xmlChar *) name3;
745 } else {
746 entry->name = xmlStrdup(name);
747 entry->name2 = xmlStrdup(name2);
748 entry->name3 = xmlStrdup(name3);
749 }
Owen Taylor3473f882001-02-23 17:55:21 +0000750 entry->payload = userdata;
751 entry->next = NULL;
Daniel Veillardfdc91562002-07-01 21:52:03 +0000752 entry->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000753 table->nbElems++;
754
755
Daniel Veillardfdc91562002-07-01 21:52:03 +0000756 if (insert != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000757 insert->next = entry;
758 }
759 return(0);
760}
761
762/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000763 * xmlHashLookup3:
Owen Taylor3473f882001-02-23 17:55:21 +0000764 * @table: the hash table
765 * @name: the name of the userdata
766 * @name2: a second name of the userdata
767 * @name3: a third name of the userdata
768 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000769 * Find the userdata specified by the (@name, @name2, @name3) tuple.
Owen Taylor3473f882001-02-23 17:55:21 +0000770 *
771 * Returns the a pointer to the userdata
772 */
773void *
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800774xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +0000775 const xmlChar *name2, const xmlChar *name3) {
776 unsigned long key;
777 xmlHashEntryPtr entry;
778
779 if (table == NULL)
780 return(NULL);
781 if (name == NULL)
782 return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000783 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000784 if (table->table[key].valid == 0)
785 return(NULL);
Daniel Veillard316a5c32005-01-23 22:56:39 +0000786 if (table->dict) {
787 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
788 if ((entry->name == name) &&
789 (entry->name2 == name2) &&
790 (entry->name3 == name3))
791 return(entry->payload);
792 }
793 }
Daniel Veillardfdc91562002-07-01 21:52:03 +0000794 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Owen Taylor3473f882001-02-23 17:55:21 +0000795 if ((xmlStrEqual(entry->name, name)) &&
796 (xmlStrEqual(entry->name2, name2)) &&
797 (xmlStrEqual(entry->name3, name3)))
798 return(entry->payload);
799 }
800 return(NULL);
801}
802
Daniel Veillarde57ec792003-09-10 10:50:59 +0000803/**
804 * xmlHashQLookup3:
805 * @table: the hash table
806 * @prefix: the prefix of the userdata
807 * @name: the name of the userdata
808 * @prefix2: the second prefix of the userdata
809 * @name2: a second name of the userdata
810 * @prefix3: the third prefix of the userdata
811 * @name3: a third name of the userdata
812 *
813 * Find the userdata specified by the (@name, @name2, @name3) tuple.
814 *
815 * Returns the a pointer to the userdata
816 */
817void *
818xmlHashQLookup3(xmlHashTablePtr table,
819 const xmlChar *prefix, const xmlChar *name,
820 const xmlChar *prefix2, const xmlChar *name2,
821 const xmlChar *prefix3, const xmlChar *name3) {
822 unsigned long key;
823 xmlHashEntryPtr entry;
824
825 if (table == NULL)
826 return(NULL);
827 if (name == NULL)
828 return(NULL);
829 key = xmlHashComputeQKey(table, prefix, name, prefix2,
830 name2, prefix3, name3);
831 if (table->table[key].valid == 0)
832 return(NULL);
833 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
834 if ((xmlStrQEqual(prefix, name, entry->name)) &&
835 (xmlStrQEqual(prefix2, name2, entry->name2)) &&
836 (xmlStrQEqual(prefix3, name3, entry->name3)))
837 return(entry->payload);
838 }
839 return(NULL);
840}
841
Daniel Veillard153120c2002-06-18 07:58:35 +0000842typedef struct {
843 xmlHashScanner hashscanner;
844 void *data;
845} stubData;
846
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800847static void
848stubHashScannerFull (void *payload, void *data, const xmlChar *name,
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000849 const xmlChar *name2 ATTRIBUTE_UNUSED,
850 const xmlChar *name3 ATTRIBUTE_UNUSED) {
Daniel Veillard153120c2002-06-18 07:58:35 +0000851 stubData *stubdata = (stubData *) data;
852 stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800853}
854
Daniel Veillard01c13b52002-12-10 15:19:08 +0000855/**
856 * xmlHashScan:
857 * @table: the hash table
858 * @f: the scanner function for items in the hash
859 * @data: extra data passed to f
860 *
861 * Scan the hash @table and applied @f to each value.
862 */
Owen Taylor3473f882001-02-23 17:55:21 +0000863void
864xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
Daniel Veillard153120c2002-06-18 07:58:35 +0000865 stubData stubdata;
866 stubdata.data = data;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800867 stubdata.hashscanner = f;
Daniel Veillard153120c2002-06-18 07:58:35 +0000868 xmlHashScanFull (table, stubHashScannerFull, &stubdata);
Thomas Broyere8126242001-07-22 03:54:15 +0000869}
870
871/**
872 * xmlHashScanFull:
873 * @table: the hash table
874 * @f: the scanner function for items in the hash
875 * @data: extra data passed to f
876 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000877 * Scan the hash @table and applied @f to each value.
Thomas Broyere8126242001-07-22 03:54:15 +0000878 */
879void
880xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
Daniel Veillardac4118d2008-01-11 05:27:32 +0000881 int i, nb;
Owen Taylor3473f882001-02-23 17:55:21 +0000882 xmlHashEntryPtr iter;
883 xmlHashEntryPtr next;
884
885 if (table == NULL)
886 return;
887 if (f == NULL)
888 return;
889
890 if (table->table) {
891 for(i = 0; i < table->size; i++) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800892 if (table->table[i].valid == 0)
Daniel Veillardfdc91562002-07-01 21:52:03 +0000893 continue;
894 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000895 while (iter) {
896 next = iter->next;
Daniel Veillardac4118d2008-01-11 05:27:32 +0000897 nb = table->nbElems;
Daniel Veillarde991fe92003-10-29 11:18:37 +0000898 if ((f != NULL) && (iter->payload != NULL))
Thomas Broyere8126242001-07-22 03:54:15 +0000899 f(iter->payload, data, iter->name,
900 iter->name2, iter->name3);
Daniel Veillardac4118d2008-01-11 05:27:32 +0000901 if (nb != table->nbElems) {
902 /* table was modified by the callback, be careful */
903 if (iter == &(table->table[i])) {
904 if (table->table[i].valid == 0)
905 iter = NULL;
906 if (table->table[i].next != next)
907 iter = &(table->table[i]);
908 } else
909 iter = next;
910 } else
911 iter = next;
Owen Taylor3473f882001-02-23 17:55:21 +0000912 }
913 }
914 }
915}
916
917/**
918 * xmlHashScan3:
919 * @table: the hash table
920 * @name: the name of the userdata or NULL
921 * @name2: a second name of the userdata or NULL
922 * @name3: a third name of the userdata or NULL
923 * @f: the scanner function for items in the hash
924 * @data: extra data passed to f
925 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000926 * Scan the hash @table and applied @f to each value matching
927 * (@name, @name2, @name3) tuple. If one of the names is null,
Owen Taylor3473f882001-02-23 17:55:21 +0000928 * the comparison is considered to match.
929 */
930void
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800931xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +0000932 const xmlChar *name2, const xmlChar *name3,
933 xmlHashScanner f, void *data) {
Nick Wellnhofere03f0a12017-11-09 16:42:47 +0100934 stubData stubdata;
935 stubdata.data = data;
936 stubdata.hashscanner = f;
937 xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
938 &stubdata);
Thomas Broyere8126242001-07-22 03:54:15 +0000939}
940
941/**
942 * xmlHashScanFull3:
943 * @table: the hash table
944 * @name: the name of the userdata or NULL
945 * @name2: a second name of the userdata or NULL
946 * @name3: a third name of the userdata or NULL
947 * @f: the scanner function for items in the hash
948 * @data: extra data passed to f
949 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000950 * Scan the hash @table and applied @f to each value matching
951 * (@name, @name2, @name3) tuple. If one of the names is null,
Thomas Broyere8126242001-07-22 03:54:15 +0000952 * the comparison is considered to match.
953 */
954void
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800955xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
Thomas Broyere8126242001-07-22 03:54:15 +0000956 const xmlChar *name2, const xmlChar *name3,
957 xmlHashScannerFull f, void *data) {
Owen Taylor3473f882001-02-23 17:55:21 +0000958 int i;
959 xmlHashEntryPtr iter;
960 xmlHashEntryPtr next;
961
962 if (table == NULL)
963 return;
964 if (f == NULL)
965 return;
966
967 if (table->table) {
968 for(i = 0; i < table->size; i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +0000969 if (table->table[i].valid == 0)
970 continue;
971 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +0000972 while (iter) {
973 next = iter->next;
974 if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
975 ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
Daniel Veillarde991fe92003-10-29 11:18:37 +0000976 ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
977 (iter->payload != NULL)) {
Thomas Broyere8126242001-07-22 03:54:15 +0000978 f(iter->payload, data, iter->name,
979 iter->name2, iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000980 }
981 iter = next;
982 }
983 }
984 }
985}
986
987/**
988 * xmlHashCopy:
989 * @table: the hash table
990 * @f: the copier function for items in the hash
991 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000992 * Scan the hash @table and applied @f to each value.
Owen Taylor3473f882001-02-23 17:55:21 +0000993 *
994 * Returns the new table or NULL in case of error.
995 */
996xmlHashTablePtr
997xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
998 int i;
999 xmlHashEntryPtr iter;
1000 xmlHashEntryPtr next;
1001 xmlHashTablePtr ret;
1002
1003 if (table == NULL)
1004 return(NULL);
1005 if (f == NULL)
1006 return(NULL);
1007
1008 ret = xmlHashCreate(table->size);
Gaurav Gupta1811add2014-07-14 17:50:27 +08001009 if (ret == NULL)
1010 return(NULL);
1011
Owen Taylor3473f882001-02-23 17:55:21 +00001012 if (table->table) {
1013 for(i = 0; i < table->size; i++) {
Daniel Veillardfdc91562002-07-01 21:52:03 +00001014 if (table->table[i].valid == 0)
1015 continue;
1016 iter = &(table->table[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001017 while (iter) {
1018 next = iter->next;
1019 xmlHashAddEntry3(ret, iter->name, iter->name2,
1020 iter->name3, f(iter->payload, iter->name));
1021 iter = next;
1022 }
1023 }
1024 }
1025 ret->nbElems = table->nbElems;
1026 return(ret);
1027}
1028
1029/**
1030 * xmlHashSize:
1031 * @table: the hash table
1032 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001033 * Query the number of elements installed in the hash @table.
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001034 *
Owen Taylor3473f882001-02-23 17:55:21 +00001035 * Returns the number of elements in the hash table or
1036 * -1 in case of error
1037 */
1038int
1039xmlHashSize(xmlHashTablePtr table) {
1040 if (table == NULL)
1041 return(-1);
1042 return(table->nbElems);
1043}
1044
1045/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00001046 * xmlHashRemoveEntry:
Owen Taylor3473f882001-02-23 17:55:21 +00001047 * @table: the hash table
1048 * @name: the name of the userdata
1049 * @f: the deallocator function for removed item (if any)
1050 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001051 * Find the userdata specified by the @name and remove
1052 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +00001053 * and freed with @f.
1054 *
1055 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1056 */
1057int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001058 xmlHashDeallocator f) {
1059 return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +00001060}
1061
1062/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00001063 * xmlHashRemoveEntry2:
Owen Taylor3473f882001-02-23 17:55:21 +00001064 * @table: the hash table
1065 * @name: the name of the userdata
1066 * @name2: a second name of the userdata
1067 * @f: the deallocator function for removed item (if any)
1068 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001069 * Find the userdata specified by the (@name, @name2) tuple and remove
1070 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +00001071 * and freed with @f.
1072 *
1073 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1074 */
Daniel Veillard01c13b52002-12-10 15:19:08 +00001075int
1076xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001077 const xmlChar *name2, xmlHashDeallocator f) {
1078 return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +00001079}
1080
1081/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00001082 * xmlHashRemoveEntry3:
Owen Taylor3473f882001-02-23 17:55:21 +00001083 * @table: the hash table
1084 * @name: the name of the userdata
1085 * @name2: a second name of the userdata
1086 * @name3: a third name of the userdata
1087 * @f: the deallocator function for removed item (if any)
1088 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001089 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
1090 * it from the hash @table. Existing userdata for this tuple will be removed
Owen Taylor3473f882001-02-23 17:55:21 +00001091 * and freed with @f.
1092 *
1093 * Returns 0 if the removal succeeded and -1 in case of error or not found.
1094 */
Daniel Veillard01c13b52002-12-10 15:19:08 +00001095int
1096xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001097 const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
1098 unsigned long key;
1099 xmlHashEntryPtr entry;
1100 xmlHashEntryPtr prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001101
Daniel Veillarda10efa82001-04-18 13:09:01 +00001102 if (table == NULL || name == NULL)
1103 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001104
Daniel Veillarda10efa82001-04-18 13:09:01 +00001105 key = xmlHashComputeKey(table, name, name2, name3);
Daniel Veillardfdc91562002-07-01 21:52:03 +00001106 if (table->table[key].valid == 0) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00001107 return(-1);
1108 } else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00001109 for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00001110 if (xmlStrEqual(entry->name, name) &&
1111 xmlStrEqual(entry->name2, name2) &&
1112 xmlStrEqual(entry->name3, name3)) {
Daniel Veillarde991fe92003-10-29 11:18:37 +00001113 if ((f != NULL) && (entry->payload != NULL))
Daniel Veillarda10efa82001-04-18 13:09:01 +00001114 f(entry->payload, entry->name);
1115 entry->payload = NULL;
Daniel Veillard316a5c32005-01-23 22:56:39 +00001116 if (table->dict == NULL) {
1117 if(entry->name)
1118 xmlFree(entry->name);
1119 if(entry->name2)
1120 xmlFree(entry->name2);
1121 if(entry->name3)
1122 xmlFree(entry->name3);
1123 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00001124 if(prev) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00001125 prev->next = entry->next;
Daniel Veillardfdc91562002-07-01 21:52:03 +00001126 xmlFree(entry);
1127 } else {
1128 if (entry->next == NULL) {
1129 entry->valid = 0;
1130 } else {
1131 entry = entry->next;
1132 memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
1133 xmlFree(entry);
1134 }
1135 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001136 table->nbElems--;
1137 return(0);
1138 }
1139 prev = entry;
1140 }
1141 return(-1);
1142 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001143}
1144