xref: /aosp_15_r20/external/libxml2/hash.c (revision 7c5688314b92172186c154356a6374bf7684c3ca)
1*7c568831SAndroid Build Coastguard Worker /*
2*7c568831SAndroid Build Coastguard Worker  * hash.c: hash tables
3*7c568831SAndroid Build Coastguard Worker  *
4*7c568831SAndroid Build Coastguard Worker  * Hash table with open addressing, linear probing and
5*7c568831SAndroid Build Coastguard Worker  * Robin Hood reordering.
6*7c568831SAndroid Build Coastguard Worker  *
7*7c568831SAndroid Build Coastguard Worker  * See Copyright for the status of this software.
8*7c568831SAndroid Build Coastguard Worker  */
9*7c568831SAndroid Build Coastguard Worker 
10*7c568831SAndroid Build Coastguard Worker #define IN_LIBXML
11*7c568831SAndroid Build Coastguard Worker #include "libxml.h"
12*7c568831SAndroid Build Coastguard Worker 
13*7c568831SAndroid Build Coastguard Worker #include <string.h>
14*7c568831SAndroid Build Coastguard Worker #include <limits.h>
15*7c568831SAndroid Build Coastguard Worker 
16*7c568831SAndroid Build Coastguard Worker #include <libxml/parser.h>
17*7c568831SAndroid Build Coastguard Worker #include <libxml/hash.h>
18*7c568831SAndroid Build Coastguard Worker #include <libxml/dict.h>
19*7c568831SAndroid Build Coastguard Worker #include <libxml/xmlmemory.h>
20*7c568831SAndroid Build Coastguard Worker #include <libxml/xmlstring.h>
21*7c568831SAndroid Build Coastguard Worker 
22*7c568831SAndroid Build Coastguard Worker #include "private/dict.h"
23*7c568831SAndroid Build Coastguard Worker 
24*7c568831SAndroid Build Coastguard Worker #ifndef SIZE_MAX
25*7c568831SAndroid Build Coastguard Worker   #define SIZE_MAX ((size_t) -1)
26*7c568831SAndroid Build Coastguard Worker #endif
27*7c568831SAndroid Build Coastguard Worker 
28*7c568831SAndroid Build Coastguard Worker #define MAX_FILL_NUM 7
29*7c568831SAndroid Build Coastguard Worker #define MAX_FILL_DENOM 8
30*7c568831SAndroid Build Coastguard Worker #define MIN_HASH_SIZE 8
31*7c568831SAndroid Build Coastguard Worker #define MAX_HASH_SIZE (1u << 31)
32*7c568831SAndroid Build Coastguard Worker 
33*7c568831SAndroid Build Coastguard Worker /*
34*7c568831SAndroid Build Coastguard Worker  * A single entry in the hash table
35*7c568831SAndroid Build Coastguard Worker  */
36*7c568831SAndroid Build Coastguard Worker typedef struct {
37*7c568831SAndroid Build Coastguard Worker     unsigned hashValue; /* 0 means unoccupied, occupied entries have the
38*7c568831SAndroid Build Coastguard Worker                          * MAX_HASH_SIZE bit set to 1 */
39*7c568831SAndroid Build Coastguard Worker     xmlChar *key;
40*7c568831SAndroid Build Coastguard Worker     xmlChar *key2; /* TODO: Don't allocate possibly empty keys */
41*7c568831SAndroid Build Coastguard Worker     xmlChar *key3;
42*7c568831SAndroid Build Coastguard Worker     void *payload;
43*7c568831SAndroid Build Coastguard Worker } xmlHashEntry;
44*7c568831SAndroid Build Coastguard Worker 
45*7c568831SAndroid Build Coastguard Worker /*
46*7c568831SAndroid Build Coastguard Worker  * The entire hash table
47*7c568831SAndroid Build Coastguard Worker  */
48*7c568831SAndroid Build Coastguard Worker struct _xmlHashTable {
49*7c568831SAndroid Build Coastguard Worker     xmlHashEntry *table;
50*7c568831SAndroid Build Coastguard Worker     unsigned size; /* power of two */
51*7c568831SAndroid Build Coastguard Worker     unsigned nbElems;
52*7c568831SAndroid Build Coastguard Worker     xmlDictPtr dict;
53*7c568831SAndroid Build Coastguard Worker     unsigned randomSeed;
54*7c568831SAndroid Build Coastguard Worker };
55*7c568831SAndroid Build Coastguard Worker 
56*7c568831SAndroid Build Coastguard Worker static int
57*7c568831SAndroid Build Coastguard Worker xmlHashGrow(xmlHashTablePtr hash, unsigned size);
58*7c568831SAndroid Build Coastguard Worker 
59*7c568831SAndroid Build Coastguard Worker ATTRIBUTE_NO_SANITIZE_INTEGER
60*7c568831SAndroid Build Coastguard Worker static unsigned
xmlHashValue(unsigned seed,const xmlChar * key,const xmlChar * key2,const xmlChar * key3,size_t * lengths)61*7c568831SAndroid Build Coastguard Worker xmlHashValue(unsigned seed, const xmlChar *key, const xmlChar *key2,
62*7c568831SAndroid Build Coastguard Worker              const xmlChar *key3, size_t *lengths) {
63*7c568831SAndroid Build Coastguard Worker     unsigned h1, h2;
64*7c568831SAndroid Build Coastguard Worker     size_t i;
65*7c568831SAndroid Build Coastguard Worker 
66*7c568831SAndroid Build Coastguard Worker     HASH_INIT(h1, h2, seed);
67*7c568831SAndroid Build Coastguard Worker 
68*7c568831SAndroid Build Coastguard Worker     for (i = 0; key[i] != 0; i++) {
69*7c568831SAndroid Build Coastguard Worker         HASH_UPDATE(h1, h2, key[i]);
70*7c568831SAndroid Build Coastguard Worker     }
71*7c568831SAndroid Build Coastguard Worker     if (lengths)
72*7c568831SAndroid Build Coastguard Worker         lengths[0] = i;
73*7c568831SAndroid Build Coastguard Worker 
74*7c568831SAndroid Build Coastguard Worker     HASH_UPDATE(h1, h2, 0);
75*7c568831SAndroid Build Coastguard Worker 
76*7c568831SAndroid Build Coastguard Worker     if (key2 != NULL) {
77*7c568831SAndroid Build Coastguard Worker         for (i = 0; key2[i] != 0; i++) {
78*7c568831SAndroid Build Coastguard Worker             HASH_UPDATE(h1, h2, key2[i]);
79*7c568831SAndroid Build Coastguard Worker         }
80*7c568831SAndroid Build Coastguard Worker         if (lengths)
81*7c568831SAndroid Build Coastguard Worker             lengths[1] = i;
82*7c568831SAndroid Build Coastguard Worker     }
83*7c568831SAndroid Build Coastguard Worker 
84*7c568831SAndroid Build Coastguard Worker     HASH_UPDATE(h1, h2, 0);
85*7c568831SAndroid Build Coastguard Worker 
86*7c568831SAndroid Build Coastguard Worker     if (key3 != NULL) {
87*7c568831SAndroid Build Coastguard Worker         for (i = 0; key3[i] != 0; i++) {
88*7c568831SAndroid Build Coastguard Worker             HASH_UPDATE(h1, h2, key3[i]);
89*7c568831SAndroid Build Coastguard Worker         }
90*7c568831SAndroid Build Coastguard Worker         if (lengths)
91*7c568831SAndroid Build Coastguard Worker             lengths[2] = i;
92*7c568831SAndroid Build Coastguard Worker     }
93*7c568831SAndroid Build Coastguard Worker 
94*7c568831SAndroid Build Coastguard Worker     HASH_FINISH(h1, h2);
95*7c568831SAndroid Build Coastguard Worker 
96*7c568831SAndroid Build Coastguard Worker     return(h2);
97*7c568831SAndroid Build Coastguard Worker }
98*7c568831SAndroid Build Coastguard Worker 
99*7c568831SAndroid Build Coastguard Worker ATTRIBUTE_NO_SANITIZE_INTEGER
100*7c568831SAndroid Build Coastguard Worker static unsigned
xmlHashQNameValue(unsigned seed,const xmlChar * prefix,const xmlChar * name,const xmlChar * prefix2,const xmlChar * name2,const xmlChar * prefix3,const xmlChar * name3)101*7c568831SAndroid Build Coastguard Worker xmlHashQNameValue(unsigned seed,
102*7c568831SAndroid Build Coastguard Worker                   const xmlChar *prefix, const xmlChar *name,
103*7c568831SAndroid Build Coastguard Worker                   const xmlChar *prefix2, const xmlChar *name2,
104*7c568831SAndroid Build Coastguard Worker                   const xmlChar *prefix3, const xmlChar *name3) {
105*7c568831SAndroid Build Coastguard Worker     unsigned h1, h2, ch;
106*7c568831SAndroid Build Coastguard Worker 
107*7c568831SAndroid Build Coastguard Worker     HASH_INIT(h1, h2, seed);
108*7c568831SAndroid Build Coastguard Worker 
109*7c568831SAndroid Build Coastguard Worker     if (prefix != NULL) {
110*7c568831SAndroid Build Coastguard Worker         while ((ch = *prefix++) != 0) {
111*7c568831SAndroid Build Coastguard Worker             HASH_UPDATE(h1, h2, ch);
112*7c568831SAndroid Build Coastguard Worker         }
113*7c568831SAndroid Build Coastguard Worker         HASH_UPDATE(h1, h2, ':');
114*7c568831SAndroid Build Coastguard Worker     }
115*7c568831SAndroid Build Coastguard Worker     if (name != NULL) {
116*7c568831SAndroid Build Coastguard Worker         while ((ch = *name++) != 0) {
117*7c568831SAndroid Build Coastguard Worker             HASH_UPDATE(h1, h2, ch);
118*7c568831SAndroid Build Coastguard Worker         }
119*7c568831SAndroid Build Coastguard Worker     }
120*7c568831SAndroid Build Coastguard Worker     HASH_UPDATE(h1, h2, 0);
121*7c568831SAndroid Build Coastguard Worker     if (prefix2 != NULL) {
122*7c568831SAndroid Build Coastguard Worker         while ((ch = *prefix2++) != 0) {
123*7c568831SAndroid Build Coastguard Worker             HASH_UPDATE(h1, h2, ch);
124*7c568831SAndroid Build Coastguard Worker         }
125*7c568831SAndroid Build Coastguard Worker         HASH_UPDATE(h1, h2, ':');
126*7c568831SAndroid Build Coastguard Worker     }
127*7c568831SAndroid Build Coastguard Worker     if (name2 != NULL) {
128*7c568831SAndroid Build Coastguard Worker         while ((ch = *name2++) != 0) {
129*7c568831SAndroid Build Coastguard Worker             HASH_UPDATE(h1, h2, ch);
130*7c568831SAndroid Build Coastguard Worker         }
131*7c568831SAndroid Build Coastguard Worker     }
132*7c568831SAndroid Build Coastguard Worker     HASH_UPDATE(h1, h2, 0);
133*7c568831SAndroid Build Coastguard Worker     if (prefix3 != NULL) {
134*7c568831SAndroid Build Coastguard Worker         while ((ch = *prefix3++) != 0) {
135*7c568831SAndroid Build Coastguard Worker             HASH_UPDATE(h1, h2, ch);
136*7c568831SAndroid Build Coastguard Worker         }
137*7c568831SAndroid Build Coastguard Worker         HASH_UPDATE(h1, h2, ':');
138*7c568831SAndroid Build Coastguard Worker     }
139*7c568831SAndroid Build Coastguard Worker     if (name3 != NULL) {
140*7c568831SAndroid Build Coastguard Worker         while ((ch = *name3++) != 0) {
141*7c568831SAndroid Build Coastguard Worker             HASH_UPDATE(h1, h2, ch);
142*7c568831SAndroid Build Coastguard Worker         }
143*7c568831SAndroid Build Coastguard Worker     }
144*7c568831SAndroid Build Coastguard Worker 
145*7c568831SAndroid Build Coastguard Worker     HASH_FINISH(h1, h2);
146*7c568831SAndroid Build Coastguard Worker 
147*7c568831SAndroid Build Coastguard Worker     return(h2);
148*7c568831SAndroid Build Coastguard Worker }
149*7c568831SAndroid Build Coastguard Worker 
150*7c568831SAndroid Build Coastguard Worker /**
151*7c568831SAndroid Build Coastguard Worker  * xmlHashCreate:
152*7c568831SAndroid Build Coastguard Worker  * @size: initial size of the hash table
153*7c568831SAndroid Build Coastguard Worker  *
154*7c568831SAndroid Build Coastguard Worker  * Create a new hash table. Set size to zero if the number of entries
155*7c568831SAndroid Build Coastguard Worker  * can't be estimated.
156*7c568831SAndroid Build Coastguard Worker  *
157*7c568831SAndroid Build Coastguard Worker  * Returns the newly created object, or NULL if a memory allocation failed.
158*7c568831SAndroid Build Coastguard Worker  */
159*7c568831SAndroid Build Coastguard Worker xmlHashTablePtr
xmlHashCreate(int size)160*7c568831SAndroid Build Coastguard Worker xmlHashCreate(int size) {
161*7c568831SAndroid Build Coastguard Worker     xmlHashTablePtr hash;
162*7c568831SAndroid Build Coastguard Worker 
163*7c568831SAndroid Build Coastguard Worker     xmlInitParser();
164*7c568831SAndroid Build Coastguard Worker 
165*7c568831SAndroid Build Coastguard Worker     hash = xmlMalloc(sizeof(*hash));
166*7c568831SAndroid Build Coastguard Worker     if (hash == NULL)
167*7c568831SAndroid Build Coastguard Worker         return(NULL);
168*7c568831SAndroid Build Coastguard Worker     hash->dict = NULL;
169*7c568831SAndroid Build Coastguard Worker     hash->size = 0;
170*7c568831SAndroid Build Coastguard Worker     hash->table = NULL;
171*7c568831SAndroid Build Coastguard Worker     hash->nbElems = 0;
172*7c568831SAndroid Build Coastguard Worker     hash->randomSeed = xmlRandom();
173*7c568831SAndroid Build Coastguard Worker #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
174*7c568831SAndroid Build Coastguard Worker     hash->randomSeed = 0;
175*7c568831SAndroid Build Coastguard Worker #endif
176*7c568831SAndroid Build Coastguard Worker 
177*7c568831SAndroid Build Coastguard Worker     /*
178*7c568831SAndroid Build Coastguard Worker      * Unless a larger size is passed, the backing table is created
179*7c568831SAndroid Build Coastguard Worker      * lazily with MIN_HASH_SIZE capacity. In practice, there are many
180*7c568831SAndroid Build Coastguard Worker      * hash tables which are never filled.
181*7c568831SAndroid Build Coastguard Worker      */
182*7c568831SAndroid Build Coastguard Worker     if (size > MIN_HASH_SIZE) {
183*7c568831SAndroid Build Coastguard Worker         unsigned newSize = MIN_HASH_SIZE * 2;
184*7c568831SAndroid Build Coastguard Worker 
185*7c568831SAndroid Build Coastguard Worker         while ((newSize < (unsigned) size) && (newSize < MAX_HASH_SIZE))
186*7c568831SAndroid Build Coastguard Worker             newSize *= 2;
187*7c568831SAndroid Build Coastguard Worker 
188*7c568831SAndroid Build Coastguard Worker         if (xmlHashGrow(hash, newSize) != 0) {
189*7c568831SAndroid Build Coastguard Worker             xmlFree(hash);
190*7c568831SAndroid Build Coastguard Worker             return(NULL);
191*7c568831SAndroid Build Coastguard Worker         }
192*7c568831SAndroid Build Coastguard Worker     }
193*7c568831SAndroid Build Coastguard Worker 
194*7c568831SAndroid Build Coastguard Worker     return(hash);
195*7c568831SAndroid Build Coastguard Worker }
196*7c568831SAndroid Build Coastguard Worker 
197*7c568831SAndroid Build Coastguard Worker /**
198*7c568831SAndroid Build Coastguard Worker  * xmlHashCreateDict:
199*7c568831SAndroid Build Coastguard Worker  * @size: the size of the hash table
200*7c568831SAndroid Build Coastguard Worker  * @dict: a dictionary to use for the hash
201*7c568831SAndroid Build Coastguard Worker  *
202*7c568831SAndroid Build Coastguard Worker  * Create a new hash table backed by a dictionary. This can reduce
203*7c568831SAndroid Build Coastguard Worker  * resource usage considerably if most keys passed to API functions
204*7c568831SAndroid Build Coastguard Worker  * originate from this dictionary.
205*7c568831SAndroid Build Coastguard Worker  *
206*7c568831SAndroid Build Coastguard Worker  * Returns the newly created object, or NULL if a memory allocation failed.
207*7c568831SAndroid Build Coastguard Worker  */
208*7c568831SAndroid Build Coastguard Worker xmlHashTablePtr
xmlHashCreateDict(int size,xmlDictPtr dict)209*7c568831SAndroid Build Coastguard Worker xmlHashCreateDict(int size, xmlDictPtr dict) {
210*7c568831SAndroid Build Coastguard Worker     xmlHashTablePtr hash;
211*7c568831SAndroid Build Coastguard Worker 
212*7c568831SAndroid Build Coastguard Worker     hash = xmlHashCreate(size);
213*7c568831SAndroid Build Coastguard Worker     if (hash != NULL) {
214*7c568831SAndroid Build Coastguard Worker         hash->dict = dict;
215*7c568831SAndroid Build Coastguard Worker         xmlDictReference(dict);
216*7c568831SAndroid Build Coastguard Worker     }
217*7c568831SAndroid Build Coastguard Worker     return(hash);
218*7c568831SAndroid Build Coastguard Worker }
219*7c568831SAndroid Build Coastguard Worker 
220*7c568831SAndroid Build Coastguard Worker /**
221*7c568831SAndroid Build Coastguard Worker  * xmlHashFree:
222*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
223*7c568831SAndroid Build Coastguard Worker  * @dealloc: deallocator function or NULL
224*7c568831SAndroid Build Coastguard Worker  *
225*7c568831SAndroid Build Coastguard Worker  * Free the hash and its contents. The payload is deallocated with
226*7c568831SAndroid Build Coastguard Worker  * @dealloc if provided.
227*7c568831SAndroid Build Coastguard Worker  */
228*7c568831SAndroid Build Coastguard Worker void
xmlHashFree(xmlHashTablePtr hash,xmlHashDeallocator dealloc)229*7c568831SAndroid Build Coastguard Worker xmlHashFree(xmlHashTablePtr hash, xmlHashDeallocator dealloc) {
230*7c568831SAndroid Build Coastguard Worker     if (hash == NULL)
231*7c568831SAndroid Build Coastguard Worker         return;
232*7c568831SAndroid Build Coastguard Worker 
233*7c568831SAndroid Build Coastguard Worker     if (hash->table) {
234*7c568831SAndroid Build Coastguard Worker         const xmlHashEntry *end = &hash->table[hash->size];
235*7c568831SAndroid Build Coastguard Worker         const xmlHashEntry *entry;
236*7c568831SAndroid Build Coastguard Worker 
237*7c568831SAndroid Build Coastguard Worker         for (entry = hash->table; entry < end; entry++) {
238*7c568831SAndroid Build Coastguard Worker             if (entry->hashValue == 0)
239*7c568831SAndroid Build Coastguard Worker                 continue;
240*7c568831SAndroid Build Coastguard Worker             if ((dealloc != NULL) && (entry->payload != NULL))
241*7c568831SAndroid Build Coastguard Worker                 dealloc(entry->payload, entry->key);
242*7c568831SAndroid Build Coastguard Worker             if (hash->dict == NULL) {
243*7c568831SAndroid Build Coastguard Worker                 if (entry->key)
244*7c568831SAndroid Build Coastguard Worker                     xmlFree(entry->key);
245*7c568831SAndroid Build Coastguard Worker                 if (entry->key2)
246*7c568831SAndroid Build Coastguard Worker                     xmlFree(entry->key2);
247*7c568831SAndroid Build Coastguard Worker                 if (entry->key3)
248*7c568831SAndroid Build Coastguard Worker                     xmlFree(entry->key3);
249*7c568831SAndroid Build Coastguard Worker             }
250*7c568831SAndroid Build Coastguard Worker         }
251*7c568831SAndroid Build Coastguard Worker 
252*7c568831SAndroid Build Coastguard Worker         xmlFree(hash->table);
253*7c568831SAndroid Build Coastguard Worker     }
254*7c568831SAndroid Build Coastguard Worker 
255*7c568831SAndroid Build Coastguard Worker     if (hash->dict)
256*7c568831SAndroid Build Coastguard Worker         xmlDictFree(hash->dict);
257*7c568831SAndroid Build Coastguard Worker 
258*7c568831SAndroid Build Coastguard Worker     xmlFree(hash);
259*7c568831SAndroid Build Coastguard Worker }
260*7c568831SAndroid Build Coastguard Worker 
261*7c568831SAndroid Build Coastguard Worker /**
262*7c568831SAndroid Build Coastguard Worker  * xmlFastStrEqual:
263*7c568831SAndroid Build Coastguard Worker  * @s1: string
264*7c568831SAndroid Build Coastguard Worker  * @s2: string
265*7c568831SAndroid Build Coastguard Worker  *
266*7c568831SAndroid Build Coastguard Worker  * Compare two strings for equality, allowing NULL values.
267*7c568831SAndroid Build Coastguard Worker  */
268*7c568831SAndroid Build Coastguard Worker static int
xmlFastStrEqual(const xmlChar * s1,const xmlChar * s2)269*7c568831SAndroid Build Coastguard Worker xmlFastStrEqual(const xmlChar *s1, const xmlChar *s2) {
270*7c568831SAndroid Build Coastguard Worker     if (s1 == NULL)
271*7c568831SAndroid Build Coastguard Worker         return(s2 == NULL);
272*7c568831SAndroid Build Coastguard Worker     else
273*7c568831SAndroid Build Coastguard Worker         return((s2 != NULL) &&
274*7c568831SAndroid Build Coastguard Worker                (strcmp((const char *) s1, (const char *) s2) == 0));
275*7c568831SAndroid Build Coastguard Worker }
276*7c568831SAndroid Build Coastguard Worker 
277*7c568831SAndroid Build Coastguard Worker /**
278*7c568831SAndroid Build Coastguard Worker  * xmlHashFindEntry:
279*7c568831SAndroid Build Coastguard Worker  * @hash: hash table, non-NULL, size > 0
280*7c568831SAndroid Build Coastguard Worker  * @key: first string key, non-NULL
281*7c568831SAndroid Build Coastguard Worker  * @key2: second string key
282*7c568831SAndroid Build Coastguard Worker  * @key3: third string key
283*7c568831SAndroid Build Coastguard Worker  * @hashValue: valid hash value of keys
284*7c568831SAndroid Build Coastguard Worker  * @pfound: result of search
285*7c568831SAndroid Build Coastguard Worker  *
286*7c568831SAndroid Build Coastguard Worker  * Try to find a matching hash table entry. If an entry was found, set
287*7c568831SAndroid Build Coastguard Worker  * @found to 1 and return the entry. Otherwise, set @found to 0 and return
288*7c568831SAndroid Build Coastguard Worker  * the location where a new entry should be inserted.
289*7c568831SAndroid Build Coastguard Worker  */
290*7c568831SAndroid Build Coastguard Worker ATTRIBUTE_NO_SANITIZE_INTEGER
291*7c568831SAndroid Build Coastguard Worker static xmlHashEntry *
xmlHashFindEntry(const xmlHashTable * hash,const xmlChar * key,const xmlChar * key2,const xmlChar * key3,unsigned hashValue,int * pfound)292*7c568831SAndroid Build Coastguard Worker xmlHashFindEntry(const xmlHashTable *hash, const xmlChar *key,
293*7c568831SAndroid Build Coastguard Worker                  const xmlChar *key2, const xmlChar *key3,
294*7c568831SAndroid Build Coastguard Worker                  unsigned hashValue, int *pfound) {
295*7c568831SAndroid Build Coastguard Worker     xmlHashEntry *entry;
296*7c568831SAndroid Build Coastguard Worker     unsigned mask, pos, displ;
297*7c568831SAndroid Build Coastguard Worker     int found = 0;
298*7c568831SAndroid Build Coastguard Worker 
299*7c568831SAndroid Build Coastguard Worker     mask = hash->size - 1;
300*7c568831SAndroid Build Coastguard Worker     pos = hashValue & mask;
301*7c568831SAndroid Build Coastguard Worker     entry = &hash->table[pos];
302*7c568831SAndroid Build Coastguard Worker 
303*7c568831SAndroid Build Coastguard Worker     if (entry->hashValue != 0) {
304*7c568831SAndroid Build Coastguard Worker         /*
305*7c568831SAndroid Build Coastguard Worker          * Robin hood hashing: abort if the displacement of the entry
306*7c568831SAndroid Build Coastguard Worker          * is smaller than the displacement of the key we look for.
307*7c568831SAndroid Build Coastguard Worker          * This also stops at the correct position when inserting.
308*7c568831SAndroid Build Coastguard Worker          */
309*7c568831SAndroid Build Coastguard Worker         displ = 0;
310*7c568831SAndroid Build Coastguard Worker         hashValue |= MAX_HASH_SIZE;
311*7c568831SAndroid Build Coastguard Worker 
312*7c568831SAndroid Build Coastguard Worker         do {
313*7c568831SAndroid Build Coastguard Worker             if (entry->hashValue == hashValue) {
314*7c568831SAndroid Build Coastguard Worker                 if (hash->dict) {
315*7c568831SAndroid Build Coastguard Worker                     if ((entry->key == key) &&
316*7c568831SAndroid Build Coastguard Worker                         (entry->key2 == key2) &&
317*7c568831SAndroid Build Coastguard Worker                         (entry->key3 == key3)) {
318*7c568831SAndroid Build Coastguard Worker                         found = 1;
319*7c568831SAndroid Build Coastguard Worker                         break;
320*7c568831SAndroid Build Coastguard Worker                     }
321*7c568831SAndroid Build Coastguard Worker                 }
322*7c568831SAndroid Build Coastguard Worker                 if ((strcmp((const char *) entry->key,
323*7c568831SAndroid Build Coastguard Worker                             (const char *) key) == 0) &&
324*7c568831SAndroid Build Coastguard Worker                     (xmlFastStrEqual(entry->key2, key2)) &&
325*7c568831SAndroid Build Coastguard Worker                     (xmlFastStrEqual(entry->key3, key3))) {
326*7c568831SAndroid Build Coastguard Worker                     found = 1;
327*7c568831SAndroid Build Coastguard Worker                     break;
328*7c568831SAndroid Build Coastguard Worker                 }
329*7c568831SAndroid Build Coastguard Worker             }
330*7c568831SAndroid Build Coastguard Worker 
331*7c568831SAndroid Build Coastguard Worker             displ++;
332*7c568831SAndroid Build Coastguard Worker             pos++;
333*7c568831SAndroid Build Coastguard Worker             entry++;
334*7c568831SAndroid Build Coastguard Worker             if ((pos & mask) == 0)
335*7c568831SAndroid Build Coastguard Worker                 entry = hash->table;
336*7c568831SAndroid Build Coastguard Worker         } while ((entry->hashValue != 0) &&
337*7c568831SAndroid Build Coastguard Worker                  (((pos - entry->hashValue) & mask) >= displ));
338*7c568831SAndroid Build Coastguard Worker     }
339*7c568831SAndroid Build Coastguard Worker 
340*7c568831SAndroid Build Coastguard Worker     *pfound = found;
341*7c568831SAndroid Build Coastguard Worker     return(entry);
342*7c568831SAndroid Build Coastguard Worker }
343*7c568831SAndroid Build Coastguard Worker 
344*7c568831SAndroid Build Coastguard Worker /**
345*7c568831SAndroid Build Coastguard Worker  * xmlHashGrow:
346*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
347*7c568831SAndroid Build Coastguard Worker  * @size: new size of the hash table
348*7c568831SAndroid Build Coastguard Worker  *
349*7c568831SAndroid Build Coastguard Worker  * Resize the hash table.
350*7c568831SAndroid Build Coastguard Worker  *
351*7c568831SAndroid Build Coastguard Worker  * Returns 0 in case of success, -1 if a memory allocation failed.
352*7c568831SAndroid Build Coastguard Worker  */
353*7c568831SAndroid Build Coastguard Worker static int
xmlHashGrow(xmlHashTablePtr hash,unsigned size)354*7c568831SAndroid Build Coastguard Worker xmlHashGrow(xmlHashTablePtr hash, unsigned size) {
355*7c568831SAndroid Build Coastguard Worker     const xmlHashEntry *oldentry, *oldend, *end;
356*7c568831SAndroid Build Coastguard Worker     xmlHashEntry *table;
357*7c568831SAndroid Build Coastguard Worker     unsigned oldsize, i;
358*7c568831SAndroid Build Coastguard Worker 
359*7c568831SAndroid Build Coastguard Worker     /* Add 0 to avoid spurious -Wtype-limits warning on 64-bit GCC */
360*7c568831SAndroid Build Coastguard Worker     if ((size_t) size + 0 > SIZE_MAX / sizeof(table[0]))
361*7c568831SAndroid Build Coastguard Worker         return(-1);
362*7c568831SAndroid Build Coastguard Worker     table = xmlMalloc(size * sizeof(table[0]));
363*7c568831SAndroid Build Coastguard Worker     if (table == NULL)
364*7c568831SAndroid Build Coastguard Worker         return(-1);
365*7c568831SAndroid Build Coastguard Worker     memset(table, 0, size * sizeof(table[0]));
366*7c568831SAndroid Build Coastguard Worker 
367*7c568831SAndroid Build Coastguard Worker     oldsize = hash->size;
368*7c568831SAndroid Build Coastguard Worker     if (oldsize == 0)
369*7c568831SAndroid Build Coastguard Worker         goto done;
370*7c568831SAndroid Build Coastguard Worker 
371*7c568831SAndroid Build Coastguard Worker     oldend = &hash->table[oldsize];
372*7c568831SAndroid Build Coastguard Worker     end = &table[size];
373*7c568831SAndroid Build Coastguard Worker 
374*7c568831SAndroid Build Coastguard Worker     /*
375*7c568831SAndroid Build Coastguard Worker      * Robin Hood sorting order is maintained if we
376*7c568831SAndroid Build Coastguard Worker      *
377*7c568831SAndroid Build Coastguard Worker      * - compute hash indices with modulo
378*7c568831SAndroid Build Coastguard Worker      * - resize by an integer factor
379*7c568831SAndroid Build Coastguard Worker      * - start to copy from the beginning of a probe sequence
380*7c568831SAndroid Build Coastguard Worker      */
381*7c568831SAndroid Build Coastguard Worker     oldentry = hash->table;
382*7c568831SAndroid Build Coastguard Worker     while (oldentry->hashValue != 0) {
383*7c568831SAndroid Build Coastguard Worker         if (++oldentry >= oldend)
384*7c568831SAndroid Build Coastguard Worker             oldentry = hash->table;
385*7c568831SAndroid Build Coastguard Worker     }
386*7c568831SAndroid Build Coastguard Worker 
387*7c568831SAndroid Build Coastguard Worker     for (i = 0; i < oldsize; i++) {
388*7c568831SAndroid Build Coastguard Worker         if (oldentry->hashValue != 0) {
389*7c568831SAndroid Build Coastguard Worker             xmlHashEntry *entry = &table[oldentry->hashValue & (size - 1)];
390*7c568831SAndroid Build Coastguard Worker 
391*7c568831SAndroid Build Coastguard Worker             while (entry->hashValue != 0) {
392*7c568831SAndroid Build Coastguard Worker                 if (++entry >= end)
393*7c568831SAndroid Build Coastguard Worker                     entry = table;
394*7c568831SAndroid Build Coastguard Worker             }
395*7c568831SAndroid Build Coastguard Worker             *entry = *oldentry;
396*7c568831SAndroid Build Coastguard Worker         }
397*7c568831SAndroid Build Coastguard Worker 
398*7c568831SAndroid Build Coastguard Worker         if (++oldentry >= oldend)
399*7c568831SAndroid Build Coastguard Worker             oldentry = hash->table;
400*7c568831SAndroid Build Coastguard Worker     }
401*7c568831SAndroid Build Coastguard Worker 
402*7c568831SAndroid Build Coastguard Worker     xmlFree(hash->table);
403*7c568831SAndroid Build Coastguard Worker 
404*7c568831SAndroid Build Coastguard Worker done:
405*7c568831SAndroid Build Coastguard Worker     hash->table = table;
406*7c568831SAndroid Build Coastguard Worker     hash->size = size;
407*7c568831SAndroid Build Coastguard Worker 
408*7c568831SAndroid Build Coastguard Worker     return(0);
409*7c568831SAndroid Build Coastguard Worker }
410*7c568831SAndroid Build Coastguard Worker 
411*7c568831SAndroid Build Coastguard Worker /**
412*7c568831SAndroid Build Coastguard Worker  * xmlHashUpdateInternal:
413*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
414*7c568831SAndroid Build Coastguard Worker  * @key: first string key
415*7c568831SAndroid Build Coastguard Worker  * @key2: second string key
416*7c568831SAndroid Build Coastguard Worker  * @key3: third string key
417*7c568831SAndroid Build Coastguard Worker  * @payload: pointer to the payload
418*7c568831SAndroid Build Coastguard Worker  * @dealloc: deallocator function for replaced item or NULL
419*7c568831SAndroid Build Coastguard Worker  * @update: whether existing entries should be updated
420*7c568831SAndroid Build Coastguard Worker  *
421*7c568831SAndroid Build Coastguard Worker  * Internal function to add or update hash entries.
422*7c568831SAndroid Build Coastguard Worker  */
423*7c568831SAndroid Build Coastguard Worker ATTRIBUTE_NO_SANITIZE_INTEGER
424*7c568831SAndroid Build Coastguard Worker static int
xmlHashUpdateInternal(xmlHashTablePtr hash,const xmlChar * key,const xmlChar * key2,const xmlChar * key3,void * payload,xmlHashDeallocator dealloc,int update)425*7c568831SAndroid Build Coastguard Worker xmlHashUpdateInternal(xmlHashTablePtr hash, const xmlChar *key,
426*7c568831SAndroid Build Coastguard Worker                       const xmlChar *key2, const xmlChar *key3,
427*7c568831SAndroid Build Coastguard Worker                       void *payload, xmlHashDeallocator dealloc, int update) {
428*7c568831SAndroid Build Coastguard Worker     xmlChar *copy, *copy2, *copy3;
429*7c568831SAndroid Build Coastguard Worker     xmlHashEntry *entry = NULL;
430*7c568831SAndroid Build Coastguard Worker     size_t lengths[3] = {0, 0, 0};
431*7c568831SAndroid Build Coastguard Worker     unsigned hashValue;
432*7c568831SAndroid Build Coastguard Worker     int found = 0;
433*7c568831SAndroid Build Coastguard Worker 
434*7c568831SAndroid Build Coastguard Worker     if ((hash == NULL) || (key == NULL))
435*7c568831SAndroid Build Coastguard Worker         return(-1);
436*7c568831SAndroid Build Coastguard Worker 
437*7c568831SAndroid Build Coastguard Worker     /*
438*7c568831SAndroid Build Coastguard Worker      * Check for an existing entry
439*7c568831SAndroid Build Coastguard Worker      */
440*7c568831SAndroid Build Coastguard Worker     hashValue = xmlHashValue(hash->randomSeed, key, key2, key3, lengths);
441*7c568831SAndroid Build Coastguard Worker     if (hash->size > 0)
442*7c568831SAndroid Build Coastguard Worker         entry = xmlHashFindEntry(hash, key, key2, key3, hashValue, &found);
443*7c568831SAndroid Build Coastguard Worker     if (found) {
444*7c568831SAndroid Build Coastguard Worker         if (update) {
445*7c568831SAndroid Build Coastguard Worker             if (dealloc)
446*7c568831SAndroid Build Coastguard Worker                 dealloc(entry->payload, entry->key);
447*7c568831SAndroid Build Coastguard Worker             entry->payload = payload;
448*7c568831SAndroid Build Coastguard Worker         }
449*7c568831SAndroid Build Coastguard Worker 
450*7c568831SAndroid Build Coastguard Worker         return(0);
451*7c568831SAndroid Build Coastguard Worker     }
452*7c568831SAndroid Build Coastguard Worker 
453*7c568831SAndroid Build Coastguard Worker     /*
454*7c568831SAndroid Build Coastguard Worker      * Grow the hash table if needed
455*7c568831SAndroid Build Coastguard Worker      */
456*7c568831SAndroid Build Coastguard Worker     if (hash->nbElems + 1 > hash->size / MAX_FILL_DENOM * MAX_FILL_NUM) {
457*7c568831SAndroid Build Coastguard Worker         unsigned newSize, mask, displ, pos;
458*7c568831SAndroid Build Coastguard Worker 
459*7c568831SAndroid Build Coastguard Worker         if (hash->size == 0) {
460*7c568831SAndroid Build Coastguard Worker             newSize = MIN_HASH_SIZE;
461*7c568831SAndroid Build Coastguard Worker         } else {
462*7c568831SAndroid Build Coastguard Worker             /* This guarantees that nbElems < INT_MAX */
463*7c568831SAndroid Build Coastguard Worker             if (hash->size >= MAX_HASH_SIZE)
464*7c568831SAndroid Build Coastguard Worker                 return(-1);
465*7c568831SAndroid Build Coastguard Worker             newSize = hash->size * 2;
466*7c568831SAndroid Build Coastguard Worker         }
467*7c568831SAndroid Build Coastguard Worker         if (xmlHashGrow(hash, newSize) != 0)
468*7c568831SAndroid Build Coastguard Worker             return(-1);
469*7c568831SAndroid Build Coastguard Worker 
470*7c568831SAndroid Build Coastguard Worker         /*
471*7c568831SAndroid Build Coastguard Worker          * Find new entry
472*7c568831SAndroid Build Coastguard Worker          */
473*7c568831SAndroid Build Coastguard Worker         mask = hash->size - 1;
474*7c568831SAndroid Build Coastguard Worker         displ = 0;
475*7c568831SAndroid Build Coastguard Worker         pos = hashValue & mask;
476*7c568831SAndroid Build Coastguard Worker         entry = &hash->table[pos];
477*7c568831SAndroid Build Coastguard Worker 
478*7c568831SAndroid Build Coastguard Worker         if (entry->hashValue != 0) {
479*7c568831SAndroid Build Coastguard Worker             do {
480*7c568831SAndroid Build Coastguard Worker                 displ++;
481*7c568831SAndroid Build Coastguard Worker                 pos++;
482*7c568831SAndroid Build Coastguard Worker                 entry++;
483*7c568831SAndroid Build Coastguard Worker                 if ((pos & mask) == 0)
484*7c568831SAndroid Build Coastguard Worker                     entry = hash->table;
485*7c568831SAndroid Build Coastguard Worker             } while ((entry->hashValue != 0) &&
486*7c568831SAndroid Build Coastguard Worker                      ((pos - entry->hashValue) & mask) >= displ);
487*7c568831SAndroid Build Coastguard Worker         }
488*7c568831SAndroid Build Coastguard Worker     }
489*7c568831SAndroid Build Coastguard Worker 
490*7c568831SAndroid Build Coastguard Worker     /*
491*7c568831SAndroid Build Coastguard Worker      * Copy keys
492*7c568831SAndroid Build Coastguard Worker      */
493*7c568831SAndroid Build Coastguard Worker     if (hash->dict != NULL) {
494*7c568831SAndroid Build Coastguard Worker         if (xmlDictOwns(hash->dict, key)) {
495*7c568831SAndroid Build Coastguard Worker             copy = (xmlChar *) key;
496*7c568831SAndroid Build Coastguard Worker         } else {
497*7c568831SAndroid Build Coastguard Worker             copy = (xmlChar *) xmlDictLookup(hash->dict, key, -1);
498*7c568831SAndroid Build Coastguard Worker             if (copy == NULL)
499*7c568831SAndroid Build Coastguard Worker                 return(-1);
500*7c568831SAndroid Build Coastguard Worker         }
501*7c568831SAndroid Build Coastguard Worker 
502*7c568831SAndroid Build Coastguard Worker         if ((key2 == NULL) || (xmlDictOwns(hash->dict, key2))) {
503*7c568831SAndroid Build Coastguard Worker             copy2 = (xmlChar *) key2;
504*7c568831SAndroid Build Coastguard Worker         } else {
505*7c568831SAndroid Build Coastguard Worker             copy2 = (xmlChar *) xmlDictLookup(hash->dict, key2, -1);
506*7c568831SAndroid Build Coastguard Worker             if (copy2 == NULL)
507*7c568831SAndroid Build Coastguard Worker                 return(-1);
508*7c568831SAndroid Build Coastguard Worker         }
509*7c568831SAndroid Build Coastguard Worker         if ((key3 == NULL) || (xmlDictOwns(hash->dict, key3))) {
510*7c568831SAndroid Build Coastguard Worker             copy3 = (xmlChar *) key3;
511*7c568831SAndroid Build Coastguard Worker         } else {
512*7c568831SAndroid Build Coastguard Worker             copy3 = (xmlChar *) xmlDictLookup(hash->dict, key3, -1);
513*7c568831SAndroid Build Coastguard Worker             if (copy3 == NULL)
514*7c568831SAndroid Build Coastguard Worker                 return(-1);
515*7c568831SAndroid Build Coastguard Worker         }
516*7c568831SAndroid Build Coastguard Worker     } else {
517*7c568831SAndroid Build Coastguard Worker         copy = xmlMalloc(lengths[0] + 1);
518*7c568831SAndroid Build Coastguard Worker         if (copy == NULL)
519*7c568831SAndroid Build Coastguard Worker             return(-1);
520*7c568831SAndroid Build Coastguard Worker         memcpy(copy, key, lengths[0] + 1);
521*7c568831SAndroid Build Coastguard Worker 
522*7c568831SAndroid Build Coastguard Worker         if (key2 != NULL) {
523*7c568831SAndroid Build Coastguard Worker             copy2 = xmlMalloc(lengths[1] + 1);
524*7c568831SAndroid Build Coastguard Worker             if (copy2 == NULL) {
525*7c568831SAndroid Build Coastguard Worker                 xmlFree(copy);
526*7c568831SAndroid Build Coastguard Worker                 return(-1);
527*7c568831SAndroid Build Coastguard Worker             }
528*7c568831SAndroid Build Coastguard Worker             memcpy(copy2, key2, lengths[1] + 1);
529*7c568831SAndroid Build Coastguard Worker         } else {
530*7c568831SAndroid Build Coastguard Worker             copy2 = NULL;
531*7c568831SAndroid Build Coastguard Worker         }
532*7c568831SAndroid Build Coastguard Worker 
533*7c568831SAndroid Build Coastguard Worker         if (key3 != NULL) {
534*7c568831SAndroid Build Coastguard Worker             copy3 = xmlMalloc(lengths[2] + 1);
535*7c568831SAndroid Build Coastguard Worker             if (copy3 == NULL) {
536*7c568831SAndroid Build Coastguard Worker                 xmlFree(copy);
537*7c568831SAndroid Build Coastguard Worker                 xmlFree(copy2);
538*7c568831SAndroid Build Coastguard Worker                 return(-1);
539*7c568831SAndroid Build Coastguard Worker             }
540*7c568831SAndroid Build Coastguard Worker             memcpy(copy3, key3, lengths[2] + 1);
541*7c568831SAndroid Build Coastguard Worker         } else {
542*7c568831SAndroid Build Coastguard Worker             copy3 = NULL;
543*7c568831SAndroid Build Coastguard Worker         }
544*7c568831SAndroid Build Coastguard Worker     }
545*7c568831SAndroid Build Coastguard Worker 
546*7c568831SAndroid Build Coastguard Worker     /*
547*7c568831SAndroid Build Coastguard Worker      * Shift the remainder of the probe sequence to the right
548*7c568831SAndroid Build Coastguard Worker      */
549*7c568831SAndroid Build Coastguard Worker     if (entry->hashValue != 0) {
550*7c568831SAndroid Build Coastguard Worker         const xmlHashEntry *end = &hash->table[hash->size];
551*7c568831SAndroid Build Coastguard Worker         const xmlHashEntry *cur = entry;
552*7c568831SAndroid Build Coastguard Worker 
553*7c568831SAndroid Build Coastguard Worker         do {
554*7c568831SAndroid Build Coastguard Worker             cur++;
555*7c568831SAndroid Build Coastguard Worker             if (cur >= end)
556*7c568831SAndroid Build Coastguard Worker                 cur = hash->table;
557*7c568831SAndroid Build Coastguard Worker         } while (cur->hashValue != 0);
558*7c568831SAndroid Build Coastguard Worker 
559*7c568831SAndroid Build Coastguard Worker         if (cur < entry) {
560*7c568831SAndroid Build Coastguard Worker             /*
561*7c568831SAndroid Build Coastguard Worker              * If we traversed the end of the buffer, handle the part
562*7c568831SAndroid Build Coastguard Worker              * at the start of the buffer.
563*7c568831SAndroid Build Coastguard Worker              */
564*7c568831SAndroid Build Coastguard Worker             memmove(&hash->table[1], hash->table,
565*7c568831SAndroid Build Coastguard Worker                     (char *) cur - (char *) hash->table);
566*7c568831SAndroid Build Coastguard Worker             cur = end - 1;
567*7c568831SAndroid Build Coastguard Worker             hash->table[0] = *cur;
568*7c568831SAndroid Build Coastguard Worker         }
569*7c568831SAndroid Build Coastguard Worker 
570*7c568831SAndroid Build Coastguard Worker         memmove(&entry[1], entry, (char *) cur - (char *) entry);
571*7c568831SAndroid Build Coastguard Worker     }
572*7c568831SAndroid Build Coastguard Worker 
573*7c568831SAndroid Build Coastguard Worker     /*
574*7c568831SAndroid Build Coastguard Worker      * Populate entry
575*7c568831SAndroid Build Coastguard Worker      */
576*7c568831SAndroid Build Coastguard Worker     entry->key = copy;
577*7c568831SAndroid Build Coastguard Worker     entry->key2 = copy2;
578*7c568831SAndroid Build Coastguard Worker     entry->key3 = copy3;
579*7c568831SAndroid Build Coastguard Worker     entry->payload = payload;
580*7c568831SAndroid Build Coastguard Worker     /* OR with MAX_HASH_SIZE to make sure that the value is non-zero */
581*7c568831SAndroid Build Coastguard Worker     entry->hashValue = hashValue | MAX_HASH_SIZE;
582*7c568831SAndroid Build Coastguard Worker 
583*7c568831SAndroid Build Coastguard Worker     hash->nbElems++;
584*7c568831SAndroid Build Coastguard Worker 
585*7c568831SAndroid Build Coastguard Worker     return(1);
586*7c568831SAndroid Build Coastguard Worker }
587*7c568831SAndroid Build Coastguard Worker 
588*7c568831SAndroid Build Coastguard Worker /**
589*7c568831SAndroid Build Coastguard Worker  * xmlHashDefaultDeallocator:
590*7c568831SAndroid Build Coastguard Worker  * @entry: hash table entry
591*7c568831SAndroid Build Coastguard Worker  * @key: the entry's string key
592*7c568831SAndroid Build Coastguard Worker  *
593*7c568831SAndroid Build Coastguard Worker  * Free a hash table entry with xmlFree.
594*7c568831SAndroid Build Coastguard Worker  */
595*7c568831SAndroid Build Coastguard Worker void
xmlHashDefaultDeallocator(void * entry,const xmlChar * key ATTRIBUTE_UNUSED)596*7c568831SAndroid Build Coastguard Worker xmlHashDefaultDeallocator(void *entry, const xmlChar *key ATTRIBUTE_UNUSED) {
597*7c568831SAndroid Build Coastguard Worker     xmlFree(entry);
598*7c568831SAndroid Build Coastguard Worker }
599*7c568831SAndroid Build Coastguard Worker 
600*7c568831SAndroid Build Coastguard Worker /**
601*7c568831SAndroid Build Coastguard Worker  * xmlHashAdd:
602*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
603*7c568831SAndroid Build Coastguard Worker  * @key: string key
604*7c568831SAndroid Build Coastguard Worker  * @payload: pointer to the payload
605*7c568831SAndroid Build Coastguard Worker  *
606*7c568831SAndroid Build Coastguard Worker  * Add a hash table entry. If an entry with this key already exists,
607*7c568831SAndroid Build Coastguard Worker  * payload will not be updated and 0 is returned. This return value
608*7c568831SAndroid Build Coastguard Worker  * can't be distinguished from out-of-memory errors, so this function
609*7c568831SAndroid Build Coastguard Worker  * should be used with care.
610*7c568831SAndroid Build Coastguard Worker  *
611*7c568831SAndroid Build Coastguard Worker  * Available since 2.13.0.
612*7c568831SAndroid Build Coastguard Worker  *
613*7c568831SAndroid Build Coastguard Worker  * Returns 1 on success, 0 if an entry exists and -1 in case of error.
614*7c568831SAndroid Build Coastguard Worker  */
615*7c568831SAndroid Build Coastguard Worker int
xmlHashAdd(xmlHashTablePtr hash,const xmlChar * key,void * payload)616*7c568831SAndroid Build Coastguard Worker xmlHashAdd(xmlHashTablePtr hash, const xmlChar *key, void *payload) {
617*7c568831SAndroid Build Coastguard Worker     return(xmlHashUpdateInternal(hash, key, NULL, NULL, payload, NULL, 0));
618*7c568831SAndroid Build Coastguard Worker }
619*7c568831SAndroid Build Coastguard Worker 
620*7c568831SAndroid Build Coastguard Worker /**
621*7c568831SAndroid Build Coastguard Worker  * xmlHashAdd2:
622*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
623*7c568831SAndroid Build Coastguard Worker  * @key: first string key
624*7c568831SAndroid Build Coastguard Worker  * @key2: second string key
625*7c568831SAndroid Build Coastguard Worker  * @payload: pointer to the payload
626*7c568831SAndroid Build Coastguard Worker  *
627*7c568831SAndroid Build Coastguard Worker  * Add a hash table entry with two strings as key.
628*7c568831SAndroid Build Coastguard Worker  *
629*7c568831SAndroid Build Coastguard Worker  * See xmlHashAdd.
630*7c568831SAndroid Build Coastguard Worker  *
631*7c568831SAndroid Build Coastguard Worker  * Available since 2.13.0.
632*7c568831SAndroid Build Coastguard Worker  *
633*7c568831SAndroid Build Coastguard Worker  * Returns 1 on success, 0 if an entry exists and -1 in case of error.
634*7c568831SAndroid Build Coastguard Worker  */
635*7c568831SAndroid Build Coastguard Worker int
xmlHashAdd2(xmlHashTablePtr hash,const xmlChar * key,const xmlChar * key2,void * payload)636*7c568831SAndroid Build Coastguard Worker xmlHashAdd2(xmlHashTablePtr hash, const xmlChar *key,
637*7c568831SAndroid Build Coastguard Worker                  const xmlChar *key2, void *payload) {
638*7c568831SAndroid Build Coastguard Worker     return(xmlHashUpdateInternal(hash, key, key2, NULL, payload, NULL, 0));
639*7c568831SAndroid Build Coastguard Worker }
640*7c568831SAndroid Build Coastguard Worker 
641*7c568831SAndroid Build Coastguard Worker /**
642*7c568831SAndroid Build Coastguard Worker  * xmlHashAdd3:
643*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
644*7c568831SAndroid Build Coastguard Worker  * @key: first string key
645*7c568831SAndroid Build Coastguard Worker  * @key2: second string key
646*7c568831SAndroid Build Coastguard Worker  * @key3: third string key
647*7c568831SAndroid Build Coastguard Worker  * @payload: pointer to the payload
648*7c568831SAndroid Build Coastguard Worker  *
649*7c568831SAndroid Build Coastguard Worker  * Add a hash table entry with three strings as key.
650*7c568831SAndroid Build Coastguard Worker  *
651*7c568831SAndroid Build Coastguard Worker  * See xmlHashAdd.
652*7c568831SAndroid Build Coastguard Worker  *
653*7c568831SAndroid Build Coastguard Worker  * Available since 2.13.0.
654*7c568831SAndroid Build Coastguard Worker  *
655*7c568831SAndroid Build Coastguard Worker  * Returns 1 on success, 0 if an entry exists and -1 in case of error.
656*7c568831SAndroid Build Coastguard Worker  */
657*7c568831SAndroid Build Coastguard Worker int
xmlHashAdd3(xmlHashTablePtr hash,const xmlChar * key,const xmlChar * key2,const xmlChar * key3,void * payload)658*7c568831SAndroid Build Coastguard Worker xmlHashAdd3(xmlHashTablePtr hash, const xmlChar *key,
659*7c568831SAndroid Build Coastguard Worker                  const xmlChar *key2, const xmlChar *key3,
660*7c568831SAndroid Build Coastguard Worker                  void *payload) {
661*7c568831SAndroid Build Coastguard Worker     return(xmlHashUpdateInternal(hash, key, key2, key3, payload, NULL, 0));
662*7c568831SAndroid Build Coastguard Worker }
663*7c568831SAndroid Build Coastguard Worker 
664*7c568831SAndroid Build Coastguard Worker /**
665*7c568831SAndroid Build Coastguard Worker  * xmlHashAddEntry:
666*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
667*7c568831SAndroid Build Coastguard Worker  * @key: string key
668*7c568831SAndroid Build Coastguard Worker  * @payload: pointer to the payload
669*7c568831SAndroid Build Coastguard Worker  *
670*7c568831SAndroid Build Coastguard Worker  * Add a hash table entry. If an entry with this key already exists,
671*7c568831SAndroid Build Coastguard Worker  * payload will not be updated and -1 is returned. This return value
672*7c568831SAndroid Build Coastguard Worker  * can't be distinguished from out-of-memory errors, so this function
673*7c568831SAndroid Build Coastguard Worker  * should be used with care.
674*7c568831SAndroid Build Coastguard Worker  *
675*7c568831SAndroid Build Coastguard Worker  * NOTE: This function doesn't allow to distinguish malloc failures from
676*7c568831SAndroid Build Coastguard Worker  *       existing entries. Use xmlHashAdd instead.
677*7c568831SAndroid Build Coastguard Worker  *
678*7c568831SAndroid Build Coastguard Worker  * Returns 0 on success and -1 in case of error.
679*7c568831SAndroid Build Coastguard Worker  */
680*7c568831SAndroid Build Coastguard Worker int
xmlHashAddEntry(xmlHashTablePtr hash,const xmlChar * key,void * payload)681*7c568831SAndroid Build Coastguard Worker xmlHashAddEntry(xmlHashTablePtr hash, const xmlChar *key, void *payload) {
682*7c568831SAndroid Build Coastguard Worker     int res = xmlHashUpdateInternal(hash, key, NULL, NULL, payload, NULL, 0);
683*7c568831SAndroid Build Coastguard Worker 
684*7c568831SAndroid Build Coastguard Worker     if (res == 0)
685*7c568831SAndroid Build Coastguard Worker         res = -1;
686*7c568831SAndroid Build Coastguard Worker     else if (res == 1)
687*7c568831SAndroid Build Coastguard Worker         res = 0;
688*7c568831SAndroid Build Coastguard Worker 
689*7c568831SAndroid Build Coastguard Worker     return(res);
690*7c568831SAndroid Build Coastguard Worker }
691*7c568831SAndroid Build Coastguard Worker 
692*7c568831SAndroid Build Coastguard Worker /**
693*7c568831SAndroid Build Coastguard Worker  * xmlHashAddEntry2:
694*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
695*7c568831SAndroid Build Coastguard Worker  * @key: first string key
696*7c568831SAndroid Build Coastguard Worker  * @key2: second string key
697*7c568831SAndroid Build Coastguard Worker  * @payload: pointer to the payload
698*7c568831SAndroid Build Coastguard Worker  *
699*7c568831SAndroid Build Coastguard Worker  * Add a hash table entry with two strings as key.
700*7c568831SAndroid Build Coastguard Worker  *
701*7c568831SAndroid Build Coastguard Worker  * See xmlHashAddEntry.
702*7c568831SAndroid Build Coastguard Worker  *
703*7c568831SAndroid Build Coastguard Worker  * Returns 0 on success and -1 in case of error.
704*7c568831SAndroid Build Coastguard Worker  */
705*7c568831SAndroid Build Coastguard Worker int
xmlHashAddEntry2(xmlHashTablePtr hash,const xmlChar * key,const xmlChar * key2,void * payload)706*7c568831SAndroid Build Coastguard Worker xmlHashAddEntry2(xmlHashTablePtr hash, const xmlChar *key,
707*7c568831SAndroid Build Coastguard Worker                  const xmlChar *key2, void *payload) {
708*7c568831SAndroid Build Coastguard Worker     int res = xmlHashUpdateInternal(hash, key, key2, NULL, payload, NULL, 0);
709*7c568831SAndroid Build Coastguard Worker 
710*7c568831SAndroid Build Coastguard Worker     if (res == 0)
711*7c568831SAndroid Build Coastguard Worker         res = -1;
712*7c568831SAndroid Build Coastguard Worker     else if (res == 1)
713*7c568831SAndroid Build Coastguard Worker         res = 0;
714*7c568831SAndroid Build Coastguard Worker 
715*7c568831SAndroid Build Coastguard Worker     return(res);
716*7c568831SAndroid Build Coastguard Worker }
717*7c568831SAndroid Build Coastguard Worker 
718*7c568831SAndroid Build Coastguard Worker /**
719*7c568831SAndroid Build Coastguard Worker  * xmlHashAddEntry3:
720*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
721*7c568831SAndroid Build Coastguard Worker  * @key: first string key
722*7c568831SAndroid Build Coastguard Worker  * @key2: second string key
723*7c568831SAndroid Build Coastguard Worker  * @key3: third string key
724*7c568831SAndroid Build Coastguard Worker  * @payload: pointer to the payload
725*7c568831SAndroid Build Coastguard Worker  *
726*7c568831SAndroid Build Coastguard Worker  * Add a hash table entry with three strings as key.
727*7c568831SAndroid Build Coastguard Worker  *
728*7c568831SAndroid Build Coastguard Worker  * See xmlHashAddEntry.
729*7c568831SAndroid Build Coastguard Worker  *
730*7c568831SAndroid Build Coastguard Worker  * Returns 0 on success and -1 in case of error.
731*7c568831SAndroid Build Coastguard Worker  */
732*7c568831SAndroid Build Coastguard Worker int
xmlHashAddEntry3(xmlHashTablePtr hash,const xmlChar * key,const xmlChar * key2,const xmlChar * key3,void * payload)733*7c568831SAndroid Build Coastguard Worker xmlHashAddEntry3(xmlHashTablePtr hash, const xmlChar *key,
734*7c568831SAndroid Build Coastguard Worker                  const xmlChar *key2, const xmlChar *key3,
735*7c568831SAndroid Build Coastguard Worker                  void *payload) {
736*7c568831SAndroid Build Coastguard Worker     int res = xmlHashUpdateInternal(hash, key, key2, key3, payload, NULL, 0);
737*7c568831SAndroid Build Coastguard Worker 
738*7c568831SAndroid Build Coastguard Worker     if (res == 0)
739*7c568831SAndroid Build Coastguard Worker         res = -1;
740*7c568831SAndroid Build Coastguard Worker     else if (res == 1)
741*7c568831SAndroid Build Coastguard Worker         res = 0;
742*7c568831SAndroid Build Coastguard Worker 
743*7c568831SAndroid Build Coastguard Worker     return(res);
744*7c568831SAndroid Build Coastguard Worker }
745*7c568831SAndroid Build Coastguard Worker 
746*7c568831SAndroid Build Coastguard Worker /**
747*7c568831SAndroid Build Coastguard Worker  * xmlHashUpdateEntry:
748*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
749*7c568831SAndroid Build Coastguard Worker  * @key: string key
750*7c568831SAndroid Build Coastguard Worker  * @payload: pointer to the payload
751*7c568831SAndroid Build Coastguard Worker  * @dealloc: deallocator function for replaced item or NULL
752*7c568831SAndroid Build Coastguard Worker  *
753*7c568831SAndroid Build Coastguard Worker  * Add a hash table entry. If an entry with this key already exists,
754*7c568831SAndroid Build Coastguard Worker  * the old payload will be freed and updated with the new value.
755*7c568831SAndroid Build Coastguard Worker  *
756*7c568831SAndroid Build Coastguard Worker  * Returns 0 in case of success, -1 if a memory allocation failed.
757*7c568831SAndroid Build Coastguard Worker  */
758*7c568831SAndroid Build Coastguard Worker int
xmlHashUpdateEntry(xmlHashTablePtr hash,const xmlChar * key,void * payload,xmlHashDeallocator dealloc)759*7c568831SAndroid Build Coastguard Worker xmlHashUpdateEntry(xmlHashTablePtr hash, const xmlChar *key,
760*7c568831SAndroid Build Coastguard Worker                    void *payload, xmlHashDeallocator dealloc) {
761*7c568831SAndroid Build Coastguard Worker     int res = xmlHashUpdateInternal(hash, key, NULL, NULL, payload,
762*7c568831SAndroid Build Coastguard Worker                                     dealloc, 1);
763*7c568831SAndroid Build Coastguard Worker 
764*7c568831SAndroid Build Coastguard Worker     if (res == 1)
765*7c568831SAndroid Build Coastguard Worker         res = 0;
766*7c568831SAndroid Build Coastguard Worker 
767*7c568831SAndroid Build Coastguard Worker     return(res);
768*7c568831SAndroid Build Coastguard Worker }
769*7c568831SAndroid Build Coastguard Worker 
770*7c568831SAndroid Build Coastguard Worker /**
771*7c568831SAndroid Build Coastguard Worker  * xmlHashUpdateEntry2:
772*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
773*7c568831SAndroid Build Coastguard Worker  * @key: first string key
774*7c568831SAndroid Build Coastguard Worker  * @key2: second string key
775*7c568831SAndroid Build Coastguard Worker  * @payload: pointer to the payload
776*7c568831SAndroid Build Coastguard Worker  * @dealloc: deallocator function for replaced item or NULL
777*7c568831SAndroid Build Coastguard Worker  *
778*7c568831SAndroid Build Coastguard Worker  * Add a hash table entry with two strings as key.
779*7c568831SAndroid Build Coastguard Worker  *
780*7c568831SAndroid Build Coastguard Worker  * See xmlHashUpdateEntry.
781*7c568831SAndroid Build Coastguard Worker  *
782*7c568831SAndroid Build Coastguard Worker  * Returns 0 on success and -1 in case of error.
783*7c568831SAndroid Build Coastguard Worker  */
784*7c568831SAndroid Build Coastguard Worker int
xmlHashUpdateEntry2(xmlHashTablePtr hash,const xmlChar * key,const xmlChar * key2,void * payload,xmlHashDeallocator dealloc)785*7c568831SAndroid Build Coastguard Worker xmlHashUpdateEntry2(xmlHashTablePtr hash, const xmlChar *key,
786*7c568831SAndroid Build Coastguard Worker                    const xmlChar *key2, void *payload,
787*7c568831SAndroid Build Coastguard Worker                    xmlHashDeallocator dealloc) {
788*7c568831SAndroid Build Coastguard Worker     int res = xmlHashUpdateInternal(hash, key, key2, NULL, payload,
789*7c568831SAndroid Build Coastguard Worker                                     dealloc, 1);
790*7c568831SAndroid Build Coastguard Worker 
791*7c568831SAndroid Build Coastguard Worker     if (res == 1)
792*7c568831SAndroid Build Coastguard Worker         res = 0;
793*7c568831SAndroid Build Coastguard Worker 
794*7c568831SAndroid Build Coastguard Worker     return(res);
795*7c568831SAndroid Build Coastguard Worker }
796*7c568831SAndroid Build Coastguard Worker 
797*7c568831SAndroid Build Coastguard Worker /**
798*7c568831SAndroid Build Coastguard Worker  * xmlHashUpdateEntry3:
799*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
800*7c568831SAndroid Build Coastguard Worker  * @key: first string key
801*7c568831SAndroid Build Coastguard Worker  * @key2: second string key
802*7c568831SAndroid Build Coastguard Worker  * @key3: third string key
803*7c568831SAndroid Build Coastguard Worker  * @payload: pointer to the payload
804*7c568831SAndroid Build Coastguard Worker  * @dealloc: deallocator function for replaced item or NULL
805*7c568831SAndroid Build Coastguard Worker  *
806*7c568831SAndroid Build Coastguard Worker  * Add a hash table entry with three strings as key.
807*7c568831SAndroid Build Coastguard Worker  *
808*7c568831SAndroid Build Coastguard Worker  * See xmlHashUpdateEntry.
809*7c568831SAndroid Build Coastguard Worker  *
810*7c568831SAndroid Build Coastguard Worker  * Returns 0 on success and -1 in case of error.
811*7c568831SAndroid Build Coastguard Worker  */
812*7c568831SAndroid Build Coastguard Worker int
xmlHashUpdateEntry3(xmlHashTablePtr hash,const xmlChar * key,const xmlChar * key2,const xmlChar * key3,void * payload,xmlHashDeallocator dealloc)813*7c568831SAndroid Build Coastguard Worker xmlHashUpdateEntry3(xmlHashTablePtr hash, const xmlChar *key,
814*7c568831SAndroid Build Coastguard Worker                    const xmlChar *key2, const xmlChar *key3,
815*7c568831SAndroid Build Coastguard Worker                    void *payload, xmlHashDeallocator dealloc) {
816*7c568831SAndroid Build Coastguard Worker     int res = xmlHashUpdateInternal(hash, key, key2, key3, payload,
817*7c568831SAndroid Build Coastguard Worker                                     dealloc, 1);
818*7c568831SAndroid Build Coastguard Worker 
819*7c568831SAndroid Build Coastguard Worker     if (res == 1)
820*7c568831SAndroid Build Coastguard Worker         res = 0;
821*7c568831SAndroid Build Coastguard Worker 
822*7c568831SAndroid Build Coastguard Worker     return(res);
823*7c568831SAndroid Build Coastguard Worker }
824*7c568831SAndroid Build Coastguard Worker 
825*7c568831SAndroid Build Coastguard Worker /**
826*7c568831SAndroid Build Coastguard Worker  * xmlHashLookup:
827*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
828*7c568831SAndroid Build Coastguard Worker  * @key: string key
829*7c568831SAndroid Build Coastguard Worker  *
830*7c568831SAndroid Build Coastguard Worker  * Find the entry specified by @key.
831*7c568831SAndroid Build Coastguard Worker  *
832*7c568831SAndroid Build Coastguard Worker  * Returns a pointer to the payload or NULL if no entry was found.
833*7c568831SAndroid Build Coastguard Worker  */
834*7c568831SAndroid Build Coastguard Worker void *
xmlHashLookup(xmlHashTablePtr hash,const xmlChar * key)835*7c568831SAndroid Build Coastguard Worker xmlHashLookup(xmlHashTablePtr hash, const xmlChar *key) {
836*7c568831SAndroid Build Coastguard Worker     return(xmlHashLookup3(hash, key, NULL, NULL));
837*7c568831SAndroid Build Coastguard Worker }
838*7c568831SAndroid Build Coastguard Worker 
839*7c568831SAndroid Build Coastguard Worker /**
840*7c568831SAndroid Build Coastguard Worker  * xmlHashLookup2:
841*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
842*7c568831SAndroid Build Coastguard Worker  * @key: first string key
843*7c568831SAndroid Build Coastguard Worker  * @key2: second string key
844*7c568831SAndroid Build Coastguard Worker  *
845*7c568831SAndroid Build Coastguard Worker  * Find the payload specified by the (@key, @key2) tuple.
846*7c568831SAndroid Build Coastguard Worker  *
847*7c568831SAndroid Build Coastguard Worker  * Returns a pointer to the payload or NULL if no entry was found.
848*7c568831SAndroid Build Coastguard Worker  */
849*7c568831SAndroid Build Coastguard Worker void *
xmlHashLookup2(xmlHashTablePtr hash,const xmlChar * key,const xmlChar * key2)850*7c568831SAndroid Build Coastguard Worker xmlHashLookup2(xmlHashTablePtr hash, const xmlChar *key,
851*7c568831SAndroid Build Coastguard Worker               const xmlChar *key2) {
852*7c568831SAndroid Build Coastguard Worker     return(xmlHashLookup3(hash, key, key2, NULL));
853*7c568831SAndroid Build Coastguard Worker }
854*7c568831SAndroid Build Coastguard Worker 
855*7c568831SAndroid Build Coastguard Worker /**
856*7c568831SAndroid Build Coastguard Worker  * xmlHashQLookup:
857*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
858*7c568831SAndroid Build Coastguard Worker  * @prefix: prefix of the string key
859*7c568831SAndroid Build Coastguard Worker  * @name: local name of the string key
860*7c568831SAndroid Build Coastguard Worker  *
861*7c568831SAndroid Build Coastguard Worker  * Find the payload specified by the QName @prefix:@name or @name.
862*7c568831SAndroid Build Coastguard Worker  *
863*7c568831SAndroid Build Coastguard Worker  * Returns a pointer to the payload or NULL if no entry was found.
864*7c568831SAndroid Build Coastguard Worker  */
865*7c568831SAndroid Build Coastguard Worker void *
xmlHashQLookup(xmlHashTablePtr hash,const xmlChar * prefix,const xmlChar * name)866*7c568831SAndroid Build Coastguard Worker xmlHashQLookup(xmlHashTablePtr hash, const xmlChar *prefix,
867*7c568831SAndroid Build Coastguard Worker                const xmlChar *name) {
868*7c568831SAndroid Build Coastguard Worker     return(xmlHashQLookup3(hash, prefix, name, NULL, NULL, NULL, NULL));
869*7c568831SAndroid Build Coastguard Worker }
870*7c568831SAndroid Build Coastguard Worker 
871*7c568831SAndroid Build Coastguard Worker /**
872*7c568831SAndroid Build Coastguard Worker  * xmlHashQLookup2:
873*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
874*7c568831SAndroid Build Coastguard Worker  * @prefix: first prefix
875*7c568831SAndroid Build Coastguard Worker  * @name: first local name
876*7c568831SAndroid Build Coastguard Worker  * @prefix2: second prefix
877*7c568831SAndroid Build Coastguard Worker  * @name2: second local name
878*7c568831SAndroid Build Coastguard Worker  *
879*7c568831SAndroid Build Coastguard Worker  * Find the payload specified by the QNames tuple.
880*7c568831SAndroid Build Coastguard Worker  *
881*7c568831SAndroid Build Coastguard Worker  * Returns a pointer to the payload or NULL if no entry was found.
882*7c568831SAndroid Build Coastguard Worker  */
883*7c568831SAndroid Build Coastguard Worker void *
xmlHashQLookup2(xmlHashTablePtr hash,const xmlChar * prefix,const xmlChar * name,const xmlChar * prefix2,const xmlChar * name2)884*7c568831SAndroid Build Coastguard Worker xmlHashQLookup2(xmlHashTablePtr hash, const xmlChar *prefix,
885*7c568831SAndroid Build Coastguard Worker                 const xmlChar *name, const xmlChar *prefix2,
886*7c568831SAndroid Build Coastguard Worker                 const xmlChar *name2) {
887*7c568831SAndroid Build Coastguard Worker     return(xmlHashQLookup3(hash, prefix, name, prefix2, name2, NULL, NULL));
888*7c568831SAndroid Build Coastguard Worker }
889*7c568831SAndroid Build Coastguard Worker 
890*7c568831SAndroid Build Coastguard Worker /**
891*7c568831SAndroid Build Coastguard Worker  * xmlHashLookup3:
892*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
893*7c568831SAndroid Build Coastguard Worker  * @key: first string key
894*7c568831SAndroid Build Coastguard Worker  * @key2: second string key
895*7c568831SAndroid Build Coastguard Worker  * @key3: third string key
896*7c568831SAndroid Build Coastguard Worker  *
897*7c568831SAndroid Build Coastguard Worker  * Find the payload specified by the (@key, @key2, @key3) tuple.
898*7c568831SAndroid Build Coastguard Worker  *
899*7c568831SAndroid Build Coastguard Worker  * Returns a pointer to the payload or NULL if no entry was found.
900*7c568831SAndroid Build Coastguard Worker  */
901*7c568831SAndroid Build Coastguard Worker void *
xmlHashLookup3(xmlHashTablePtr hash,const xmlChar * key,const xmlChar * key2,const xmlChar * key3)902*7c568831SAndroid Build Coastguard Worker xmlHashLookup3(xmlHashTablePtr hash, const xmlChar *key,
903*7c568831SAndroid Build Coastguard Worker                const xmlChar *key2, const xmlChar *key3) {
904*7c568831SAndroid Build Coastguard Worker     const xmlHashEntry *entry;
905*7c568831SAndroid Build Coastguard Worker     unsigned hashValue;
906*7c568831SAndroid Build Coastguard Worker     int found;
907*7c568831SAndroid Build Coastguard Worker 
908*7c568831SAndroid Build Coastguard Worker     if ((hash == NULL) || (hash->size == 0) || (key == NULL))
909*7c568831SAndroid Build Coastguard Worker         return(NULL);
910*7c568831SAndroid Build Coastguard Worker     hashValue = xmlHashValue(hash->randomSeed, key, key2, key3, NULL);
911*7c568831SAndroid Build Coastguard Worker     entry = xmlHashFindEntry(hash, key, key2, key3, hashValue, &found);
912*7c568831SAndroid Build Coastguard Worker     if (found)
913*7c568831SAndroid Build Coastguard Worker         return(entry->payload);
914*7c568831SAndroid Build Coastguard Worker     return(NULL);
915*7c568831SAndroid Build Coastguard Worker }
916*7c568831SAndroid Build Coastguard Worker 
917*7c568831SAndroid Build Coastguard Worker /**
918*7c568831SAndroid Build Coastguard Worker  * xmlHashQLookup3:
919*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
920*7c568831SAndroid Build Coastguard Worker  * @prefix: first prefix
921*7c568831SAndroid Build Coastguard Worker  * @name: first local name
922*7c568831SAndroid Build Coastguard Worker  * @prefix2: second prefix
923*7c568831SAndroid Build Coastguard Worker  * @name2: second local name
924*7c568831SAndroid Build Coastguard Worker  * @prefix3: third prefix
925*7c568831SAndroid Build Coastguard Worker  * @name3: third local name
926*7c568831SAndroid Build Coastguard Worker  *
927*7c568831SAndroid Build Coastguard Worker  * Find the payload specified by the QNames tuple.
928*7c568831SAndroid Build Coastguard Worker  *
929*7c568831SAndroid Build Coastguard Worker  * Returns a pointer to the payload or NULL if no entry was found.
930*7c568831SAndroid Build Coastguard Worker  */
931*7c568831SAndroid Build Coastguard Worker ATTRIBUTE_NO_SANITIZE_INTEGER
932*7c568831SAndroid Build Coastguard Worker void *
xmlHashQLookup3(xmlHashTablePtr hash,const xmlChar * prefix,const xmlChar * name,const xmlChar * prefix2,const xmlChar * name2,const xmlChar * prefix3,const xmlChar * name3)933*7c568831SAndroid Build Coastguard Worker xmlHashQLookup3(xmlHashTablePtr hash,
934*7c568831SAndroid Build Coastguard Worker                 const xmlChar *prefix, const xmlChar *name,
935*7c568831SAndroid Build Coastguard Worker                 const xmlChar *prefix2, const xmlChar *name2,
936*7c568831SAndroid Build Coastguard Worker                 const xmlChar *prefix3, const xmlChar *name3) {
937*7c568831SAndroid Build Coastguard Worker     const xmlHashEntry *entry;
938*7c568831SAndroid Build Coastguard Worker     unsigned hashValue, mask, pos, displ;
939*7c568831SAndroid Build Coastguard Worker 
940*7c568831SAndroid Build Coastguard Worker     if ((hash == NULL) || (hash->size == 0) || (name == NULL))
941*7c568831SAndroid Build Coastguard Worker         return(NULL);
942*7c568831SAndroid Build Coastguard Worker 
943*7c568831SAndroid Build Coastguard Worker     hashValue = xmlHashQNameValue(hash->randomSeed, prefix, name, prefix2,
944*7c568831SAndroid Build Coastguard Worker                                   name2, prefix3, name3);
945*7c568831SAndroid Build Coastguard Worker     mask = hash->size - 1;
946*7c568831SAndroid Build Coastguard Worker     pos = hashValue & mask;
947*7c568831SAndroid Build Coastguard Worker     entry = &hash->table[pos];
948*7c568831SAndroid Build Coastguard Worker 
949*7c568831SAndroid Build Coastguard Worker     if (entry->hashValue != 0) {
950*7c568831SAndroid Build Coastguard Worker         displ = 0;
951*7c568831SAndroid Build Coastguard Worker         hashValue |= MAX_HASH_SIZE;
952*7c568831SAndroid Build Coastguard Worker 
953*7c568831SAndroid Build Coastguard Worker         do {
954*7c568831SAndroid Build Coastguard Worker             if ((hashValue == entry->hashValue) &&
955*7c568831SAndroid Build Coastguard Worker                 (xmlStrQEqual(prefix, name, entry->key)) &&
956*7c568831SAndroid Build Coastguard Worker                 (xmlStrQEqual(prefix2, name2, entry->key2)) &&
957*7c568831SAndroid Build Coastguard Worker                 (xmlStrQEqual(prefix3, name3, entry->key3)))
958*7c568831SAndroid Build Coastguard Worker                 return(entry->payload);
959*7c568831SAndroid Build Coastguard Worker 
960*7c568831SAndroid Build Coastguard Worker             displ++;
961*7c568831SAndroid Build Coastguard Worker             pos++;
962*7c568831SAndroid Build Coastguard Worker             entry++;
963*7c568831SAndroid Build Coastguard Worker             if ((pos & mask) == 0)
964*7c568831SAndroid Build Coastguard Worker                 entry = hash->table;
965*7c568831SAndroid Build Coastguard Worker         } while ((entry->hashValue != 0) &&
966*7c568831SAndroid Build Coastguard Worker                  (((pos - entry->hashValue) & mask) >= displ));
967*7c568831SAndroid Build Coastguard Worker     }
968*7c568831SAndroid Build Coastguard Worker 
969*7c568831SAndroid Build Coastguard Worker     return(NULL);
970*7c568831SAndroid Build Coastguard Worker }
971*7c568831SAndroid Build Coastguard Worker 
972*7c568831SAndroid Build Coastguard Worker typedef struct {
973*7c568831SAndroid Build Coastguard Worker     xmlHashScanner scan;
974*7c568831SAndroid Build Coastguard Worker     void *data;
975*7c568831SAndroid Build Coastguard Worker } stubData;
976*7c568831SAndroid Build Coastguard Worker 
977*7c568831SAndroid Build Coastguard Worker static void
stubHashScannerFull(void * payload,void * data,const xmlChar * key,const xmlChar * key2 ATTRIBUTE_UNUSED,const xmlChar * key3 ATTRIBUTE_UNUSED)978*7c568831SAndroid Build Coastguard Worker stubHashScannerFull(void *payload, void *data, const xmlChar *key,
979*7c568831SAndroid Build Coastguard Worker                     const xmlChar *key2 ATTRIBUTE_UNUSED,
980*7c568831SAndroid Build Coastguard Worker                     const xmlChar *key3 ATTRIBUTE_UNUSED) {
981*7c568831SAndroid Build Coastguard Worker     stubData *sdata = (stubData *) data;
982*7c568831SAndroid Build Coastguard Worker     sdata->scan(payload, sdata->data, key);
983*7c568831SAndroid Build Coastguard Worker }
984*7c568831SAndroid Build Coastguard Worker 
985*7c568831SAndroid Build Coastguard Worker /**
986*7c568831SAndroid Build Coastguard Worker  * xmlHashScan:
987*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
988*7c568831SAndroid Build Coastguard Worker  * @scan: scanner function for items in the hash
989*7c568831SAndroid Build Coastguard Worker  * @data: extra data passed to @scan
990*7c568831SAndroid Build Coastguard Worker  *
991*7c568831SAndroid Build Coastguard Worker  * Scan the hash @table and apply @scan to each value.
992*7c568831SAndroid Build Coastguard Worker  */
993*7c568831SAndroid Build Coastguard Worker void
xmlHashScan(xmlHashTablePtr hash,xmlHashScanner scan,void * data)994*7c568831SAndroid Build Coastguard Worker xmlHashScan(xmlHashTablePtr hash, xmlHashScanner scan, void *data) {
995*7c568831SAndroid Build Coastguard Worker     stubData sdata;
996*7c568831SAndroid Build Coastguard Worker     sdata.data = data;
997*7c568831SAndroid Build Coastguard Worker     sdata.scan = scan;
998*7c568831SAndroid Build Coastguard Worker     xmlHashScanFull(hash, stubHashScannerFull, &sdata);
999*7c568831SAndroid Build Coastguard Worker }
1000*7c568831SAndroid Build Coastguard Worker 
1001*7c568831SAndroid Build Coastguard Worker /**
1002*7c568831SAndroid Build Coastguard Worker  * xmlHashScanFull:
1003*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
1004*7c568831SAndroid Build Coastguard Worker  * @scan: scanner function for items in the hash
1005*7c568831SAndroid Build Coastguard Worker  * @data: extra data passed to @scan
1006*7c568831SAndroid Build Coastguard Worker  *
1007*7c568831SAndroid Build Coastguard Worker  * Scan the hash @table and apply @scan to each value.
1008*7c568831SAndroid Build Coastguard Worker  */
1009*7c568831SAndroid Build Coastguard Worker void
xmlHashScanFull(xmlHashTablePtr hash,xmlHashScannerFull scan,void * data)1010*7c568831SAndroid Build Coastguard Worker xmlHashScanFull(xmlHashTablePtr hash, xmlHashScannerFull scan, void *data) {
1011*7c568831SAndroid Build Coastguard Worker     const xmlHashEntry *entry, *end;
1012*7c568831SAndroid Build Coastguard Worker     xmlHashEntry old;
1013*7c568831SAndroid Build Coastguard Worker     unsigned i;
1014*7c568831SAndroid Build Coastguard Worker 
1015*7c568831SAndroid Build Coastguard Worker     if ((hash == NULL) || (hash->size == 0) || (scan == NULL))
1016*7c568831SAndroid Build Coastguard Worker         return;
1017*7c568831SAndroid Build Coastguard Worker 
1018*7c568831SAndroid Build Coastguard Worker     /*
1019*7c568831SAndroid Build Coastguard Worker      * We must handle the case that a scanned entry is removed when executing
1020*7c568831SAndroid Build Coastguard Worker      * the callback (xmlCleanSpecialAttr and possibly other places).
1021*7c568831SAndroid Build Coastguard Worker      *
1022*7c568831SAndroid Build Coastguard Worker      * Find the start of a probe sequence to avoid scanning entries twice if
1023*7c568831SAndroid Build Coastguard Worker      * a deletion happens.
1024*7c568831SAndroid Build Coastguard Worker      */
1025*7c568831SAndroid Build Coastguard Worker     entry = hash->table;
1026*7c568831SAndroid Build Coastguard Worker     end = &hash->table[hash->size];
1027*7c568831SAndroid Build Coastguard Worker     while (entry->hashValue != 0) {
1028*7c568831SAndroid Build Coastguard Worker         if (++entry >= end)
1029*7c568831SAndroid Build Coastguard Worker             entry = hash->table;
1030*7c568831SAndroid Build Coastguard Worker     }
1031*7c568831SAndroid Build Coastguard Worker 
1032*7c568831SAndroid Build Coastguard Worker     for (i = 0; i < hash->size; i++) {
1033*7c568831SAndroid Build Coastguard Worker         if ((entry->hashValue != 0) && (entry->payload != NULL)) {
1034*7c568831SAndroid Build Coastguard Worker             /*
1035*7c568831SAndroid Build Coastguard Worker              * Make sure to rescan after a possible deletion.
1036*7c568831SAndroid Build Coastguard Worker              */
1037*7c568831SAndroid Build Coastguard Worker             do {
1038*7c568831SAndroid Build Coastguard Worker                 old = *entry;
1039*7c568831SAndroid Build Coastguard Worker                 scan(entry->payload, data, entry->key, entry->key2, entry->key3);
1040*7c568831SAndroid Build Coastguard Worker             } while ((entry->hashValue != 0) &&
1041*7c568831SAndroid Build Coastguard Worker                      (entry->payload != NULL) &&
1042*7c568831SAndroid Build Coastguard Worker                      ((entry->key != old.key) ||
1043*7c568831SAndroid Build Coastguard Worker                       (entry->key2 != old.key2) ||
1044*7c568831SAndroid Build Coastguard Worker                       (entry->key3 != old.key3)));
1045*7c568831SAndroid Build Coastguard Worker         }
1046*7c568831SAndroid Build Coastguard Worker         if (++entry >= end)
1047*7c568831SAndroid Build Coastguard Worker             entry = hash->table;
1048*7c568831SAndroid Build Coastguard Worker     }
1049*7c568831SAndroid Build Coastguard Worker }
1050*7c568831SAndroid Build Coastguard Worker 
1051*7c568831SAndroid Build Coastguard Worker /**
1052*7c568831SAndroid Build Coastguard Worker  * xmlHashScan3:
1053*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
1054*7c568831SAndroid Build Coastguard Worker  * @key: first string key or NULL
1055*7c568831SAndroid Build Coastguard Worker  * @key2: second string key or NULL
1056*7c568831SAndroid Build Coastguard Worker  * @key3: third string key or NULL
1057*7c568831SAndroid Build Coastguard Worker  * @scan: scanner function for items in the hash
1058*7c568831SAndroid Build Coastguard Worker  * @data: extra data passed to @scan
1059*7c568831SAndroid Build Coastguard Worker  *
1060*7c568831SAndroid Build Coastguard Worker  * Scan the hash @table and apply @scan to each value matching
1061*7c568831SAndroid Build Coastguard Worker  * (@key, @key2, @key3) tuple. If one of the keys is null,
1062*7c568831SAndroid Build Coastguard Worker  * the comparison is considered to match.
1063*7c568831SAndroid Build Coastguard Worker  */
1064*7c568831SAndroid Build Coastguard Worker void
xmlHashScan3(xmlHashTablePtr hash,const xmlChar * key,const xmlChar * key2,const xmlChar * key3,xmlHashScanner scan,void * data)1065*7c568831SAndroid Build Coastguard Worker xmlHashScan3(xmlHashTablePtr hash, const xmlChar *key,
1066*7c568831SAndroid Build Coastguard Worker              const xmlChar *key2, const xmlChar *key3,
1067*7c568831SAndroid Build Coastguard Worker              xmlHashScanner scan, void *data) {
1068*7c568831SAndroid Build Coastguard Worker     stubData sdata;
1069*7c568831SAndroid Build Coastguard Worker     sdata.data = data;
1070*7c568831SAndroid Build Coastguard Worker     sdata.scan = scan;
1071*7c568831SAndroid Build Coastguard Worker     xmlHashScanFull3(hash, key, key2, key3, stubHashScannerFull, &sdata);
1072*7c568831SAndroid Build Coastguard Worker }
1073*7c568831SAndroid Build Coastguard Worker 
1074*7c568831SAndroid Build Coastguard Worker /**
1075*7c568831SAndroid Build Coastguard Worker  * xmlHashScanFull3:
1076*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
1077*7c568831SAndroid Build Coastguard Worker  * @key: first string key or NULL
1078*7c568831SAndroid Build Coastguard Worker  * @key2: second string key or NULL
1079*7c568831SAndroid Build Coastguard Worker  * @key3: third string key or NULL
1080*7c568831SAndroid Build Coastguard Worker  * @scan: scanner function for items in the hash
1081*7c568831SAndroid Build Coastguard Worker  * @data: extra data passed to @scan
1082*7c568831SAndroid Build Coastguard Worker  *
1083*7c568831SAndroid Build Coastguard Worker  * Scan the hash @table and apply @scan to each value matching
1084*7c568831SAndroid Build Coastguard Worker  * (@key, @key2, @key3) tuple. If one of the keys is null,
1085*7c568831SAndroid Build Coastguard Worker  * the comparison is considered to match.
1086*7c568831SAndroid Build Coastguard Worker  */
1087*7c568831SAndroid Build Coastguard Worker void
xmlHashScanFull3(xmlHashTablePtr hash,const xmlChar * key,const xmlChar * key2,const xmlChar * key3,xmlHashScannerFull scan,void * data)1088*7c568831SAndroid Build Coastguard Worker xmlHashScanFull3(xmlHashTablePtr hash, const xmlChar *key,
1089*7c568831SAndroid Build Coastguard Worker                  const xmlChar *key2, const xmlChar *key3,
1090*7c568831SAndroid Build Coastguard Worker                  xmlHashScannerFull scan, void *data) {
1091*7c568831SAndroid Build Coastguard Worker     const xmlHashEntry *entry, *end;
1092*7c568831SAndroid Build Coastguard Worker     xmlHashEntry old;
1093*7c568831SAndroid Build Coastguard Worker     unsigned i;
1094*7c568831SAndroid Build Coastguard Worker 
1095*7c568831SAndroid Build Coastguard Worker     if ((hash == NULL) || (hash->size == 0) || (scan == NULL))
1096*7c568831SAndroid Build Coastguard Worker         return;
1097*7c568831SAndroid Build Coastguard Worker 
1098*7c568831SAndroid Build Coastguard Worker     /*
1099*7c568831SAndroid Build Coastguard Worker      * We must handle the case that a scanned entry is removed when executing
1100*7c568831SAndroid Build Coastguard Worker      * the callback (xmlCleanSpecialAttr and possibly other places).
1101*7c568831SAndroid Build Coastguard Worker      *
1102*7c568831SAndroid Build Coastguard Worker      * Find the start of a probe sequence to avoid scanning entries twice if
1103*7c568831SAndroid Build Coastguard Worker      * a deletion happens.
1104*7c568831SAndroid Build Coastguard Worker      */
1105*7c568831SAndroid Build Coastguard Worker     entry = hash->table;
1106*7c568831SAndroid Build Coastguard Worker     end = &hash->table[hash->size];
1107*7c568831SAndroid Build Coastguard Worker     while (entry->hashValue != 0) {
1108*7c568831SAndroid Build Coastguard Worker         if (++entry >= end)
1109*7c568831SAndroid Build Coastguard Worker             entry = hash->table;
1110*7c568831SAndroid Build Coastguard Worker     }
1111*7c568831SAndroid Build Coastguard Worker 
1112*7c568831SAndroid Build Coastguard Worker     for (i = 0; i < hash->size; i++) {
1113*7c568831SAndroid Build Coastguard Worker         if ((entry->hashValue != 0) && (entry->payload != NULL)) {
1114*7c568831SAndroid Build Coastguard Worker             /*
1115*7c568831SAndroid Build Coastguard Worker              * Make sure to rescan after a possible deletion.
1116*7c568831SAndroid Build Coastguard Worker              */
1117*7c568831SAndroid Build Coastguard Worker             do {
1118*7c568831SAndroid Build Coastguard Worker                 if (((key != NULL) && (strcmp((const char *) key,
1119*7c568831SAndroid Build Coastguard Worker                                               (const char *) entry->key) != 0)) ||
1120*7c568831SAndroid Build Coastguard Worker                     ((key2 != NULL) && (!xmlFastStrEqual(key2, entry->key2))) ||
1121*7c568831SAndroid Build Coastguard Worker                     ((key3 != NULL) && (!xmlFastStrEqual(key3, entry->key3))))
1122*7c568831SAndroid Build Coastguard Worker                     break;
1123*7c568831SAndroid Build Coastguard Worker                 old = *entry;
1124*7c568831SAndroid Build Coastguard Worker                 scan(entry->payload, data, entry->key, entry->key2, entry->key3);
1125*7c568831SAndroid Build Coastguard Worker             } while ((entry->hashValue != 0) &&
1126*7c568831SAndroid Build Coastguard Worker                      (entry->payload != NULL) &&
1127*7c568831SAndroid Build Coastguard Worker                      ((entry->key != old.key) ||
1128*7c568831SAndroid Build Coastguard Worker                       (entry->key2 != old.key2) ||
1129*7c568831SAndroid Build Coastguard Worker                       (entry->key3 != old.key3)));
1130*7c568831SAndroid Build Coastguard Worker         }
1131*7c568831SAndroid Build Coastguard Worker         if (++entry >= end)
1132*7c568831SAndroid Build Coastguard Worker             entry = hash->table;
1133*7c568831SAndroid Build Coastguard Worker     }
1134*7c568831SAndroid Build Coastguard Worker }
1135*7c568831SAndroid Build Coastguard Worker 
1136*7c568831SAndroid Build Coastguard Worker /*
1137*7c568831SAndroid Build Coastguard Worker  * xmlHashCopySafe:
1138*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
1139*7c568831SAndroid Build Coastguard Worker  * @copyFunc: copier function for items in the hash
1140*7c568831SAndroid Build Coastguard Worker  * @deallocFunc: deallocation function in case of errors
1141*7c568831SAndroid Build Coastguard Worker  *
1142*7c568831SAndroid Build Coastguard Worker  * Copy the hash table using @copyFunc to copy payloads.
1143*7c568831SAndroid Build Coastguard Worker  *
1144*7c568831SAndroid Build Coastguard Worker  * Available since 2.13.0.
1145*7c568831SAndroid Build Coastguard Worker  *
1146*7c568831SAndroid Build Coastguard Worker  * Returns the new table or NULL if a memory allocation failed.
1147*7c568831SAndroid Build Coastguard Worker  */
1148*7c568831SAndroid Build Coastguard Worker xmlHashTablePtr
xmlHashCopySafe(xmlHashTablePtr hash,xmlHashCopier copyFunc,xmlHashDeallocator deallocFunc)1149*7c568831SAndroid Build Coastguard Worker xmlHashCopySafe(xmlHashTablePtr hash, xmlHashCopier copyFunc,
1150*7c568831SAndroid Build Coastguard Worker                 xmlHashDeallocator deallocFunc) {
1151*7c568831SAndroid Build Coastguard Worker     const xmlHashEntry *entry, *end;
1152*7c568831SAndroid Build Coastguard Worker     xmlHashTablePtr ret;
1153*7c568831SAndroid Build Coastguard Worker 
1154*7c568831SAndroid Build Coastguard Worker     if ((hash == NULL) || (copyFunc == NULL))
1155*7c568831SAndroid Build Coastguard Worker         return(NULL);
1156*7c568831SAndroid Build Coastguard Worker 
1157*7c568831SAndroid Build Coastguard Worker     ret = xmlHashCreate(hash->size);
1158*7c568831SAndroid Build Coastguard Worker     if (ret == NULL)
1159*7c568831SAndroid Build Coastguard Worker         return(NULL);
1160*7c568831SAndroid Build Coastguard Worker 
1161*7c568831SAndroid Build Coastguard Worker     if (hash->size == 0)
1162*7c568831SAndroid Build Coastguard Worker         return(ret);
1163*7c568831SAndroid Build Coastguard Worker 
1164*7c568831SAndroid Build Coastguard Worker     end = &hash->table[hash->size];
1165*7c568831SAndroid Build Coastguard Worker 
1166*7c568831SAndroid Build Coastguard Worker     for (entry = hash->table; entry < end; entry++) {
1167*7c568831SAndroid Build Coastguard Worker         if (entry->hashValue != 0) {
1168*7c568831SAndroid Build Coastguard Worker             void *copy;
1169*7c568831SAndroid Build Coastguard Worker 
1170*7c568831SAndroid Build Coastguard Worker             copy = copyFunc(entry->payload, entry->key);
1171*7c568831SAndroid Build Coastguard Worker             if (copy == NULL)
1172*7c568831SAndroid Build Coastguard Worker                 goto error;
1173*7c568831SAndroid Build Coastguard Worker             if (xmlHashAdd3(ret, entry->key, entry->key2, entry->key3,
1174*7c568831SAndroid Build Coastguard Worker                             copy) <= 0) {
1175*7c568831SAndroid Build Coastguard Worker                 if (deallocFunc != NULL)
1176*7c568831SAndroid Build Coastguard Worker                     deallocFunc(copy, entry->key);
1177*7c568831SAndroid Build Coastguard Worker                 goto error;
1178*7c568831SAndroid Build Coastguard Worker             }
1179*7c568831SAndroid Build Coastguard Worker         }
1180*7c568831SAndroid Build Coastguard Worker     }
1181*7c568831SAndroid Build Coastguard Worker 
1182*7c568831SAndroid Build Coastguard Worker     return(ret);
1183*7c568831SAndroid Build Coastguard Worker 
1184*7c568831SAndroid Build Coastguard Worker error:
1185*7c568831SAndroid Build Coastguard Worker     xmlHashFree(ret, deallocFunc);
1186*7c568831SAndroid Build Coastguard Worker     return(NULL);
1187*7c568831SAndroid Build Coastguard Worker }
1188*7c568831SAndroid Build Coastguard Worker 
1189*7c568831SAndroid Build Coastguard Worker /*
1190*7c568831SAndroid Build Coastguard Worker  * xmlHashCopy:
1191*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
1192*7c568831SAndroid Build Coastguard Worker  * @copy: copier function for items in the hash
1193*7c568831SAndroid Build Coastguard Worker  *
1194*7c568831SAndroid Build Coastguard Worker  * DEPRECATED: Leaks memory in error case.
1195*7c568831SAndroid Build Coastguard Worker  *
1196*7c568831SAndroid Build Coastguard Worker  * Copy the hash table using @copy to copy payloads.
1197*7c568831SAndroid Build Coastguard Worker  *
1198*7c568831SAndroid Build Coastguard Worker  * Returns the new table or NULL if a memory allocation failed.
1199*7c568831SAndroid Build Coastguard Worker  */
1200*7c568831SAndroid Build Coastguard Worker xmlHashTablePtr
xmlHashCopy(xmlHashTablePtr hash,xmlHashCopier copy)1201*7c568831SAndroid Build Coastguard Worker xmlHashCopy(xmlHashTablePtr hash, xmlHashCopier copy) {
1202*7c568831SAndroid Build Coastguard Worker     return(xmlHashCopySafe(hash, copy, NULL));
1203*7c568831SAndroid Build Coastguard Worker }
1204*7c568831SAndroid Build Coastguard Worker 
1205*7c568831SAndroid Build Coastguard Worker /**
1206*7c568831SAndroid Build Coastguard Worker  * xmlHashSize:
1207*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
1208*7c568831SAndroid Build Coastguard Worker  *
1209*7c568831SAndroid Build Coastguard Worker  * Query the number of elements in the hash table.
1210*7c568831SAndroid Build Coastguard Worker  *
1211*7c568831SAndroid Build Coastguard Worker  * Returns the number of elements in the hash table or
1212*7c568831SAndroid Build Coastguard Worker  * -1 in case of error.
1213*7c568831SAndroid Build Coastguard Worker  */
1214*7c568831SAndroid Build Coastguard Worker int
xmlHashSize(xmlHashTablePtr hash)1215*7c568831SAndroid Build Coastguard Worker xmlHashSize(xmlHashTablePtr hash) {
1216*7c568831SAndroid Build Coastguard Worker     if (hash == NULL)
1217*7c568831SAndroid Build Coastguard Worker         return(-1);
1218*7c568831SAndroid Build Coastguard Worker     return(hash->nbElems);
1219*7c568831SAndroid Build Coastguard Worker }
1220*7c568831SAndroid Build Coastguard Worker 
1221*7c568831SAndroid Build Coastguard Worker /**
1222*7c568831SAndroid Build Coastguard Worker  * xmlHashRemoveEntry:
1223*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
1224*7c568831SAndroid Build Coastguard Worker  * @key: string key
1225*7c568831SAndroid Build Coastguard Worker  * @dealloc: deallocator function for removed item or NULL
1226*7c568831SAndroid Build Coastguard Worker  *
1227*7c568831SAndroid Build Coastguard Worker  * Find the entry specified by the @key and remove it from the hash table.
1228*7c568831SAndroid Build Coastguard Worker  * Payload will be freed with @dealloc.
1229*7c568831SAndroid Build Coastguard Worker  *
1230*7c568831SAndroid Build Coastguard Worker  * Returns 0 on success and -1 if no entry was found.
1231*7c568831SAndroid Build Coastguard Worker  */
xmlHashRemoveEntry(xmlHashTablePtr hash,const xmlChar * key,xmlHashDeallocator dealloc)1232*7c568831SAndroid Build Coastguard Worker int xmlHashRemoveEntry(xmlHashTablePtr hash, const xmlChar *key,
1233*7c568831SAndroid Build Coastguard Worker                        xmlHashDeallocator dealloc) {
1234*7c568831SAndroid Build Coastguard Worker     return(xmlHashRemoveEntry3(hash, key, NULL, NULL, dealloc));
1235*7c568831SAndroid Build Coastguard Worker }
1236*7c568831SAndroid Build Coastguard Worker 
1237*7c568831SAndroid Build Coastguard Worker /**
1238*7c568831SAndroid Build Coastguard Worker  * xmlHashRemoveEntry2:
1239*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
1240*7c568831SAndroid Build Coastguard Worker  * @key: first string key
1241*7c568831SAndroid Build Coastguard Worker  * @key2: second string key
1242*7c568831SAndroid Build Coastguard Worker  * @dealloc: deallocator function for removed item or NULL
1243*7c568831SAndroid Build Coastguard Worker  *
1244*7c568831SAndroid Build Coastguard Worker  * Remove an entry with two strings as key.
1245*7c568831SAndroid Build Coastguard Worker  *
1246*7c568831SAndroid Build Coastguard Worker  * See xmlHashRemoveEntry.
1247*7c568831SAndroid Build Coastguard Worker  *
1248*7c568831SAndroid Build Coastguard Worker  * Returns 0 on success and -1 in case of error.
1249*7c568831SAndroid Build Coastguard Worker  */
1250*7c568831SAndroid Build Coastguard Worker int
xmlHashRemoveEntry2(xmlHashTablePtr hash,const xmlChar * key,const xmlChar * key2,xmlHashDeallocator dealloc)1251*7c568831SAndroid Build Coastguard Worker xmlHashRemoveEntry2(xmlHashTablePtr hash, const xmlChar *key,
1252*7c568831SAndroid Build Coastguard Worker                     const xmlChar *key2, xmlHashDeallocator dealloc) {
1253*7c568831SAndroid Build Coastguard Worker     return(xmlHashRemoveEntry3(hash, key, key2, NULL, dealloc));
1254*7c568831SAndroid Build Coastguard Worker }
1255*7c568831SAndroid Build Coastguard Worker 
1256*7c568831SAndroid Build Coastguard Worker /**
1257*7c568831SAndroid Build Coastguard Worker  * xmlHashRemoveEntry3:
1258*7c568831SAndroid Build Coastguard Worker  * @hash: hash table
1259*7c568831SAndroid Build Coastguard Worker  * @key: first string key
1260*7c568831SAndroid Build Coastguard Worker  * @key2: second string key
1261*7c568831SAndroid Build Coastguard Worker  * @key3: third string key
1262*7c568831SAndroid Build Coastguard Worker  * @dealloc: deallocator function for removed item or NULL
1263*7c568831SAndroid Build Coastguard Worker  *
1264*7c568831SAndroid Build Coastguard Worker  * Remove an entry with three strings as key.
1265*7c568831SAndroid Build Coastguard Worker  *
1266*7c568831SAndroid Build Coastguard Worker  * See xmlHashRemoveEntry.
1267*7c568831SAndroid Build Coastguard Worker  *
1268*7c568831SAndroid Build Coastguard Worker  * Returns 0 on success and -1 in case of error.
1269*7c568831SAndroid Build Coastguard Worker  */
1270*7c568831SAndroid Build Coastguard Worker ATTRIBUTE_NO_SANITIZE_INTEGER
1271*7c568831SAndroid Build Coastguard Worker int
xmlHashRemoveEntry3(xmlHashTablePtr hash,const xmlChar * key,const xmlChar * key2,const xmlChar * key3,xmlHashDeallocator dealloc)1272*7c568831SAndroid Build Coastguard Worker xmlHashRemoveEntry3(xmlHashTablePtr hash, const xmlChar *key,
1273*7c568831SAndroid Build Coastguard Worker                     const xmlChar *key2, const xmlChar *key3,
1274*7c568831SAndroid Build Coastguard Worker                     xmlHashDeallocator dealloc) {
1275*7c568831SAndroid Build Coastguard Worker     xmlHashEntry *entry, *cur, *next;
1276*7c568831SAndroid Build Coastguard Worker     unsigned hashValue, mask, pos, nextpos;
1277*7c568831SAndroid Build Coastguard Worker     int found;
1278*7c568831SAndroid Build Coastguard Worker 
1279*7c568831SAndroid Build Coastguard Worker     if ((hash == NULL) || (hash->size == 0) || (key == NULL))
1280*7c568831SAndroid Build Coastguard Worker         return(-1);
1281*7c568831SAndroid Build Coastguard Worker 
1282*7c568831SAndroid Build Coastguard Worker     hashValue = xmlHashValue(hash->randomSeed, key, key2, key3, NULL);
1283*7c568831SAndroid Build Coastguard Worker     entry = xmlHashFindEntry(hash, key, key2, key3, hashValue, &found);
1284*7c568831SAndroid Build Coastguard Worker     if (!found)
1285*7c568831SAndroid Build Coastguard Worker         return(-1);
1286*7c568831SAndroid Build Coastguard Worker 
1287*7c568831SAndroid Build Coastguard Worker     if ((dealloc != NULL) && (entry->payload != NULL))
1288*7c568831SAndroid Build Coastguard Worker         dealloc(entry->payload, entry->key);
1289*7c568831SAndroid Build Coastguard Worker     if (hash->dict == NULL) {
1290*7c568831SAndroid Build Coastguard Worker         if (entry->key)
1291*7c568831SAndroid Build Coastguard Worker             xmlFree(entry->key);
1292*7c568831SAndroid Build Coastguard Worker         if (entry->key2)
1293*7c568831SAndroid Build Coastguard Worker             xmlFree(entry->key2);
1294*7c568831SAndroid Build Coastguard Worker         if (entry->key3)
1295*7c568831SAndroid Build Coastguard Worker             xmlFree(entry->key3);
1296*7c568831SAndroid Build Coastguard Worker     }
1297*7c568831SAndroid Build Coastguard Worker 
1298*7c568831SAndroid Build Coastguard Worker     /*
1299*7c568831SAndroid Build Coastguard Worker      * Find end of probe sequence. Entries at their initial probe
1300*7c568831SAndroid Build Coastguard Worker      * position start a new sequence.
1301*7c568831SAndroid Build Coastguard Worker      */
1302*7c568831SAndroid Build Coastguard Worker     mask = hash->size - 1;
1303*7c568831SAndroid Build Coastguard Worker     pos = entry - hash->table;
1304*7c568831SAndroid Build Coastguard Worker     cur = entry;
1305*7c568831SAndroid Build Coastguard Worker 
1306*7c568831SAndroid Build Coastguard Worker     while (1) {
1307*7c568831SAndroid Build Coastguard Worker         nextpos = pos + 1;
1308*7c568831SAndroid Build Coastguard Worker         next = cur + 1;
1309*7c568831SAndroid Build Coastguard Worker         if ((nextpos & mask) == 0)
1310*7c568831SAndroid Build Coastguard Worker             next = hash->table;
1311*7c568831SAndroid Build Coastguard Worker 
1312*7c568831SAndroid Build Coastguard Worker         if ((next->hashValue == 0) ||
1313*7c568831SAndroid Build Coastguard Worker             (((next->hashValue - nextpos) & mask) == 0))
1314*7c568831SAndroid Build Coastguard Worker             break;
1315*7c568831SAndroid Build Coastguard Worker 
1316*7c568831SAndroid Build Coastguard Worker         cur = next;
1317*7c568831SAndroid Build Coastguard Worker         pos = nextpos;
1318*7c568831SAndroid Build Coastguard Worker     }
1319*7c568831SAndroid Build Coastguard Worker 
1320*7c568831SAndroid Build Coastguard Worker     /*
1321*7c568831SAndroid Build Coastguard Worker      * Backward shift
1322*7c568831SAndroid Build Coastguard Worker      */
1323*7c568831SAndroid Build Coastguard Worker     next = entry + 1;
1324*7c568831SAndroid Build Coastguard Worker 
1325*7c568831SAndroid Build Coastguard Worker     if (cur < entry) {
1326*7c568831SAndroid Build Coastguard Worker         xmlHashEntry *end = &hash->table[hash->size];
1327*7c568831SAndroid Build Coastguard Worker 
1328*7c568831SAndroid Build Coastguard Worker         memmove(entry, next, (char *) end - (char *) next);
1329*7c568831SAndroid Build Coastguard Worker         entry = hash->table;
1330*7c568831SAndroid Build Coastguard Worker         end[-1] = *entry;
1331*7c568831SAndroid Build Coastguard Worker         next = entry + 1;
1332*7c568831SAndroid Build Coastguard Worker     }
1333*7c568831SAndroid Build Coastguard Worker 
1334*7c568831SAndroid Build Coastguard Worker     memmove(entry, next, (char *) cur - (char *) entry);
1335*7c568831SAndroid Build Coastguard Worker 
1336*7c568831SAndroid Build Coastguard Worker     /*
1337*7c568831SAndroid Build Coastguard Worker      * Update entry
1338*7c568831SAndroid Build Coastguard Worker      */
1339*7c568831SAndroid Build Coastguard Worker     cur->hashValue = 0;
1340*7c568831SAndroid Build Coastguard Worker 
1341*7c568831SAndroid Build Coastguard Worker     hash->nbElems--;
1342*7c568831SAndroid Build Coastguard Worker 
1343*7c568831SAndroid Build Coastguard Worker     return(0);
1344*7c568831SAndroid Build Coastguard Worker }
1345*7c568831SAndroid Build Coastguard Worker 
1346