blob: a78ccee782fcb17ab8614b430e71eb4b78cf890d [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 Veillard81514ba2003-09-16 23:17:26 +000074 * xmlDictAddString:
75 * @dict: the dictionnary
76 * @name: the name of the userdata
77 * @len: the length of the name, if -1 it is recomputed
78 *
79 * Add the string to the array[s]
80 *
81 * Returns the pointer of the local string, or NULL in case of error.
82 */
83static const xmlChar *
84xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
85 xmlDictStringsPtr pool;
86 const xmlChar *ret;
87 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
88
89 pool = dict->strings;
90 while (pool != NULL) {
91 if (pool->end - pool->free > namelen)
92 goto found_pool;
93 if (pool->size > size) size = pool->size;
94 pool = pool->next;
95 }
96 /*
97 * Not found, need to allocate
98 */
99 if (pool == NULL) {
100 if (size == 0) size = 1000;
101 else size *= 4; /* exponential growth */
102 if (size < 4 * namelen)
103 size = 4 * namelen; /* just in case ! */
104 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
105 if (pool == NULL)
106 return(NULL);
107 pool->size = size;
108 pool->nbStrings = 0;
109 pool->free = &pool->array[0];
110 pool->end = &pool->array[size];
111 pool->next = dict->strings;
112 dict->strings = pool;
113 }
114found_pool:
115 ret = pool->free;
116 memcpy(pool->free, name, namelen);
117 pool->free += namelen;
118 *(pool->free++) = 0;
119 return(ret);
120}
121
122/*
Daniel Veillarde72c5082003-09-19 12:44:05 +0000123 * xmlDictAddQString:
124 * @dict: the dictionnary
125 * @prefix: the prefix of the userdata
126 * @name: the name of the userdata
127 * @len: the length of the name, if -1 it is recomputed
128 *
129 * Add the QName to the array[s]
130 *
131 * Returns the pointer of the local string, or NULL in case of error.
132 */
133static const xmlChar *
134xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix,
135 const xmlChar *name, int namelen)
136{
137 xmlDictStringsPtr pool;
138 const xmlChar *ret;
139 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
140 int plen;
141
142 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
143 plen = xmlStrlen(prefix);
144
145 pool = dict->strings;
146 while (pool != NULL) {
147 if (pool->end - pool->free > namelen)
148 goto found_pool;
149 if (pool->size > size) size = pool->size;
150 pool = pool->next;
151 }
152 /*
153 * Not found, need to allocate
154 */
155 if (pool == NULL) {
156 if (size == 0) size = 1000;
157 else size *= 4; /* exponential growth */
158 if (size < 4 * namelen)
159 size = 4 * namelen; /* just in case ! */
160 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
161 if (pool == NULL)
162 return(NULL);
163 pool->size = size;
164 pool->nbStrings = 0;
165 pool->free = &pool->array[0];
166 pool->end = &pool->array[size];
167 pool->next = dict->strings;
168 dict->strings = pool;
169 }
170found_pool:
171 ret = pool->free;
172 memcpy(pool->free, prefix, plen);
173 pool->free += plen;
174 *(pool->free++) = ':';
175 namelen -= plen + 1;
176 memcpy(pool->free, name, namelen);
177 pool->free += namelen;
178 *(pool->free++) = 0;
179 return(ret);
180}
181
182/*
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000183 * xmlDictComputeKey:
184 * Calculate the hash key
185 */
186static unsigned long
Daniel Veillard4773df22004-01-23 13:15:13 +0000187xmlDictComputeKey(const xmlChar *name, int namelen) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000188 unsigned long value = 0L;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000189
190 if (name == NULL) return(0);
Daniel Veillard4773df22004-01-23 13:15:13 +0000191 value = *name;
192 value <<= 5;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000193 if (namelen > 10) {
194 value += name[namelen - 1];
195 namelen = 10;
196 }
197 switch (namelen) {
198 case 10: value += name[9];
199 case 9: value += name[8];
200 case 8: value += name[7];
201 case 7: value += name[6];
202 case 6: value += name[5];
203 case 5: value += name[4];
204 case 4: value += name[3];
205 case 3: value += name[2];
206 case 2: value += name[1];
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000207 default: break;
208 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000209 return(value);
Daniel Veillarde72c5082003-09-19 12:44:05 +0000210}
211
212/*
213 * xmlDictComputeQKey:
214 * Calculate the hash key
215 */
216static unsigned long
Daniel Veillard4773df22004-01-23 13:15:13 +0000217xmlDictComputeQKey(const xmlChar *prefix, const xmlChar *name, int len)
Daniel Veillarde72c5082003-09-19 12:44:05 +0000218{
219 unsigned long value = 0L;
220 int plen;
221
222 if (prefix == NULL)
Daniel Veillard4773df22004-01-23 13:15:13 +0000223 return(xmlDictComputeKey(name, len));
Daniel Veillarde72c5082003-09-19 12:44:05 +0000224
225 plen = xmlStrlen(prefix);
226 if (plen == 0)
227 value += 30 * (unsigned long) ':';
228 else
229 value += 30 * (*prefix);
230
231 if (len > 10) {
232 value += name[len - (plen + 1 + 1)];
233 len = 10;
234 if (plen > 10)
235 plen = 10;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000236 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000237 switch (plen) {
238 case 10: value += prefix[9];
239 case 9: value += prefix[8];
240 case 8: value += prefix[7];
241 case 7: value += prefix[6];
242 case 6: value += prefix[5];
243 case 5: value += prefix[4];
244 case 4: value += prefix[3];
245 case 3: value += prefix[2];
246 case 2: value += prefix[1];
247 case 1: value += prefix[0];
248 default: break;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000249 }
Daniel Veillarde72c5082003-09-19 12:44:05 +0000250 len -= plen;
251 if (len > 0) {
252 value += (unsigned long) ':';
253 len--;
254 }
255 switch (len) {
256 case 10: value += name[9];
257 case 9: value += name[8];
258 case 8: value += name[7];
259 case 7: value += name[6];
260 case 6: value += name[5];
261 case 5: value += name[4];
262 case 4: value += name[3];
263 case 3: value += name[2];
264 case 2: value += name[1];
265 case 1: value += name[0];
266 default: break;
267 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000268 return(value);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000269}
270
271/**
272 * xmlDictCreate:
273 *
274 * Create a new dictionary
275 *
Daniel Veillard4773df22004-01-23 13:15:13 +0000276 * Returns the newly created dictionnary, or NULL if an error occured.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000277 */
278xmlDictPtr
279xmlDictCreate(void) {
280 xmlDictPtr dict;
281
282 dict = xmlMalloc(sizeof(xmlDict));
283 if (dict) {
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000284 dict->ref_counter = 1;
285
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000286 dict->size = MIN_DICT_SIZE;
287 dict->nbElems = 0;
288 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000289 dict->strings = NULL;
Daniel Veillard4773df22004-01-23 13:15:13 +0000290 dict->subdict = NULL;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000291 if (dict->dict) {
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000292 if ((dict->mutex = xmlNewRMutex()) != NULL) {
293 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
294 return(dict);
295 }
296 xmlFree(dict->dict);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000297 }
298 xmlFree(dict);
299 }
300 return(NULL);
301}
302
303/**
Daniel Veillard4773df22004-01-23 13:15:13 +0000304 * xmlDictCreateSub:
305 * @sub: an existing dictionnary
306 *
307 * Create a new dictionary, inheriting strings from the read-only
308 * dictionnary @sub. On lookup, strings are first searched in the
309 * new dictionnary, then in @sub, and if not found are created in the
310 * new dictionnary.
311 *
312 * Returns the newly created dictionnary, or NULL if an error occured.
313 */
314xmlDictPtr
315xmlDictCreateSub(xmlDictPtr sub) {
316 xmlDictPtr dict = xmlDictCreate();
317
318 if ((dict != NULL) && (sub != NULL)) {
319 dict->subdict = sub;
320 xmlDictReference(dict->subdict);
321 }
322 return(dict);
323}
324
325/**
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000326 * xmlDictReference:
327 * @dict: the dictionnary
328 *
329 * Increment the reference counter of a dictionary
330 *
331 * Returns 0 in case of success and -1 in case of error
332 */
333int
334xmlDictReference(xmlDictPtr dict) {
335 if (dict == NULL) return -1;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000336 xmlRMutexLock(dict->mutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000337 dict->ref_counter++;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000338 xmlRMutexUnlock(dict->mutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000339 return(0);
340}
341
342/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000343 * xmlDictGrow:
344 * @dict: the dictionnary
345 * @size: the new size of the dictionnary
346 *
347 * resize the dictionnary
348 *
349 * Returns 0 in case of success, -1 in case of failure
350 */
351static int
352xmlDictGrow(xmlDictPtr dict, int size) {
353 unsigned long key;
354 int oldsize, i;
355 xmlDictEntryPtr iter, next;
356 struct _xmlDictEntry *olddict;
357#ifdef DEBUG_GROW
358 unsigned long nbElem = 0;
359#endif
360
361 if (dict == NULL)
362 return(-1);
363 if (size < 8)
364 return(-1);
365 if (size > 8 * 2048)
366 return(-1);
367
368 oldsize = dict->size;
369 olddict = dict->dict;
370 if (olddict == NULL)
371 return(-1);
372
373 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
374 if (dict->dict == NULL) {
375 dict->dict = olddict;
376 return(-1);
377 }
378 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
379 dict->size = size;
380
381 /* If the two loops are merged, there would be situations where
382 a new entry needs to allocated and data copied into it from
383 the main dict. So instead, we run through the array twice, first
384 copying all the elements in the main array (where we can't get
385 conflicts) and then the rest, so we only free (and don't allocate)
386 */
387 for (i = 0; i < oldsize; i++) {
388 if (olddict[i].valid == 0)
389 continue;
Daniel Veillard4773df22004-01-23 13:15:13 +0000390 key = xmlDictComputeKey(olddict[i].name, olddict[i].len) % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000391 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
392 dict->dict[key].next = NULL;
393#ifdef DEBUG_GROW
394 nbElem++;
395#endif
396 }
397
398 for (i = 0; i < oldsize; i++) {
399 iter = olddict[i].next;
400 while (iter) {
401 next = iter->next;
402
403 /*
404 * put back the entry in the new dict
405 */
406
Daniel Veillard4773df22004-01-23 13:15:13 +0000407 key = xmlDictComputeKey(iter->name, iter->len) % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000408 if (dict->dict[key].valid == 0) {
409 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
410 dict->dict[key].next = NULL;
411 dict->dict[key].valid = 1;
412 xmlFree(iter);
413 } else {
414 iter->next = dict->dict[key].next;
415 dict->dict[key].next = iter;
416 }
417
418#ifdef DEBUG_GROW
419 nbElem++;
420#endif
421
422 iter = next;
423 }
424 }
425
426 xmlFree(olddict);
427
428#ifdef DEBUG_GROW
429 xmlGenericError(xmlGenericErrorContext,
430 "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
431#endif
432
433 return(0);
434}
435
436/**
437 * xmlDictFree:
438 * @dict: the dictionnary
439 *
440 * Free the hash @dict and its contents. The userdata is
441 * deallocated with @f if provided.
442 */
443void
444xmlDictFree(xmlDictPtr dict) {
445 int i;
446 xmlDictEntryPtr iter;
447 xmlDictEntryPtr next;
448 int inside_dict = 0;
Daniel Veillard81514ba2003-09-16 23:17:26 +0000449 xmlDictStringsPtr pool, nextp;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000450
451 if (dict == NULL)
452 return;
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000453
454 /* decrement the counter, it may be shared by a parser and docs */
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000455 xmlRMutexLock(dict->mutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000456 dict->ref_counter--;
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000457 if (dict->ref_counter > 0) {
458 xmlRMutexUnlock(dict->mutex);
459 return;
460 }
461
462 xmlRMutexUnlock(dict->mutex);
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000463
Daniel Veillard4773df22004-01-23 13:15:13 +0000464 if (dict->subdict != NULL) {
465 xmlDictFree(dict->subdict);
466 }
467
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000468 if (dict->dict) {
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000469 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000470 iter = &(dict->dict[i]);
471 if (iter->valid == 0)
472 continue;
473 inside_dict = 1;
474 while (iter) {
475 next = iter->next;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000476 if (!inside_dict)
477 xmlFree(iter);
Daniel Veillard6155d8a2003-08-19 15:01:28 +0000478 dict->nbElems--;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000479 inside_dict = 0;
480 iter = next;
481 }
482 inside_dict = 0;
483 }
484 xmlFree(dict->dict);
485 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000486 pool = dict->strings;
487 while (pool != NULL) {
488 nextp = pool->next;
489 xmlFree(pool);
490 pool = nextp;
491 }
Daniel Veillard1bb16a12005-01-21 16:55:41 +0000492 xmlFreeRMutex(dict->mutex);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000493 xmlFree(dict);
494}
495
496/**
497 * xmlDictLookup:
498 * @dict: the dictionnary
499 * @name: the name of the userdata
Daniel Veillard0fb18932003-09-07 09:14:37 +0000500 * @len: the length of the name, if -1 it is recomputed
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000501 *
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000502 * Add the @name to the dictionnary @dict if not present.
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000503 *
504 * Returns the internal copy of the name or NULL in case of internal error
505 */
506const xmlChar *
507xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000508 unsigned long key, okey, nbi = 0;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000509 xmlDictEntryPtr entry;
510 xmlDictEntryPtr insert;
511 const xmlChar *ret;
512
Daniel Veillard0fb18932003-09-07 09:14:37 +0000513 if ((dict == NULL) || (name == NULL))
514 return(NULL);
515
516 if (len < 0)
517 len = xmlStrlen(name);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000518
519 /*
520 * Check for duplicate and insertion location.
521 */
Daniel Veillard4773df22004-01-23 13:15:13 +0000522 okey = xmlDictComputeKey(name, len);
523 key = okey % dict->size;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000524 if (dict->dict[key].valid == 0) {
525 insert = NULL;
526 } else {
527 for (insert = &(dict->dict[key]); insert->next != NULL;
528 insert = insert->next) {
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000529#ifdef __GNUC__
530 if (insert->len == len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000531 if (!memcmp(insert->name, name, len))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000532 return(insert->name);
533 }
534#else
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000535 if ((insert->len == len) &&
536 (!xmlStrncmp(insert->name, name, len)))
537 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000538#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000539 nbi++;
540 }
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000541#ifdef __GNUC__
542 if (insert->len == len) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000543 if (!memcmp(insert->name, name, len))
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000544 return(insert->name);
545 }
546#else
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000547 if ((insert->len == len) &&
548 (!xmlStrncmp(insert->name, name, len)))
549 return(insert->name);
Daniel Veillardc82c57e2004-01-12 16:24:34 +0000550#endif
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000551 }
552
Daniel Veillard4773df22004-01-23 13:15:13 +0000553 if (dict->subdict) {
554 key = okey % dict->subdict->size;
555 if (dict->subdict->dict[key].valid != 0) {
556 xmlDictEntryPtr tmp;
557
558 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
559 tmp = tmp->next) {
560#ifdef __GNUC__
561 if (tmp->len == len) {
562 if (!memcmp(tmp->name, name, len))
563 return(tmp->name);
564 }
565#else
566 if ((tmp->len == len) &&
567 (!xmlStrncmp(tmp->name, name, len)))
568 return(tmp->name);
569#endif
570 nbi++;
571 }
572#ifdef __GNUC__
573 if (tmp->len == len) {
574 if (!memcmp(tmp->name, name, len))
575 return(tmp->name);
576 }
577#else
578 if ((tmp->len == len) &&
579 (!xmlStrncmp(tmp->name, name, len)))
580 return(tmp->name);
581#endif
582 }
583 key = okey % dict->size;
584 }
585
Daniel Veillard81514ba2003-09-16 23:17:26 +0000586 ret = xmlDictAddString(dict, name, len);
587 if (ret == NULL)
588 return(NULL);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000589 if (insert == NULL) {
590 entry = &(dict->dict[key]);
591 } else {
592 entry = xmlMalloc(sizeof(xmlDictEntry));
593 if (entry == NULL)
594 return(NULL);
595 }
Daniel Veillard81514ba2003-09-16 23:17:26 +0000596 entry->name = ret;
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000597 entry->len = len;
598 entry->next = NULL;
599 entry->valid = 1;
600
601
602 if (insert != NULL)
603 insert->next = entry;
604
605 dict->nbElems++;
606
607 if ((nbi > MAX_HASH_LEN) &&
608 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
609 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
610 /* Note that entry may have been freed at this point by xmlDictGrow */
611
612 return(ret);
613}
614
615/**
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000616 * xmlDictExists:
617 * @dict: the dictionnary
618 * @name: the name of the userdata
619 * @len: the length of the name, if -1 it is recomputed
620 *
621 * Check if the @name exists in the dictionnary @dict.
622 *
623 * Returns the internal copy of the name or NULL if not found.
624 */
625const xmlChar *
626xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
627 unsigned long key, okey, nbi = 0;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000628 xmlDictEntryPtr insert;
Daniel Veillard6bb3e862004-11-24 12:39:00 +0000629
630 if ((dict == NULL) || (name == NULL))
631 return(NULL);
632
633 if (len < 0)
634 len = xmlStrlen(name);
635
636 /*
637 * Check for duplicate and insertion location.
638 */
639 okey = xmlDictComputeKey(name, len);
640 key = okey % dict->size;
641 if (dict->dict[key].valid == 0) {
642 insert = NULL;
643 } else {
644 for (insert = &(dict->dict[key]); insert->next != NULL;
645 insert = insert->next) {
646#ifdef __GNUC__
647 if (insert->len == len) {
648 if (!memcmp(insert->name, name, len))
649 return(insert->name);
650 }
651#else
652 if ((insert->len == len) &&
653 (!xmlStrncmp(insert->name, name, len)))
654 return(insert->name);
655#endif
656 nbi++;
657 }
658#ifdef __GNUC__
659 if (insert->len == len) {
660 if (!memcmp(insert->name, name, len))
661 return(insert->name);
662 }
663#else
664 if ((insert->len == len) &&
665 (!xmlStrncmp(insert->name, name, len)))
666 return(insert->name);
667#endif
668 }
669
670 if (dict->subdict) {
671 key = okey % dict->subdict->size;
672 if (dict->subdict->dict[key].valid != 0) {
673 xmlDictEntryPtr tmp;
674
675 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
676 tmp = tmp->next) {
677#ifdef __GNUC__
678 if (tmp->len == len) {
679 if (!memcmp(tmp->name, name, len))
680 return(tmp->name);
681 }
682#else
683 if ((tmp->len == len) &&
684 (!xmlStrncmp(tmp->name, name, len)))
685 return(tmp->name);
686#endif
687 nbi++;
688 }
689#ifdef __GNUC__
690 if (tmp->len == len) {
691 if (!memcmp(tmp->name, name, len))
692 return(tmp->name);
693 }
694#else
695 if ((tmp->len == len) &&
696 (!xmlStrncmp(tmp->name, name, len)))
697 return(tmp->name);
698#endif
699 }
700 key = okey % dict->size;
701 }
702
703 /* not found */
704 return(NULL);
705}
706
707/**
Daniel Veillarde72c5082003-09-19 12:44:05 +0000708 * xmlDictQLookup:
709 * @dict: the dictionnary
710 * @prefix: the prefix
711 * @name: the name
712 *
713 * Add the QName @prefix:@name to the hash @dict if not present.
714 *
715 * Returns the internal copy of the QName or NULL in case of internal error
716 */
717const xmlChar *
718xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard4773df22004-01-23 13:15:13 +0000719 unsigned long okey, key, nbi = 0;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000720 xmlDictEntryPtr entry;
721 xmlDictEntryPtr insert;
722 const xmlChar *ret;
723 int len;
724
725 if ((dict == NULL) || (name == NULL))
726 return(NULL);
727
728 len = xmlStrlen(name);
729 if (prefix != NULL)
730 len += 1 + xmlStrlen(prefix);
731
732 /*
733 * Check for duplicate and insertion location.
734 */
Daniel Veillard4773df22004-01-23 13:15:13 +0000735 okey = xmlDictComputeQKey(prefix, name, len);
736 key = okey % dict->size;
Daniel Veillarde72c5082003-09-19 12:44:05 +0000737 if (dict->dict[key].valid == 0) {
738 insert = NULL;
739 } else {
740 for (insert = &(dict->dict[key]); insert->next != NULL;
741 insert = insert->next) {
742 if ((insert->len == len) &&
743 (xmlStrQEqual(prefix, name, insert->name)))
744 return(insert->name);
745 nbi++;
746 }
747 if ((insert->len == len) &&
748 (xmlStrQEqual(prefix, name, insert->name)))
749 return(insert->name);
750 }
751
Daniel Veillard4773df22004-01-23 13:15:13 +0000752 if (dict->subdict) {
753 key = okey % dict->subdict->size;
754 if (dict->subdict->dict[key].valid != 0) {
755 xmlDictEntryPtr tmp;
756 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
757 tmp = tmp->next) {
758 if ((tmp->len == len) &&
759 (xmlStrQEqual(prefix, name, tmp->name)))
760 return(tmp->name);
761 nbi++;
762 }
763 if ((tmp->len == len) &&
764 (xmlStrQEqual(prefix, name, tmp->name)))
765 return(tmp->name);
766 }
767 key = okey % dict->size;
768 }
769
Daniel Veillarde72c5082003-09-19 12:44:05 +0000770 ret = xmlDictAddQString(dict, prefix, name, len);
771 if (ret == NULL)
772 return(NULL);
773 if (insert == NULL) {
774 entry = &(dict->dict[key]);
775 } else {
776 entry = xmlMalloc(sizeof(xmlDictEntry));
777 if (entry == NULL)
778 return(NULL);
779 }
780 entry->name = ret;
781 entry->len = len;
782 entry->next = NULL;
783 entry->valid = 1;
784
785 if (insert != NULL)
786 insert->next = entry;
787
788 dict->nbElems++;
789
790 if ((nbi > MAX_HASH_LEN) &&
791 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
792 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
793 /* Note that entry may have been freed at this point by xmlDictGrow */
794
795 return(ret);
796}
797
798/**
Daniel Veillard81514ba2003-09-16 23:17:26 +0000799 * xmlDictOwns:
800 * @dict: the dictionnary
801 * @str: the string
802 *
803 * check if a string is owned by the disctionary
804 *
805 * Returns 1 if true, 0 if false and -1 in case of error
806 * -1 in case of error
807 */
808int
809xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
810 xmlDictStringsPtr pool;
811
812 if ((dict == NULL) || (str == NULL))
813 return(-1);
814 pool = dict->strings;
815 while (pool != NULL) {
William M. Brackbf5cf212004-08-31 06:47:17 +0000816 if ((str >= &pool->array[0]) && (str <= pool->free))
Daniel Veillard81514ba2003-09-16 23:17:26 +0000817 return(1);
818 pool = pool->next;
819 }
Daniel Veillard4773df22004-01-23 13:15:13 +0000820 if (dict->subdict)
821 return(xmlDictOwns(dict->subdict, str));
Daniel Veillard81514ba2003-09-16 23:17:26 +0000822 return(0);
823}
Daniel Veillarde96a2a42003-09-24 21:23:56 +0000824
Daniel Veillard81514ba2003-09-16 23:17:26 +0000825/**
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000826 * xmlDictSize:
827 * @dict: the dictionnary
828 *
829 * Query the number of elements installed in the hash @dict.
830 *
831 * Returns the number of elements in the dictionnary or
832 * -1 in case of error
833 */
834int
835xmlDictSize(xmlDictPtr dict) {
836 if (dict == NULL)
837 return(-1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000838 if (dict->subdict)
839 return(dict->nbElems + dict->subdict->nbElems);
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000840 return(dict->nbElems);
841}
842
843