blob: 0e07e8dcbea3ead36d45e97ea04b4914e7506dcb [file] [log] [blame]
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001/*
2 * dict.c: dictionary of reusable strings, just used to avoid allocation
3 * and freeing operations.
4 *
5 * Copyright (C) 2003 Daniel Veillard.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
13 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
15 *
16 * Author: daniel@veillard.com
17 */
18
19#define IN_LIBXML
20#include "libxml.h"
21
22#include <string.h>
Rob Richardsb6b2ee12008-05-03 12:34:25 +000023#ifdef HAVE_STDINT_H
Daniel Veillarde9100a52008-04-22 08:28:50 +000024#include <stdint.h>
Daniel Veillard7f4547c2008-10-03 07:58:23 +000025#else
26#ifdef HAVE_INTTYPES_H
27#include <inttypes.h>
Rob Richardsb6b2ee12008-05-03 12:34:25 +000028#elif defined(WIN32)
29typedef unsigned __int32 uint32_t;
Rob Richardsb6b2ee12008-05-03 12:34:25 +000030#endif
Daniel Veillard7f4547c2008-10-03 07:58:23 +000031#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +000032#include <libxml/tree.h>
33#include <libxml/dict.h>
34#include <libxml/xmlmemory.h>
35#include <libxml/xmlerror.h>
36#include <libxml/globals.h>
37
Daniel Veillard424785e2008-08-06 09:35:25 +000038/* #define DEBUG_GROW */
39/* #define DICT_DEBUG_PATTERNS */
40
Daniel Veillarde9100a52008-04-22 08:28:50 +000041#define MAX_HASH_LEN 3
Daniel Veillard2fdbd322003-08-18 12:15:38 +000042#define MIN_DICT_SIZE 128
43#define MAX_DICT_HASH 8 * 2048
Daniel Veillard424785e2008-08-06 09:35:25 +000044#define WITH_BIG_KEY
Daniel Veillard2fdbd322003-08-18 12:15:38 +000045
Daniel Veillard424785e2008-08-06 09:35:25 +000046#ifdef WITH_BIG_KEY
47#define xmlDictComputeKey(dict, name, len) \
48 (((dict)->size == MIN_DICT_SIZE) ? \
49 xmlDictComputeFastKey(name, len) : \
50 xmlDictComputeBigKey(name, len))
Daniel Veillarde9100a52008-04-22 08:28:50 +000051
Daniel Veillardffda65f2008-08-07 16:33:49 +000052#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
Daniel Veillard424785e2008-08-06 09:35:25 +000053 (((prefix) == NULL) ? \
54 (xmlDictComputeKey(dict, name, len)) : \
55 (((dict)->size == MIN_DICT_SIZE) ? \
Daniel Veillardffda65f2008-08-07 16:33:49 +000056 xmlDictComputeFastQKey(prefix, plen, name, len) : \
57 xmlDictComputeBigQKey(prefix, plen, name, len)))
Daniel Veillarde9100a52008-04-22 08:28:50 +000058
Daniel Veillard424785e2008-08-06 09:35:25 +000059#else /* !WITH_BIG_KEY */
60#define xmlDictComputeKey(dict, name, len) \
61 xmlDictComputeFastKey(name, len)
Daniel Veillardffda65f2008-08-07 16:33:49 +000062#define xmlDictComputeQKey(dict, prefix, plen, name, len) \
63 xmlDictComputeFastQKey(prefix, plen, name, len)
Daniel Veillard424785e2008-08-06 09:35:25 +000064#endif /* WITH_BIG_KEY */
Daniel Veillard2fdbd322003-08-18 12:15:38 +000065
66/*
67 * An entry in the dictionnary
68 */
69typedef struct _xmlDictEntry xmlDictEntry;
70typedef xmlDictEntry *xmlDictEntryPtr;
71struct _xmlDictEntry {
72 struct _xmlDictEntry *next;
Daniel Veillard81514ba2003-09-16 23:17:26 +000073 const xmlChar *name;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000074 int len;
75 int valid;
Daniel Veillardd68f8912008-08-08 10:09:19 +000076 unsigned long okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000077};
78
Daniel Veillard81514ba2003-09-16 23:17:26 +000079typedef struct _xmlDictStrings xmlDictStrings;
80typedef xmlDictStrings *xmlDictStringsPtr;
81struct _xmlDictStrings {
82 xmlDictStringsPtr next;
83 xmlChar *free;
84 xmlChar *end;
85 int size;
86 int nbStrings;
87 xmlChar array[1];
88};
Daniel Veillard2fdbd322003-08-18 12:15:38 +000089/*
90 * The entire dictionnary
91 */
92struct _xmlDict {
Daniel Veillarde96a2a42003-09-24 21:23:56 +000093 int ref_counter;
94
Daniel Veillard2fdbd322003-08-18 12:15:38 +000095 struct _xmlDictEntry *dict;
96 int size;
97 int nbElems;
Daniel Veillard81514ba2003-09-16 23:17:26 +000098 xmlDictStringsPtr strings;
Daniel Veillard4773df22004-01-23 13:15:13 +000099
100 struct _xmlDict *subdict;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000101};
102
103/*
Daniel Veillard14412512005-01-21 23:53:26 +0000104 * A mutex for modifying the reference counter for shared
105 * dictionaries.
106 */
107static xmlRMutexPtr xmlDictMutex = NULL;
108
109/*
110 * Whether the dictionary mutex was initialized.
111 */
112static int xmlDictInitialized = 0;
113
114/**
William M. Brack4e1c2db2005-02-11 10:58:55 +0000115 * xmlInitializeDict:
Daniel Veillard14412512005-01-21 23:53:26 +0000116 *
117 * Do the dictionary mutex initialization.
118 * this function is not thread safe, initialization should
119 * preferably be done once at startup
120 */
William M. Brack4e1c2db2005-02-11 10:58:55 +0000121static int xmlInitializeDict(void) {
Daniel Veillard14412512005-01-21 23:53:26 +0000122 if (xmlDictInitialized)
123 return(1);
124
125 if ((xmlDictMutex = xmlNewRMutex()) == NULL)
126 return(0);
127
128 xmlDictInitialized = 1;
129 return(1);
130}
131
132/**
Daniel Veillard2ae13382005-01-25 23:45:06 +0000133 * xmlDictCleanup:
Daniel Veillard14412512005-01-21 23:53:26 +0000134 *
135 * Free the dictionary mutex.
136 */
137void
138xmlDictCleanup(void) {
139 if (!xmlDictInitialized)
140 return;
141
142 xmlFreeRMutex(xmlDictMutex);
143
144 xmlDictInitialized = 0;
145}
146
147/*
Daniel Veillard81514ba2003-09-16 23:17:26 +0000148 * xmlDictAddString:
149 * @dict: the dictionnary
150 * @name: the name of the userdata
151 * @len: the length of the name, if -1 it is recomputed
152 *
153 * Add the string to the array[s]
154 *
155 * Returns the pointer of the local string, or NULL in case of error.
156 */
157static const xmlChar *
158xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
159 xmlDictStringsPtr pool;
160 const xmlChar *ret;
161 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
162
Daniel Veillard424785e2008-08-06 09:35:25 +0000163#ifdef DICT_DEBUG_PATTERNS
164 fprintf(stderr, "-");
165#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000166 pool = dict->strings;
167 while (pool != NULL) {
168 if (pool->end - pool->free > namelen)
169 goto found_pool;
170 if (pool->size > size) size = pool->size;
171 pool = pool->next;
172 }
173 /*
174 * Not found, need to allocate
175 */
176 if (pool == NULL) {
177 if (size == 0) size = 1000;
178 else size *= 4; /* exponential growth */
179 if (size < 4 * namelen)
180 size = 4 * namelen; /* just in case ! */
181 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
182 if (pool == NULL)
183 return(NULL);
184 pool->size = size;
185 pool->nbStrings = 0;
186 pool->free = &pool->array[0];
187 pool->end = &pool->array[size];
188 pool->next = dict->strings;
189 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000190#ifdef DICT_DEBUG_PATTERNS
191 fprintf(stderr, "+");
192#endif
Daniel Veillard81514ba2003-09-16 23:17:26 +0000193 }
194found_pool:
195 ret = pool->free;
196 memcpy(pool->free, name, namelen);
197 pool->free += namelen;
198 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000199 pool->nbStrings++;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000200 return(ret);
201}
202
203/*
Daniel Veillarde72c5082003-09-19 12:44:05 +0000204 * xmlDictAddQString:
205 * @dict: the dictionnary
206 * @prefix: the prefix of the userdata
Daniel Veillardffda65f2008-08-07 16:33:49 +0000207 * @plen: the prefix length
Daniel Veillarde72c5082003-09-19 12:44:05 +0000208 * @name: the name of the userdata
209 * @len: the length of the name, if -1 it is recomputed
210 *
211 * Add the QName to the array[s]
212 *
213 * Returns the pointer of the local string, or NULL in case of error.
214 */
215static const xmlChar *
Daniel Veillardffda65f2008-08-07 16:33:49 +0000216xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen,
Daniel Veillarde72c5082003-09-19 12:44:05 +0000217 const xmlChar *name, int namelen)
218{
219 xmlDictStringsPtr pool;
220 const xmlChar *ret;
221 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000222
223 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
Daniel Veillarde72c5082003-09-19 12:44:05 +0000224
Daniel Veillard424785e2008-08-06 09:35:25 +0000225#ifdef DICT_DEBUG_PATTERNS
226 fprintf(stderr, "=");
227#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000228 pool = dict->strings;
229 while (pool != NULL) {
Daniel Veillardffda65f2008-08-07 16:33:49 +0000230 if (pool->end - pool->free > namelen + plen + 1)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000231 goto found_pool;
232 if (pool->size > size) size = pool->size;
233 pool = pool->next;
234 }
235 /*
236 * Not found, need to allocate
237 */
238 if (pool == NULL) {
239 if (size == 0) size = 1000;
240 else size *= 4; /* exponential growth */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000241 if (size < 4 * (namelen + plen + 1))
242 size = 4 * (namelen + plen + 1); /* just in case ! */
Daniel Veillarde72c5082003-09-19 12:44:05 +0000243 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
244 if (pool == NULL)
245 return(NULL);
246 pool->size = size;
247 pool->nbStrings = 0;
248 pool->free = &pool->array[0];
249 pool->end = &pool->array[size];
250 pool->next = dict->strings;
251 dict->strings = pool;
Daniel Veillard424785e2008-08-06 09:35:25 +0000252#ifdef DICT_DEBUG_PATTERNS
253 fprintf(stderr, "+");
254#endif
Daniel Veillarde72c5082003-09-19 12:44:05 +0000255 }
256found_pool:
257 ret = pool->free;
258 memcpy(pool->free, prefix, plen);
259 pool->free += plen;
260 *(pool->free++) = ':';
Daniel Veillarde72c5082003-09-19 12:44:05 +0000261 memcpy(pool->free, name, namelen);
262 pool->free += namelen;
263 *(pool->free++) = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000264 pool->nbStrings++;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000265 return(ret);
266}
267
Daniel Veillard424785e2008-08-06 09:35:25 +0000268#ifdef WITH_BIG_KEY
Daniel Veillarde72c5082003-09-19 12:44:05 +0000269/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000270 * xmlDictComputeBigKey:
271 *
272 * Calculate a hash key using a good hash function that works well for
273 * larger hash table sizes.
274 *
Daniel Veillard424785e2008-08-06 09:35:25 +0000275 * Hash function by "One-at-a-Time Hash" see
Daniel Veillarde9100a52008-04-22 08:28:50 +0000276 * http://burtleburtle.net/bob/hash/doobs.html
277 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000278
279static uint32_t
Daniel Veillard424785e2008-08-06 09:35:25 +0000280xmlDictComputeBigKey(const xmlChar* data, int namelen) {
281 uint32_t hash;
282 int i;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000283
Daniel Veillard424785e2008-08-06 09:35:25 +0000284 if (namelen <= 0 || data == NULL) return(0);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000285
Daniel Veillard424785e2008-08-06 09:35:25 +0000286 hash = 0;
Daniel Veillarde9100a52008-04-22 08:28:50 +0000287
Daniel Veillard424785e2008-08-06 09:35:25 +0000288 for (i = 0;i < namelen; i++) {
289 hash += data[i];
290 hash += (hash << 10);
291 hash ^= (hash >> 6);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000292 }
Daniel Veillard424785e2008-08-06 09:35:25 +0000293 hash += (hash << 3);
294 hash ^= (hash >> 11);
295 hash += (hash << 15);
Daniel Veillarde9100a52008-04-22 08:28:50 +0000296
297 return hash;
298}
299
300/*
Daniel Veillard424785e2008-08-06 09:35:25 +0000301 * xmlDictComputeBigQKey:
302 *
303 * Calculate a hash key for two strings using a good hash function
304 * that works well for larger hash table sizes.
305 *
306 * Hash function by "One-at-a-Time Hash" see
307 * http://burtleburtle.net/bob/hash/doobs.html
308 *
309 * Neither of the two strings must be NULL.
310 */
311static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000312xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
313 const xmlChar *name, int len)
Daniel Veillard424785e2008-08-06 09:35:25 +0000314{
315 uint32_t hash;
316 int i;
Daniel Veillard424785e2008-08-06 09:35:25 +0000317
318 hash = 0;
319
320 for (i = 0;i < plen; i++) {
321 hash += prefix[i];
322 hash += (hash << 10);
323 hash ^= (hash >> 6);
324 }
325 hash += ':';
326 hash += (hash << 10);
327 hash ^= (hash >> 6);
328
329 for (i = 0;i < len; i++) {
330 hash += name[i];
331 hash += (hash << 10);
332 hash ^= (hash >> 6);
333 }
334 hash += (hash << 3);
335 hash ^= (hash >> 11);
336 hash += (hash << 15);
337
338 return hash;
339}
340#endif /* WITH_BIG_KEY */
341
342/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000343 * xmlDictComputeFastKey:
344 *
345 * Calculate a hash key using a fast hash function that works well
346 * for low hash table fill.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000347 */
348static unsigned long
Daniel Veillarde9100a52008-04-22 08:28:50 +0000349xmlDictComputeFastKey(const xmlChar *name, int namelen) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000350 unsigned long value = 0L;
Daniel Veillard424785e2008-08-06 09:35:25 +0000351
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000352 if (name == NULL) return(0);
Daniel Veillard4773df22004-01-23 13:15:13 +0000353 value = *name;
354 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000355 if (namelen > 10) {
356 value += name[namelen - 1];
357 namelen = 10;
358 }
359 switch (namelen) {
360 case 10: value += name[9];
361 case 9: value += name[8];
362 case 8: value += name[7];
363 case 7: value += name[6];
364 case 6: value += name[5];
365 case 5: value += name[4];
366 case 4: value += name[3];
367 case 3: value += name[2];
368 case 2: value += name[1];
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000369 default: break;
370 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000371 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000372}
373
374/*
Daniel Veillarde9100a52008-04-22 08:28:50 +0000375 * xmlDictComputeFastQKey:
376 *
377 * Calculate a hash key for two strings using a fast hash function
378 * that works well for low hash table fill.
379 *
380 * Neither of the two strings must be NULL.
Daniel Veillarde72c5082003-09-19 12:44:05 +0000381 */
382static unsigned long
Daniel Veillardffda65f2008-08-07 16:33:49 +0000383xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
384 const xmlChar *name, int len)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000385{
386 unsigned long value = 0L;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000387
Daniel Veillarde72c5082003-09-19 12:44:05 +0000388 if (plen == 0)
389 value += 30 * (unsigned long) ':';
390 else
391 value += 30 * (*prefix);
Daniel Veillard424785e2008-08-06 09:35:25 +0000392
Daniel Veillarde72c5082003-09-19 12:44:05 +0000393 if (len > 10) {
394 value += name[len - (plen + 1 + 1)];
395 len = 10;
396 if (plen > 10)
397 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000398 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000399 switch (plen) {
400 case 10: value += prefix[9];
401 case 9: value += prefix[8];
402 case 8: value += prefix[7];
403 case 7: value += prefix[6];
404 case 6: value += prefix[5];
405 case 5: value += prefix[4];
406 case 4: value += prefix[3];
407 case 3: value += prefix[2];
408 case 2: value += prefix[1];
409 case 1: value += prefix[0];
410 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000411 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000412 len -= plen;
413 if (len > 0) {
414 value += (unsigned long) ':';
415 len--;
416 }
417 switch (len) {
418 case 10: value += name[9];
419 case 9: value += name[8];
420 case 8: value += name[7];
421 case 7: value += name[6];
422 case 6: value += name[5];
423 case 5: value += name[4];
424 case 4: value += name[3];
425 case 3: value += name[2];
426 case 2: value += name[1];
427 case 1: value += name[0];
428 default: break;
429 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000430 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000431}
432
433/**
434 * xmlDictCreate:
435 *
436 * Create a new dictionary
437 *
Daniel Veillard4773df22004-01-23 13:15:13 +0000438 * Returns the newly created dictionnary, or NULL if an error occured.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000439 */
440xmlDictPtr
441xmlDictCreate(void) {
442 xmlDictPtr dict;
Daniel Veillard14412512005-01-21 23:53:26 +0000443
444 if (!xmlDictInitialized)
445 if (!xmlInitializeDict())
446 return(NULL);
Daniel Veillard424785e2008-08-06 09:35:25 +0000447
448#ifdef DICT_DEBUG_PATTERNS
449 fprintf(stderr, "C");
450#endif
451
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000452 dict = xmlMalloc(sizeof(xmlDict));
453 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000454 dict->ref_counter = 1;
455
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000456 dict->size = MIN_DICT_SIZE;
457 dict->nbElems = 0;
458 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000459 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000460 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000461 if (dict->dict) {
Daniel Veillardb242b082008-02-08 09:56:31 +0000462 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
463 return(dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000464 }
465 xmlFree(dict);
466 }
467 return(NULL);
468}
469
470/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000471 * xmlDictCreateSub:
472 * @sub: an existing dictionnary
473 *
474 * Create a new dictionary, inheriting strings from the read-only
475 * dictionnary @sub. On lookup, strings are first searched in the
476 * new dictionnary, then in @sub, and if not found are created in the
477 * new dictionnary.
478 *
479 * Returns the newly created dictionnary, or NULL if an error occured.
480 */
481xmlDictPtr
482xmlDictCreateSub(xmlDictPtr sub) {
483 xmlDictPtr dict = xmlDictCreate();
Daniel Veillard424785e2008-08-06 09:35:25 +0000484
Daniel Veillard4773df22004-01-23 13:15:13 +0000485 if ((dict != NULL) && (sub != NULL)) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000486#ifdef DICT_DEBUG_PATTERNS
487 fprintf(stderr, "R");
488#endif
Daniel Veillard4773df22004-01-23 13:15:13 +0000489 dict->subdict = sub;
490 xmlDictReference(dict->subdict);
491 }
492 return(dict);
493}
494
495/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000496 * xmlDictReference:
497 * @dict: the dictionnary
498 *
499 * Increment the reference counter of a dictionary
500 *
501 * Returns 0 in case of success and -1 in case of error
502 */
503int
504xmlDictReference(xmlDictPtr dict) {
Daniel Veillard14412512005-01-21 23:53:26 +0000505 if (!xmlDictInitialized)
506 if (!xmlInitializeDict())
507 return(-1);
508
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000509 if (dict == NULL) return -1;
Daniel Veillard14412512005-01-21 23:53:26 +0000510 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000511 dict->ref_counter++;
Daniel Veillard14412512005-01-21 23:53:26 +0000512 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000513 return(0);
514}
515
516/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000517 * xmlDictGrow:
518 * @dict: the dictionnary
519 * @size: the new size of the dictionnary
520 *
521 * resize the dictionnary
522 *
523 * Returns 0 in case of success, -1 in case of failure
524 */
525static int
526xmlDictGrow(xmlDictPtr dict, int size) {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000527 unsigned long key, okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000528 int oldsize, i;
529 xmlDictEntryPtr iter, next;
530 struct _xmlDictEntry *olddict;
531#ifdef DEBUG_GROW
532 unsigned long nbElem = 0;
533#endif
Daniel Veillardffda65f2008-08-07 16:33:49 +0000534 int ret = 0;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000535 int keep_keys = 1;
Daniel Veillard424785e2008-08-06 09:35:25 +0000536
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000537 if (dict == NULL)
538 return(-1);
539 if (size < 8)
540 return(-1);
541 if (size > 8 * 2048)
542 return(-1);
543
Daniel Veillard424785e2008-08-06 09:35:25 +0000544#ifdef DICT_DEBUG_PATTERNS
545 fprintf(stderr, "*");
546#endif
547
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000548 oldsize = dict->size;
549 olddict = dict->dict;
550 if (olddict == NULL)
551 return(-1);
Daniel Veillardd68f8912008-08-08 10:09:19 +0000552 if (oldsize == MIN_DICT_SIZE)
553 keep_keys = 0;
Daniel Veillard424785e2008-08-06 09:35:25 +0000554
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000555 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
556 if (dict->dict == NULL) {
557 dict->dict = olddict;
558 return(-1);
559 }
560 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
561 dict->size = size;
562
563 /* If the two loops are merged, there would be situations where
Daniel Veillard424785e2008-08-06 09:35:25 +0000564 a new entry needs to allocated and data copied into it from
Daniel Veillardffda65f2008-08-07 16:33:49 +0000565 the main dict. It is nicer to run through the array twice, first
566 copying all the elements in the main array (less probability of
567 allocate) and then the rest, so we only free in the second loop.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000568 */
569 for (i = 0; i < oldsize; i++) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000570 if (olddict[i].valid == 0)
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000571 continue;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000572
573 if (keep_keys)
574 okey = olddict[i].okey;
575 else
576 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
577 key = okey % dict->size;
578
Daniel Veillardffda65f2008-08-07 16:33:49 +0000579 if (dict->dict[key].valid == 0) {
580 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
581 dict->dict[key].next = NULL;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000582 dict->dict[key].okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000583 } else {
584 xmlDictEntryPtr entry;
585
586 entry = xmlMalloc(sizeof(xmlDictEntry));
587 if (entry != NULL) {
588 entry->name = olddict[i].name;
589 entry->len = olddict[i].len;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000590 entry->okey = okey;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000591 entry->next = dict->dict[key].next;
592 entry->valid = 1;
593 dict->dict[key].next = entry;
594 } else {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000595 /*
596 * we don't have much ways to alert from herei
597 * result is loosing an entry and unicity garantee
598 */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000599 ret = -1;
600 }
601 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000602#ifdef DEBUG_GROW
603 nbElem++;
604#endif
605 }
606
607 for (i = 0; i < oldsize; i++) {
608 iter = olddict[i].next;
609 while (iter) {
610 next = iter->next;
611
612 /*
613 * put back the entry in the new dict
614 */
615
Daniel Veillardd68f8912008-08-08 10:09:19 +0000616 if (keep_keys)
617 okey = iter->okey;
618 else
619 okey = xmlDictComputeKey(dict, iter->name, iter->len);
620 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000621 if (dict->dict[key].valid == 0) {
622 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
623 dict->dict[key].next = NULL;
624 dict->dict[key].valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000625 dict->dict[key].okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000626 xmlFree(iter);
627 } else {
Daniel Veillard424785e2008-08-06 09:35:25 +0000628 iter->next = dict->dict[key].next;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000629 iter->okey = okey;
Daniel Veillard424785e2008-08-06 09:35:25 +0000630 dict->dict[key].next = iter;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000631 }
632
633#ifdef DEBUG_GROW
634 nbElem++;
635#endif
636
637 iter = next;
638 }
639 }
640
641 xmlFree(olddict);
642
643#ifdef DEBUG_GROW
644 xmlGenericError(xmlGenericErrorContext,
645 "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
646#endif
647
Daniel Veillardffda65f2008-08-07 16:33:49 +0000648 return(ret);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000649}
650
651/**
652 * xmlDictFree:
653 * @dict: the dictionnary
654 *
655 * Free the hash @dict and its contents. The userdata is
656 * deallocated with @f if provided.
657 */
658void
659xmlDictFree(xmlDictPtr dict) {
660 int i;
661 xmlDictEntryPtr iter;
662 xmlDictEntryPtr next;
663 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000664 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000665
666 if (dict == NULL)
667 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000668
Daniel Veillard14412512005-01-21 23:53:26 +0000669 if (!xmlDictInitialized)
670 if (!xmlInitializeDict())
671 return;
672
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000673 /* decrement the counter, it may be shared by a parser and docs */
Daniel Veillard14412512005-01-21 23:53:26 +0000674 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000675 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000676 if (dict->ref_counter > 0) {
Daniel Veillard14412512005-01-21 23:53:26 +0000677 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000678 return;
679 }
680
Daniel Veillard14412512005-01-21 23:53:26 +0000681 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000682
Daniel Veillard4773df22004-01-23 13:15:13 +0000683 if (dict->subdict != NULL) {
684 xmlDictFree(dict->subdict);
685 }
686
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000687 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000688 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000689 iter = &(dict->dict[i]);
690 if (iter->valid == 0)
691 continue;
692 inside_dict = 1;
693 while (iter) {
694 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000695 if (!inside_dict)
696 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000697 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000698 inside_dict = 0;
699 iter = next;
700 }
701 inside_dict = 0;
702 }
703 xmlFree(dict->dict);
704 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000705 pool = dict->strings;
706 while (pool != NULL) {
707 nextp = pool->next;
708 xmlFree(pool);
709 pool = nextp;
710 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000711 xmlFree(dict);
712}
713
714/**
715 * xmlDictLookup:
716 * @dict: the dictionnary
717 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000718 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000719 *
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000720 * Add the @name to the dictionnary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000721 *
722 * Returns the internal copy of the name or NULL in case of internal error
723 */
724const xmlChar *
725xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000726 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000727 xmlDictEntryPtr entry;
728 xmlDictEntryPtr insert;
729 const xmlChar *ret;
730
Daniel Veillard0fb18932003-09-07 09:14:37 +0000731 if ((dict == NULL) || (name == NULL))
732 return(NULL);
733
734 if (len < 0)
Daniel Veillardffda65f2008-08-07 16:33:49 +0000735 len = strlen((const char *) name);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000736
737 /*
738 * Check for duplicate and insertion location.
739 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000740 okey = xmlDictComputeKey(dict, name, len);
Daniel Veillard4773df22004-01-23 13:15:13 +0000741 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000742 if (dict->dict[key].valid == 0) {
743 insert = NULL;
744 } else {
745 for (insert = &(dict->dict[key]); insert->next != NULL;
746 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000747#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000748 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000749 if (!memcmp(insert->name, name, len))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000750 return(insert->name);
751 }
752#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000753 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000754 (!xmlStrncmp(insert->name, name, len)))
755 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000756#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000757 nbi++;
758 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000759#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000760 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000761 if (!memcmp(insert->name, name, len))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000762 return(insert->name);
763 }
764#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000765 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000766 (!xmlStrncmp(insert->name, name, len)))
767 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000768#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000769 }
770
Daniel Veillard4773df22004-01-23 13:15:13 +0000771 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000772 unsigned long skey;
773
774 /* we cannot always reuse the same okey for the subdict */
775 if (((dict->size == MIN_DICT_SIZE) &&
776 (dict->subdict->size != MIN_DICT_SIZE)) ||
777 ((dict->size != MIN_DICT_SIZE) &&
778 (dict->subdict->size == MIN_DICT_SIZE)))
779 skey = xmlDictComputeKey(dict->subdict, name, len);
780 else
781 skey = okey;
782
783 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +0000784 if (dict->subdict->dict[key].valid != 0) {
785 xmlDictEntryPtr tmp;
786
787 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
788 tmp = tmp->next) {
789#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000790 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000791 if (!memcmp(tmp->name, name, len))
792 return(tmp->name);
793 }
794#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000795 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +0000796 (!xmlStrncmp(tmp->name, name, len)))
797 return(tmp->name);
798#endif
799 nbi++;
800 }
801#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000802 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000803 if (!memcmp(tmp->name, name, len))
804 return(tmp->name);
805 }
806#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000807 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +0000808 (!xmlStrncmp(tmp->name, name, len)))
809 return(tmp->name);
810#endif
811 }
812 key = okey % dict->size;
813 }
814
Daniel Veillard81514ba2003-09-16 23:17:26 +0000815 ret = xmlDictAddString(dict, name, len);
816 if (ret == NULL)
817 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000818 if (insert == NULL) {
819 entry = &(dict->dict[key]);
820 } else {
821 entry = xmlMalloc(sizeof(xmlDictEntry));
822 if (entry == NULL)
823 return(NULL);
824 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000825 entry->name = ret;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000826 entry->len = len;
827 entry->next = NULL;
828 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +0000829 entry->okey = okey;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000830
831
832 if (insert != NULL)
833 insert->next = entry;
834
835 dict->nbElems++;
836
837 if ((nbi > MAX_HASH_LEN) &&
Daniel Veillardffda65f2008-08-07 16:33:49 +0000838 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
839 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
840 return(NULL);
841 }
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000842 /* Note that entry may have been freed at this point by xmlDictGrow */
843
844 return(ret);
845}
846
847/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000848 * xmlDictExists:
849 * @dict: the dictionnary
850 * @name: the name of the userdata
851 * @len: the length of the name, if -1 it is recomputed
852 *
853 * Check if the @name exists in the dictionnary @dict.
854 *
855 * Returns the internal copy of the name or NULL if not found.
856 */
857const xmlChar *
858xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
859 unsigned long key, okey, nbi = 0;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000860 xmlDictEntryPtr insert;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000861
862 if ((dict == NULL) || (name == NULL))
863 return(NULL);
864
865 if (len < 0)
Daniel Veillardffda65f2008-08-07 16:33:49 +0000866 len = strlen((const char *) name);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000867
868 /*
869 * Check for duplicate and insertion location.
870 */
Daniel Veillarde9100a52008-04-22 08:28:50 +0000871 okey = xmlDictComputeKey(dict, name, len);
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000872 key = okey % dict->size;
873 if (dict->dict[key].valid == 0) {
874 insert = NULL;
875 } else {
876 for (insert = &(dict->dict[key]); insert->next != NULL;
877 insert = insert->next) {
878#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000879 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000880 if (!memcmp(insert->name, name, len))
881 return(insert->name);
882 }
883#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000884 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000885 (!xmlStrncmp(insert->name, name, len)))
886 return(insert->name);
887#endif
888 nbi++;
889 }
890#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000891 if ((insert->okey == okey) && (insert->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000892 if (!memcmp(insert->name, name, len))
893 return(insert->name);
894 }
895#else
Rob Richards117baa02008-08-10 17:07:33 +0000896 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000897 (!xmlStrncmp(insert->name, name, len)))
898 return(insert->name);
899#endif
900 }
901
902 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000903 unsigned long skey;
904
905 /* we cannot always reuse the same okey for the subdict */
906 if (((dict->size == MIN_DICT_SIZE) &&
907 (dict->subdict->size != MIN_DICT_SIZE)) ||
908 ((dict->size != MIN_DICT_SIZE) &&
909 (dict->subdict->size == MIN_DICT_SIZE)))
910 skey = xmlDictComputeKey(dict->subdict, name, len);
911 else
912 skey = okey;
913
914 key = skey % dict->subdict->size;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000915 if (dict->subdict->dict[key].valid != 0) {
916 xmlDictEntryPtr tmp;
917
918 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
919 tmp = tmp->next) {
920#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000921 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000922 if (!memcmp(tmp->name, name, len))
923 return(tmp->name);
924 }
925#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000926 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000927 (!xmlStrncmp(tmp->name, name, len)))
928 return(tmp->name);
929#endif
930 nbi++;
931 }
932#ifdef __GNUC__
Daniel Veillardd68f8912008-08-08 10:09:19 +0000933 if ((tmp->okey == skey) && (tmp->len == len)) {
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000934 if (!memcmp(tmp->name, name, len))
935 return(tmp->name);
936 }
937#else
Daniel Veillardd68f8912008-08-08 10:09:19 +0000938 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000939 (!xmlStrncmp(tmp->name, name, len)))
940 return(tmp->name);
941#endif
942 }
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000943 }
944
945 /* not found */
946 return(NULL);
947}
948
949/**
Daniel Veillarde72c5082003-09-19 12:44:05 +0000950 * xmlDictQLookup:
951 * @dict: the dictionnary
Daniel Veillardd68f8912008-08-08 10:09:19 +0000952 * @prefix: the prefix
Daniel Veillarde72c5082003-09-19 12:44:05 +0000953 * @name: the name
954 *
955 * Add the QName @prefix:@name to the hash @dict if not present.
956 *
957 * Returns the internal copy of the QName or NULL in case of internal error
958 */
959const xmlChar *
960xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000961 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000962 xmlDictEntryPtr entry;
963 xmlDictEntryPtr insert;
964 const xmlChar *ret;
Daniel Veillardffda65f2008-08-07 16:33:49 +0000965 int len, plen, l;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000966
967 if ((dict == NULL) || (name == NULL))
968 return(NULL);
Daniel Veillardffda65f2008-08-07 16:33:49 +0000969 if (prefix == NULL)
970 return(xmlDictLookup(dict, name, -1));
Daniel Veillarde72c5082003-09-19 12:44:05 +0000971
Daniel Veillardffda65f2008-08-07 16:33:49 +0000972 l = len = strlen((const char *) name);
973 plen = strlen((const char *) prefix);
974 len += 1 + plen;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000975
976 /*
977 * Check for duplicate and insertion location.
978 */
Daniel Veillardffda65f2008-08-07 16:33:49 +0000979 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
Daniel Veillard4773df22004-01-23 13:15:13 +0000980 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000981 if (dict->dict[key].valid == 0) {
982 insert = NULL;
983 } else {
984 for (insert = &(dict->dict[key]); insert->next != NULL;
985 insert = insert->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +0000986 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +0000987 (xmlStrQEqual(prefix, name, insert->name)))
988 return(insert->name);
989 nbi++;
990 }
Daniel Veillardd68f8912008-08-08 10:09:19 +0000991 if ((insert->okey == okey) && (insert->len == len) &&
Daniel Veillarde72c5082003-09-19 12:44:05 +0000992 (xmlStrQEqual(prefix, name, insert->name)))
993 return(insert->name);
994 }
995
Daniel Veillard4773df22004-01-23 13:15:13 +0000996 if (dict->subdict) {
Daniel Veillard424785e2008-08-06 09:35:25 +0000997 unsigned long skey;
998
999 /* we cannot always reuse the same okey for the subdict */
1000 if (((dict->size == MIN_DICT_SIZE) &&
1001 (dict->subdict->size != MIN_DICT_SIZE)) ||
1002 ((dict->size != MIN_DICT_SIZE) &&
1003 (dict->subdict->size == MIN_DICT_SIZE)))
Daniel Veillardffda65f2008-08-07 16:33:49 +00001004 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
Daniel Veillard424785e2008-08-06 09:35:25 +00001005 else
1006 skey = okey;
1007
1008 key = skey % dict->subdict->size;
Daniel Veillard4773df22004-01-23 13:15:13 +00001009 if (dict->subdict->dict[key].valid != 0) {
1010 xmlDictEntryPtr tmp;
1011 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1012 tmp = tmp->next) {
Daniel Veillardd68f8912008-08-08 10:09:19 +00001013 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001014 (xmlStrQEqual(prefix, name, tmp->name)))
1015 return(tmp->name);
1016 nbi++;
1017 }
Daniel Veillardd68f8912008-08-08 10:09:19 +00001018 if ((tmp->okey == skey) && (tmp->len == len) &&
Daniel Veillard4773df22004-01-23 13:15:13 +00001019 (xmlStrQEqual(prefix, name, tmp->name)))
1020 return(tmp->name);
1021 }
1022 key = okey % dict->size;
1023 }
1024
Daniel Veillardffda65f2008-08-07 16:33:49 +00001025 ret = xmlDictAddQString(dict, prefix, plen, name, l);
Daniel Veillarde72c5082003-09-19 12:44:05 +00001026 if (ret == NULL)
1027 return(NULL);
1028 if (insert == NULL) {
1029 entry = &(dict->dict[key]);
1030 } else {
1031 entry = xmlMalloc(sizeof(xmlDictEntry));
1032 if (entry == NULL)
1033 return(NULL);
1034 }
1035 entry->name = ret;
1036 entry->len = len;
1037 entry->next = NULL;
1038 entry->valid = 1;
Daniel Veillardd68f8912008-08-08 10:09:19 +00001039 entry->okey = okey;
Daniel Veillarde72c5082003-09-19 12:44:05 +00001040
1041 if (insert != NULL)
1042 insert->next = entry;
1043
1044 dict->nbElems++;
1045
1046 if ((nbi > MAX_HASH_LEN) &&
1047 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1048 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1049 /* Note that entry may have been freed at this point by xmlDictGrow */
1050
1051 return(ret);
1052}
1053
1054/**
Daniel Veillard81514ba2003-09-16 23:17:26 +00001055 * xmlDictOwns:
1056 * @dict: the dictionnary
1057 * @str: the string
1058 *
1059 * check if a string is owned by the disctionary
1060 *
1061 * Returns 1 if true, 0 if false and -1 in case of error
1062 * -1 in case of error
1063 */
1064int
1065xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1066 xmlDictStringsPtr pool;
1067
1068 if ((dict == NULL) || (str == NULL))
1069 return(-1);
1070 pool = dict->strings;
1071 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +00001072 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +00001073 return(1);
1074 pool = pool->next;
1075 }
Daniel Veillard4773df22004-01-23 13:15:13 +00001076 if (dict->subdict)
1077 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +00001078 return(0);
1079}
Daniel Veillarde96a2a42003-09-24 21:23:56 +00001080
Daniel Veillard81514ba2003-09-16 23:17:26 +00001081/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001082 * xmlDictSize:
1083 * @dict: the dictionnary
1084 *
1085 * Query the number of elements installed in the hash @dict.
1086 *
1087 * Returns the number of elements in the dictionnary or
1088 * -1 in case of error
1089 */
1090int
1091xmlDictSize(xmlDictPtr dict) {
1092 if (dict == NULL)
1093 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +00001094 if (dict->subdict)
1095 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001096 return(dict->nbElems);
1097}
1098
1099
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001100#define bottom_dict
1101#include "elfgcchack.h"