blob: 3b4054f2380b331bf720a35e1d427f828c2d17ab [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>
23#include <libxml/tree.h>
24#include <libxml/dict.h>
25#include <libxml/xmlmemory.h>
26#include <libxml/xmlerror.h>
27#include <libxml/globals.h>
28
29#define MAX_HASH_LEN 4
30#define MIN_DICT_SIZE 128
31#define MAX_DICT_HASH 8 * 2048
32
33/* #define ALLOW_REMOVAL */
34/* #define DEBUG_GROW */
35
36/*
37 * An entry in the dictionnary
38 */
39typedef struct _xmlDictEntry xmlDictEntry;
40typedef xmlDictEntry *xmlDictEntryPtr;
41struct _xmlDictEntry {
42 struct _xmlDictEntry *next;
Daniel Veillard81514ba2003-09-16 23:17:26 +000043 const xmlChar *name;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000044 int len;
45 int valid;
46};
47
Daniel Veillard81514ba2003-09-16 23:17:26 +000048typedef struct _xmlDictStrings xmlDictStrings;
49typedef xmlDictStrings *xmlDictStringsPtr;
50struct _xmlDictStrings {
51 xmlDictStringsPtr next;
52 xmlChar *free;
53 xmlChar *end;
54 int size;
55 int nbStrings;
56 xmlChar array[1];
57};
Daniel Veillard2fdbd322003-08-18 12:15:38 +000058/*
59 * The entire dictionnary
60 */
61struct _xmlDict {
Daniel Veillarde96a2a42003-09-24 21:23:56 +000062 int ref_counter;
Daniel Veillard1bb16a12005-01-21 16:55:41 +000063 xmlRMutexPtr mutex;
Daniel Veillarde96a2a42003-09-24 21:23:56 +000064
Daniel Veillard2fdbd322003-08-18 12:15:38 +000065 struct _xmlDictEntry *dict;
66 int size;
67 int nbElems;
Daniel Veillard81514ba2003-09-16 23:17:26 +000068 xmlDictStringsPtr strings;
Daniel Veillard4773df22004-01-23 13:15:13 +000069
70 struct _xmlDict *subdict;
Daniel Veillard2fdbd322003-08-18 12:15:38 +000071};
72
73/*
Daniel Veillard14412512005-01-21 23:53:26 +000074 * A mutex for modifying the reference counter for shared
75 * dictionaries.
76 */
77static xmlRMutexPtr xmlDictMutex = NULL;
78
79/*
80 * Whether the dictionary mutex was initialized.
81 */
82static int xmlDictInitialized = 0;
83
84/**
William M. Brack4e1c2db2005-02-11 10:58:55 +000085 * xmlInitializeDict:
Daniel Veillard14412512005-01-21 23:53:26 +000086 *
87 * Do the dictionary mutex initialization.
88 * this function is not thread safe, initialization should
89 * preferably be done once at startup
90 */
William M. Brack4e1c2db2005-02-11 10:58:55 +000091static int xmlInitializeDict(void) {
Daniel Veillard14412512005-01-21 23:53:26 +000092 if (xmlDictInitialized)
93 return(1);
94
95 if ((xmlDictMutex = xmlNewRMutex()) == NULL)
96 return(0);
97
98 xmlDictInitialized = 1;
99 return(1);
100}
101
102/**
Daniel Veillard2ae13382005-01-25 23:45:06 +0000103 * xmlDictCleanup:
Daniel Veillard14412512005-01-21 23:53:26 +0000104 *
105 * Free the dictionary mutex.
106 */
107void
108xmlDictCleanup(void) {
109 if (!xmlDictInitialized)
110 return;
111
112 xmlFreeRMutex(xmlDictMutex);
113
114 xmlDictInitialized = 0;
115}
116
117/*
Daniel Veillard81514ba2003-09-16 23:17:26 +0000118 * xmlDictAddString:
119 * @dict: the dictionnary
120 * @name: the name of the userdata
121 * @len: the length of the name, if -1 it is recomputed
122 *
123 * Add the string to the array[s]
124 *
125 * Returns the pointer of the local string, or NULL in case of error.
126 */
127static const xmlChar *
128xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
129 xmlDictStringsPtr pool;
130 const xmlChar *ret;
131 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
132
133 pool = dict->strings;
134 while (pool != NULL) {
135 if (pool->end - pool->free > namelen)
136 goto found_pool;
137 if (pool->size > size) size = pool->size;
138 pool = pool->next;
139 }
140 /*
141 * Not found, need to allocate
142 */
143 if (pool == NULL) {
144 if (size == 0) size = 1000;
145 else size *= 4; /* exponential growth */
146 if (size < 4 * namelen)
147 size = 4 * namelen; /* just in case ! */
148 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
149 if (pool == NULL)
150 return(NULL);
151 pool->size = size;
152 pool->nbStrings = 0;
153 pool->free = &pool->array[0];
154 pool->end = &pool->array[size];
155 pool->next = dict->strings;
156 dict->strings = pool;
157 }
158found_pool:
159 ret = pool->free;
160 memcpy(pool->free, name, namelen);
161 pool->free += namelen;
162 *(pool->free++) = 0;
163 return(ret);
164}
165
166/*
Daniel Veillarde72c5082003-09-19 12:44:05 +0000167 * xmlDictAddQString:
168 * @dict: the dictionnary
169 * @prefix: the prefix of the userdata
170 * @name: the name of the userdata
171 * @len: the length of the name, if -1 it is recomputed
172 *
173 * Add the QName to the array[s]
174 *
175 * Returns the pointer of the local string, or NULL in case of error.
176 */
177static const xmlChar *
178xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix,
179 const xmlChar *name, int namelen)
180{
181 xmlDictStringsPtr pool;
182 const xmlChar *ret;
183 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
184 int plen;
185
186 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
187 plen = xmlStrlen(prefix);
188
189 pool = dict->strings;
190 while (pool != NULL) {
191 if (pool->end - pool->free > namelen)
192 goto found_pool;
193 if (pool->size > size) size = pool->size;
194 pool = pool->next;
195 }
196 /*
197 * Not found, need to allocate
198 */
199 if (pool == NULL) {
200 if (size == 0) size = 1000;
201 else size *= 4; /* exponential growth */
202 if (size < 4 * namelen)
203 size = 4 * namelen; /* just in case ! */
204 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
205 if (pool == NULL)
206 return(NULL);
207 pool->size = size;
208 pool->nbStrings = 0;
209 pool->free = &pool->array[0];
210 pool->end = &pool->array[size];
211 pool->next = dict->strings;
212 dict->strings = pool;
213 }
214found_pool:
215 ret = pool->free;
216 memcpy(pool->free, prefix, plen);
217 pool->free += plen;
218 *(pool->free++) = ':';
219 namelen -= plen + 1;
220 memcpy(pool->free, name, namelen);
221 pool->free += namelen;
222 *(pool->free++) = 0;
223 return(ret);
224}
225
226/*
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000227 * xmlDictComputeKey:
228 * Calculate the hash key
229 */
230static unsigned long
Daniel Veillard4773df22004-01-23 13:15:13 +0000231xmlDictComputeKey(const xmlChar *name, int namelen) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000232 unsigned long value = 0L;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000233
234 if (name == NULL) return(0);
Daniel Veillard4773df22004-01-23 13:15:13 +0000235 value = *name;
236 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000237 if (namelen > 10) {
238 value += name[namelen - 1];
239 namelen = 10;
240 }
241 switch (namelen) {
242 case 10: value += name[9];
243 case 9: value += name[8];
244 case 8: value += name[7];
245 case 7: value += name[6];
246 case 6: value += name[5];
247 case 5: value += name[4];
248 case 4: value += name[3];
249 case 3: value += name[2];
250 case 2: value += name[1];
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000251 default: break;
252 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000253 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000254}
255
256/*
257 * xmlDictComputeQKey:
258 * Calculate the hash key
259 */
260static unsigned long
Daniel Veillard4773df22004-01-23 13:15:13 +0000261xmlDictComputeQKey(const xmlChar *prefix, const xmlChar *name, int len)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000262{
263 unsigned long value = 0L;
264 int plen;
265
266 if (prefix == NULL)
Daniel Veillard4773df22004-01-23 13:15:13 +0000267 return(xmlDictComputeKey(name, len));
Daniel Veillarde72c5082003-09-19 12:44:05 +0000268
269 plen = xmlStrlen(prefix);
270 if (plen == 0)
271 value += 30 * (unsigned long) ':';
272 else
273 value += 30 * (*prefix);
274
275 if (len > 10) {
276 value += name[len - (plen + 1 + 1)];
277 len = 10;
278 if (plen > 10)
279 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000280 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000281 switch (plen) {
282 case 10: value += prefix[9];
283 case 9: value += prefix[8];
284 case 8: value += prefix[7];
285 case 7: value += prefix[6];
286 case 6: value += prefix[5];
287 case 5: value += prefix[4];
288 case 4: value += prefix[3];
289 case 3: value += prefix[2];
290 case 2: value += prefix[1];
291 case 1: value += prefix[0];
292 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000293 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000294 len -= plen;
295 if (len > 0) {
296 value += (unsigned long) ':';
297 len--;
298 }
299 switch (len) {
300 case 10: value += name[9];
301 case 9: value += name[8];
302 case 8: value += name[7];
303 case 7: value += name[6];
304 case 6: value += name[5];
305 case 5: value += name[4];
306 case 4: value += name[3];
307 case 3: value += name[2];
308 case 2: value += name[1];
309 case 1: value += name[0];
310 default: break;
311 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000312 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000313}
314
315/**
316 * xmlDictCreate:
317 *
318 * Create a new dictionary
319 *
Daniel Veillard4773df22004-01-23 13:15:13 +0000320 * Returns the newly created dictionnary, or NULL if an error occured.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000321 */
322xmlDictPtr
323xmlDictCreate(void) {
324 xmlDictPtr dict;
Daniel Veillard14412512005-01-21 23:53:26 +0000325
326 if (!xmlDictInitialized)
327 if (!xmlInitializeDict())
328 return(NULL);
329
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000330 dict = xmlMalloc(sizeof(xmlDict));
331 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000332 dict->ref_counter = 1;
333
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000334 dict->size = MIN_DICT_SIZE;
335 dict->nbElems = 0;
336 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000337 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000338 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000339 if (dict->dict) {
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000340 if ((dict->mutex = xmlNewRMutex()) != NULL) {
341 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
342 return(dict);
343 }
344 xmlFree(dict->dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000345 }
346 xmlFree(dict);
347 }
348 return(NULL);
349}
350
351/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000352 * xmlDictCreateSub:
353 * @sub: an existing dictionnary
354 *
355 * Create a new dictionary, inheriting strings from the read-only
356 * dictionnary @sub. On lookup, strings are first searched in the
357 * new dictionnary, then in @sub, and if not found are created in the
358 * new dictionnary.
359 *
360 * Returns the newly created dictionnary, or NULL if an error occured.
361 */
362xmlDictPtr
363xmlDictCreateSub(xmlDictPtr sub) {
364 xmlDictPtr dict = xmlDictCreate();
365
366 if ((dict != NULL) && (sub != NULL)) {
367 dict->subdict = sub;
368 xmlDictReference(dict->subdict);
369 }
370 return(dict);
371}
372
373/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000374 * xmlDictReference:
375 * @dict: the dictionnary
376 *
377 * Increment the reference counter of a dictionary
378 *
379 * Returns 0 in case of success and -1 in case of error
380 */
381int
382xmlDictReference(xmlDictPtr dict) {
Daniel Veillard14412512005-01-21 23:53:26 +0000383 if (!xmlDictInitialized)
384 if (!xmlInitializeDict())
385 return(-1);
386
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000387 if (dict == NULL) return -1;
Daniel Veillard14412512005-01-21 23:53:26 +0000388 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000389 dict->ref_counter++;
Daniel Veillard14412512005-01-21 23:53:26 +0000390 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000391 return(0);
392}
393
394/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000395 * xmlDictGrow:
396 * @dict: the dictionnary
397 * @size: the new size of the dictionnary
398 *
399 * resize the dictionnary
400 *
401 * Returns 0 in case of success, -1 in case of failure
402 */
403static int
404xmlDictGrow(xmlDictPtr dict, int size) {
405 unsigned long key;
406 int oldsize, i;
407 xmlDictEntryPtr iter, next;
408 struct _xmlDictEntry *olddict;
409#ifdef DEBUG_GROW
410 unsigned long nbElem = 0;
411#endif
412
413 if (dict == NULL)
414 return(-1);
415 if (size < 8)
416 return(-1);
417 if (size > 8 * 2048)
418 return(-1);
419
420 oldsize = dict->size;
421 olddict = dict->dict;
422 if (olddict == NULL)
423 return(-1);
424
425 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
426 if (dict->dict == NULL) {
427 dict->dict = olddict;
428 return(-1);
429 }
430 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
431 dict->size = size;
432
433 /* If the two loops are merged, there would be situations where
434 a new entry needs to allocated and data copied into it from
435 the main dict. So instead, we run through the array twice, first
436 copying all the elements in the main array (where we can't get
437 conflicts) and then the rest, so we only free (and don't allocate)
438 */
439 for (i = 0; i < oldsize; i++) {
440 if (olddict[i].valid == 0)
441 continue;
Daniel Veillard4773df22004-01-23 13:15:13 +0000442 key = xmlDictComputeKey(olddict[i].name, olddict[i].len) % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000443 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
444 dict->dict[key].next = NULL;
445#ifdef DEBUG_GROW
446 nbElem++;
447#endif
448 }
449
450 for (i = 0; i < oldsize; i++) {
451 iter = olddict[i].next;
452 while (iter) {
453 next = iter->next;
454
455 /*
456 * put back the entry in the new dict
457 */
458
Daniel Veillard4773df22004-01-23 13:15:13 +0000459 key = xmlDictComputeKey(iter->name, iter->len) % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000460 if (dict->dict[key].valid == 0) {
461 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
462 dict->dict[key].next = NULL;
463 dict->dict[key].valid = 1;
464 xmlFree(iter);
465 } else {
466 iter->next = dict->dict[key].next;
467 dict->dict[key].next = iter;
468 }
469
470#ifdef DEBUG_GROW
471 nbElem++;
472#endif
473
474 iter = next;
475 }
476 }
477
478 xmlFree(olddict);
479
480#ifdef DEBUG_GROW
481 xmlGenericError(xmlGenericErrorContext,
482 "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
483#endif
484
485 return(0);
486}
487
488/**
489 * xmlDictFree:
490 * @dict: the dictionnary
491 *
492 * Free the hash @dict and its contents. The userdata is
493 * deallocated with @f if provided.
494 */
495void
496xmlDictFree(xmlDictPtr dict) {
497 int i;
498 xmlDictEntryPtr iter;
499 xmlDictEntryPtr next;
500 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000501 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000502
503 if (dict == NULL)
504 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000505
Daniel Veillard14412512005-01-21 23:53:26 +0000506 if (!xmlDictInitialized)
507 if (!xmlInitializeDict())
508 return;
509
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000510 /* decrement the counter, it may be shared by a parser and docs */
Daniel Veillard14412512005-01-21 23:53:26 +0000511 xmlRMutexLock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000512 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000513 if (dict->ref_counter > 0) {
Daniel Veillard14412512005-01-21 23:53:26 +0000514 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000515 return;
516 }
517
Daniel Veillard14412512005-01-21 23:53:26 +0000518 xmlRMutexUnlock(xmlDictMutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000519
Daniel Veillard4773df22004-01-23 13:15:13 +0000520 if (dict->subdict != NULL) {
521 xmlDictFree(dict->subdict);
522 }
523
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000524 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000525 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000526 iter = &(dict->dict[i]);
527 if (iter->valid == 0)
528 continue;
529 inside_dict = 1;
530 while (iter) {
531 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000532 if (!inside_dict)
533 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000534 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000535 inside_dict = 0;
536 iter = next;
537 }
538 inside_dict = 0;
539 }
540 xmlFree(dict->dict);
541 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000542 pool = dict->strings;
543 while (pool != NULL) {
544 nextp = pool->next;
545 xmlFree(pool);
546 pool = nextp;
547 }
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000548 xmlFreeRMutex(dict->mutex);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000549 xmlFree(dict);
550}
551
552/**
553 * xmlDictLookup:
554 * @dict: the dictionnary
555 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000556 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000557 *
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000558 * Add the @name to the dictionnary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000559 *
560 * Returns the internal copy of the name or NULL in case of internal error
561 */
562const xmlChar *
563xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000564 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000565 xmlDictEntryPtr entry;
566 xmlDictEntryPtr insert;
567 const xmlChar *ret;
568
Daniel Veillard0fb18932003-09-07 09:14:37 +0000569 if ((dict == NULL) || (name == NULL))
570 return(NULL);
571
572 if (len < 0)
573 len = xmlStrlen(name);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000574
575 /*
576 * Check for duplicate and insertion location.
577 */
Daniel Veillard4773df22004-01-23 13:15:13 +0000578 okey = xmlDictComputeKey(name, len);
579 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000580 if (dict->dict[key].valid == 0) {
581 insert = NULL;
582 } else {
583 for (insert = &(dict->dict[key]); insert->next != NULL;
584 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000585#ifdef __GNUC__
586 if (insert->len == len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000587 if (!memcmp(insert->name, name, len))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000588 return(insert->name);
589 }
590#else
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000591 if ((insert->len == len) &&
592 (!xmlStrncmp(insert->name, name, len)))
593 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000594#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000595 nbi++;
596 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000597#ifdef __GNUC__
598 if (insert->len == len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000599 if (!memcmp(insert->name, name, len))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000600 return(insert->name);
601 }
602#else
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000603 if ((insert->len == len) &&
604 (!xmlStrncmp(insert->name, name, len)))
605 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000606#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000607 }
608
Daniel Veillard4773df22004-01-23 13:15:13 +0000609 if (dict->subdict) {
610 key = okey % dict->subdict->size;
611 if (dict->subdict->dict[key].valid != 0) {
612 xmlDictEntryPtr tmp;
613
614 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
615 tmp = tmp->next) {
616#ifdef __GNUC__
617 if (tmp->len == len) {
618 if (!memcmp(tmp->name, name, len))
619 return(tmp->name);
620 }
621#else
622 if ((tmp->len == len) &&
623 (!xmlStrncmp(tmp->name, name, len)))
624 return(tmp->name);
625#endif
626 nbi++;
627 }
628#ifdef __GNUC__
629 if (tmp->len == len) {
630 if (!memcmp(tmp->name, name, len))
631 return(tmp->name);
632 }
633#else
634 if ((tmp->len == len) &&
635 (!xmlStrncmp(tmp->name, name, len)))
636 return(tmp->name);
637#endif
638 }
639 key = okey % dict->size;
640 }
641
Daniel Veillard81514ba2003-09-16 23:17:26 +0000642 ret = xmlDictAddString(dict, name, len);
643 if (ret == NULL)
644 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000645 if (insert == NULL) {
646 entry = &(dict->dict[key]);
647 } else {
648 entry = xmlMalloc(sizeof(xmlDictEntry));
649 if (entry == NULL)
650 return(NULL);
651 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000652 entry->name = ret;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000653 entry->len = len;
654 entry->next = NULL;
655 entry->valid = 1;
656
657
658 if (insert != NULL)
659 insert->next = entry;
660
661 dict->nbElems++;
662
663 if ((nbi > MAX_HASH_LEN) &&
664 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
665 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
666 /* Note that entry may have been freed at this point by xmlDictGrow */
667
668 return(ret);
669}
670
671/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000672 * xmlDictExists:
673 * @dict: the dictionnary
674 * @name: the name of the userdata
675 * @len: the length of the name, if -1 it is recomputed
676 *
677 * Check if the @name exists in the dictionnary @dict.
678 *
679 * Returns the internal copy of the name or NULL if not found.
680 */
681const xmlChar *
682xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
683 unsigned long key, okey, nbi = 0;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000684 xmlDictEntryPtr insert;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000685
686 if ((dict == NULL) || (name == NULL))
687 return(NULL);
688
689 if (len < 0)
690 len = xmlStrlen(name);
691
692 /*
693 * Check for duplicate and insertion location.
694 */
695 okey = xmlDictComputeKey(name, len);
696 key = okey % dict->size;
697 if (dict->dict[key].valid == 0) {
698 insert = NULL;
699 } else {
700 for (insert = &(dict->dict[key]); insert->next != NULL;
701 insert = insert->next) {
702#ifdef __GNUC__
703 if (insert->len == len) {
704 if (!memcmp(insert->name, name, len))
705 return(insert->name);
706 }
707#else
708 if ((insert->len == len) &&
709 (!xmlStrncmp(insert->name, name, len)))
710 return(insert->name);
711#endif
712 nbi++;
713 }
714#ifdef __GNUC__
715 if (insert->len == len) {
716 if (!memcmp(insert->name, name, len))
717 return(insert->name);
718 }
719#else
720 if ((insert->len == len) &&
721 (!xmlStrncmp(insert->name, name, len)))
722 return(insert->name);
723#endif
724 }
725
726 if (dict->subdict) {
727 key = okey % dict->subdict->size;
728 if (dict->subdict->dict[key].valid != 0) {
729 xmlDictEntryPtr tmp;
730
731 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
732 tmp = tmp->next) {
733#ifdef __GNUC__
734 if (tmp->len == len) {
735 if (!memcmp(tmp->name, name, len))
736 return(tmp->name);
737 }
738#else
739 if ((tmp->len == len) &&
740 (!xmlStrncmp(tmp->name, name, len)))
741 return(tmp->name);
742#endif
743 nbi++;
744 }
745#ifdef __GNUC__
746 if (tmp->len == len) {
747 if (!memcmp(tmp->name, name, len))
748 return(tmp->name);
749 }
750#else
751 if ((tmp->len == len) &&
752 (!xmlStrncmp(tmp->name, name, len)))
753 return(tmp->name);
754#endif
755 }
756 key = okey % dict->size;
757 }
758
759 /* not found */
760 return(NULL);
761}
762
763/**
Daniel Veillarde72c5082003-09-19 12:44:05 +0000764 * xmlDictQLookup:
765 * @dict: the dictionnary
766 * @prefix: the prefix
767 * @name: the name
768 *
769 * Add the QName @prefix:@name to the hash @dict if not present.
770 *
771 * Returns the internal copy of the QName or NULL in case of internal error
772 */
773const xmlChar *
774xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000775 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000776 xmlDictEntryPtr entry;
777 xmlDictEntryPtr insert;
778 const xmlChar *ret;
779 int len;
780
781 if ((dict == NULL) || (name == NULL))
782 return(NULL);
783
784 len = xmlStrlen(name);
785 if (prefix != NULL)
786 len += 1 + xmlStrlen(prefix);
787
788 /*
789 * Check for duplicate and insertion location.
790 */
Daniel Veillard4773df22004-01-23 13:15:13 +0000791 okey = xmlDictComputeQKey(prefix, name, len);
792 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000793 if (dict->dict[key].valid == 0) {
794 insert = NULL;
795 } else {
796 for (insert = &(dict->dict[key]); insert->next != NULL;
797 insert = insert->next) {
798 if ((insert->len == len) &&
799 (xmlStrQEqual(prefix, name, insert->name)))
800 return(insert->name);
801 nbi++;
802 }
803 if ((insert->len == len) &&
804 (xmlStrQEqual(prefix, name, insert->name)))
805 return(insert->name);
806 }
807
Daniel Veillard4773df22004-01-23 13:15:13 +0000808 if (dict->subdict) {
809 key = okey % dict->subdict->size;
810 if (dict->subdict->dict[key].valid != 0) {
811 xmlDictEntryPtr tmp;
812 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
813 tmp = tmp->next) {
814 if ((tmp->len == len) &&
815 (xmlStrQEqual(prefix, name, tmp->name)))
816 return(tmp->name);
817 nbi++;
818 }
819 if ((tmp->len == len) &&
820 (xmlStrQEqual(prefix, name, tmp->name)))
821 return(tmp->name);
822 }
823 key = okey % dict->size;
824 }
825
Daniel Veillarde72c5082003-09-19 12:44:05 +0000826 ret = xmlDictAddQString(dict, prefix, name, len);
827 if (ret == NULL)
828 return(NULL);
829 if (insert == NULL) {
830 entry = &(dict->dict[key]);
831 } else {
832 entry = xmlMalloc(sizeof(xmlDictEntry));
833 if (entry == NULL)
834 return(NULL);
835 }
836 entry->name = ret;
837 entry->len = len;
838 entry->next = NULL;
839 entry->valid = 1;
840
841 if (insert != NULL)
842 insert->next = entry;
843
844 dict->nbElems++;
845
846 if ((nbi > MAX_HASH_LEN) &&
847 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
848 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
849 /* Note that entry may have been freed at this point by xmlDictGrow */
850
851 return(ret);
852}
853
854/**
Daniel Veillard81514ba2003-09-16 23:17:26 +0000855 * xmlDictOwns:
856 * @dict: the dictionnary
857 * @str: the string
858 *
859 * check if a string is owned by the disctionary
860 *
861 * Returns 1 if true, 0 if false and -1 in case of error
862 * -1 in case of error
863 */
864int
865xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
866 xmlDictStringsPtr pool;
867
868 if ((dict == NULL) || (str == NULL))
869 return(-1);
870 pool = dict->strings;
871 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +0000872 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +0000873 return(1);
874 pool = pool->next;
875 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000876 if (dict->subdict)
877 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000878 return(0);
879}
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000880
Daniel Veillard81514ba2003-09-16 23:17:26 +0000881/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000882 * xmlDictSize:
883 * @dict: the dictionnary
884 *
885 * Query the number of elements installed in the hash @dict.
886 *
887 * Returns the number of elements in the dictionnary or
888 * -1 in case of error
889 */
890int
891xmlDictSize(xmlDictPtr dict) {
892 if (dict == NULL)
893 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000894 if (dict->subdict)
895 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000896 return(dict->nbElems);
897}
898
899
Daniel Veillard5d4644e2005-04-01 13:11:58 +0000900#define bottom_dict
901#include "elfgcchack.h"