2 * dict.c: dictionary of reusable strings, just used to avoid allocation
3 * and freeing operations.
5 * Copyright (C) 2003-2012 Daniel Veillard.
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.
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.
16 * Author: daniel@veillard.com
30 * Following http://www.ocert.org/advisories/ocert-2011-003.html
31 * it seems that having hash randomization might be a good idea
32 * when using XML with untrusted data
33 * Note1: that it works correctly only if compiled with WITH_BIG_KEY
34 * which is the default.
35 * Note2: the fast function used for a small dict won't protect very
36 * well but since the attack is based on growing a very big hash
37 * list we will use the BigKey algo as soon as the hash size grows
38 * over MIN_DICT_SIZE so this actually works
40 #if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME)
41 #define DICT_RANDOMIZATION
48 #ifdef HAVE_INTTYPES_H
51 typedef unsigned __int32 uint32_t;
54 #include <libxml/tree.h>
55 #include <libxml/dict.h>
56 #include <libxml/xmlmemory.h>
57 #include <libxml/xmlerror.h>
58 #include <libxml/globals.h>
60 /* #define DEBUG_GROW */
61 /* #define DICT_DEBUG_PATTERNS */
63 #define MAX_HASH_LEN 3
64 #define MIN_DICT_SIZE 128
65 #define MAX_DICT_HASH 8 * 2048
69 #define xmlDictComputeKey(dict, name, len) \
70 (((dict)->size == MIN_DICT_SIZE) ? \
71 xmlDictComputeFastKey(name, len, (dict)->seed) : \
72 xmlDictComputeBigKey(name, len, (dict)->seed))
74 #define xmlDictComputeQKey(dict, prefix, plen, name, len) \
75 (((prefix) == NULL) ? \
76 (xmlDictComputeKey(dict, name, len)) : \
77 (((dict)->size == MIN_DICT_SIZE) ? \
78 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) : \
79 xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
81 #else /* !WITH_BIG_KEY */
82 #define xmlDictComputeKey(dict, name, len) \
83 xmlDictComputeFastKey(name, len, (dict)->seed)
84 #define xmlDictComputeQKey(dict, prefix, plen, name, len) \
85 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
86 #endif /* WITH_BIG_KEY */
89 * An entry in the dictionnary
91 typedef struct _xmlDictEntry xmlDictEntry;
92 typedef xmlDictEntry *xmlDictEntryPtr;
93 struct _xmlDictEntry {
94 struct _xmlDictEntry *next;
101 typedef struct _xmlDictStrings xmlDictStrings;
102 typedef xmlDictStrings *xmlDictStringsPtr;
103 struct _xmlDictStrings {
104 xmlDictStringsPtr next;
112 * The entire dictionnary
117 struct _xmlDictEntry *dict;
120 xmlDictStringsPtr strings;
122 struct _xmlDict *subdict;
123 /* used for randomization */
128 * A mutex for modifying the reference counter for shared
131 static xmlRMutexPtr xmlDictMutex = NULL;
134 * Whether the dictionary mutex was initialized.
136 static int xmlDictInitialized = 0;
138 #ifdef DICT_RANDOMIZATION
141 * Internal data for random function, protected by xmlDictMutex
143 unsigned int rand_seed = 0;
150 * Do the dictionary mutex initialization.
151 * this function is not thread safe, initialization should
152 * preferably be done once at startup
154 * Returns 0 if initialization was already done, and 1 if that
155 * call led to the initialization
157 int xmlInitializeDict(void) {
158 if (xmlDictInitialized)
161 if ((xmlDictMutex = xmlNewRMutex()) == NULL)
163 xmlRMutexLock(xmlDictMutex);
165 #ifdef DICT_RANDOMIZATION
167 rand_seed = time(NULL);
173 xmlDictInitialized = 1;
174 xmlRMutexUnlock(xmlDictMutex);
178 #ifdef DICT_RANDOMIZATION
179 int __xmlRandom(void) {
182 if (xmlDictInitialized == 0)
185 xmlRMutexLock(xmlDictMutex);
187 ret = rand_r(& rand_seed);
191 xmlRMutexUnlock(xmlDictMutex);
199 * Free the dictionary mutex. Do not call unless sure the library
200 * is not in use anymore !
203 xmlDictCleanup(void) {
204 if (!xmlDictInitialized)
207 xmlFreeRMutex(xmlDictMutex);
209 xmlDictInitialized = 0;
214 * @dict: the dictionnary
215 * @name: the name of the userdata
216 * @len: the length of the name, if -1 it is recomputed
218 * Add the string to the array[s]
220 * Returns the pointer of the local string, or NULL in case of error.
222 static const xmlChar *
223 xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
224 xmlDictStringsPtr pool;
226 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
228 #ifdef DICT_DEBUG_PATTERNS
229 fprintf(stderr, "-");
231 pool = dict->strings;
232 while (pool != NULL) {
233 if (pool->end - pool->free > namelen)
235 if (pool->size > size) size = pool->size;
239 * Not found, need to allocate
242 if (size == 0) size = 1000;
243 else size *= 4; /* exponential growth */
244 if (size < 4 * namelen)
245 size = 4 * namelen; /* just in case ! */
246 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
251 pool->free = &pool->array[0];
252 pool->end = &pool->array[size];
253 pool->next = dict->strings;
254 dict->strings = pool;
255 #ifdef DICT_DEBUG_PATTERNS
256 fprintf(stderr, "+");
261 memcpy(pool->free, name, namelen);
262 pool->free += namelen;
270 * @dict: the dictionnary
271 * @prefix: the prefix of the userdata
272 * @plen: the prefix length
273 * @name: the name of the userdata
274 * @len: the length of the name, if -1 it is recomputed
276 * Add the QName to the array[s]
278 * Returns the pointer of the local string, or NULL in case of error.
280 static const xmlChar *
281 xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen,
282 const xmlChar *name, int namelen)
284 xmlDictStringsPtr pool;
286 int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
288 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
290 #ifdef DICT_DEBUG_PATTERNS
291 fprintf(stderr, "=");
293 pool = dict->strings;
294 while (pool != NULL) {
295 if (pool->end - pool->free > namelen + plen + 1)
297 if (pool->size > size) size = pool->size;
301 * Not found, need to allocate
304 if (size == 0) size = 1000;
305 else size *= 4; /* exponential growth */
306 if (size < 4 * (namelen + plen + 1))
307 size = 4 * (namelen + plen + 1); /* just in case ! */
308 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
313 pool->free = &pool->array[0];
314 pool->end = &pool->array[size];
315 pool->next = dict->strings;
316 dict->strings = pool;
317 #ifdef DICT_DEBUG_PATTERNS
318 fprintf(stderr, "+");
323 memcpy(pool->free, prefix, plen);
325 *(pool->free++) = ':';
326 memcpy(pool->free, name, namelen);
327 pool->free += namelen;
335 * xmlDictComputeBigKey:
337 * Calculate a hash key using a good hash function that works well for
338 * larger hash table sizes.
340 * Hash function by "One-at-a-Time Hash" see
341 * http://burtleburtle.net/bob/hash/doobs.html
345 xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
349 if (namelen <= 0 || data == NULL) return(0);
353 for (i = 0;i < namelen; i++) {
355 hash += (hash << 10);
359 hash ^= (hash >> 11);
360 hash += (hash << 15);
366 * xmlDictComputeBigQKey:
368 * Calculate a hash key for two strings using a good hash function
369 * that works well for larger hash table sizes.
371 * Hash function by "One-at-a-Time Hash" see
372 * http://burtleburtle.net/bob/hash/doobs.html
374 * Neither of the two strings must be NULL.
377 xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
378 const xmlChar *name, int len, int seed)
385 for (i = 0;i < plen; i++) {
387 hash += (hash << 10);
391 hash += (hash << 10);
394 for (i = 0;i < len; i++) {
396 hash += (hash << 10);
400 hash ^= (hash >> 11);
401 hash += (hash << 15);
405 #endif /* WITH_BIG_KEY */
408 * xmlDictComputeFastKey:
410 * Calculate a hash key using a fast hash function that works well
411 * for low hash table fill.
414 xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
415 unsigned long value = seed;
417 if (name == NULL) return(0);
421 value += name[namelen - 1];
425 case 10: value += name[9];
426 case 9: value += name[8];
427 case 8: value += name[7];
428 case 7: value += name[6];
429 case 6: value += name[5];
430 case 5: value += name[4];
431 case 4: value += name[3];
432 case 3: value += name[2];
433 case 2: value += name[1];
440 * xmlDictComputeFastQKey:
442 * Calculate a hash key for two strings using a fast hash function
443 * that works well for low hash table fill.
445 * Neither of the two strings must be NULL.
448 xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
449 const xmlChar *name, int len, int seed)
451 unsigned long value = (unsigned long) seed;
454 value += 30 * (unsigned long) ':';
456 value += 30 * (*prefix);
459 value += name[len - (plen + 1 + 1)];
465 case 10: value += prefix[9];
466 case 9: value += prefix[8];
467 case 8: value += prefix[7];
468 case 7: value += prefix[6];
469 case 6: value += prefix[5];
470 case 5: value += prefix[4];
471 case 4: value += prefix[3];
472 case 3: value += prefix[2];
473 case 2: value += prefix[1];
474 case 1: value += prefix[0];
479 value += (unsigned long) ':';
483 case 10: value += name[9];
484 case 9: value += name[8];
485 case 8: value += name[7];
486 case 7: value += name[6];
487 case 6: value += name[5];
488 case 5: value += name[4];
489 case 4: value += name[3];
490 case 3: value += name[2];
491 case 2: value += name[1];
492 case 1: value += name[0];
501 * Create a new dictionary
503 * Returns the newly created dictionnary, or NULL if an error occured.
506 xmlDictCreate(void) {
509 if (!xmlDictInitialized)
510 if (!xmlInitializeDict())
513 #ifdef DICT_DEBUG_PATTERNS
514 fprintf(stderr, "C");
517 dict = xmlMalloc(sizeof(xmlDict));
519 dict->ref_counter = 1;
521 dict->size = MIN_DICT_SIZE;
523 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
524 dict->strings = NULL;
525 dict->subdict = NULL;
527 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
528 #ifdef DICT_RANDOMIZATION
529 dict->seed = __xmlRandom();
542 * @sub: an existing dictionnary
544 * Create a new dictionary, inheriting strings from the read-only
545 * dictionnary @sub. On lookup, strings are first searched in the
546 * new dictionnary, then in @sub, and if not found are created in the
549 * Returns the newly created dictionnary, or NULL if an error occured.
552 xmlDictCreateSub(xmlDictPtr sub) {
553 xmlDictPtr dict = xmlDictCreate();
555 if ((dict != NULL) && (sub != NULL)) {
556 #ifdef DICT_DEBUG_PATTERNS
557 fprintf(stderr, "R");
559 dict->seed = sub->seed;
561 xmlDictReference(dict->subdict);
568 * @dict: the dictionnary
570 * Increment the reference counter of a dictionary
572 * Returns 0 in case of success and -1 in case of error
575 xmlDictReference(xmlDictPtr dict) {
576 if (!xmlDictInitialized)
577 if (!xmlInitializeDict())
580 if (dict == NULL) return -1;
581 xmlRMutexLock(xmlDictMutex);
583 xmlRMutexUnlock(xmlDictMutex);
589 * @dict: the dictionnary
590 * @size: the new size of the dictionnary
592 * resize the dictionnary
594 * Returns 0 in case of success, -1 in case of failure
597 xmlDictGrow(xmlDictPtr dict, int size) {
598 unsigned long key, okey;
600 xmlDictEntryPtr iter, next;
601 struct _xmlDictEntry *olddict;
603 unsigned long nbElem = 0;
615 #ifdef DICT_DEBUG_PATTERNS
616 fprintf(stderr, "*");
619 oldsize = dict->size;
620 olddict = dict->dict;
623 if (oldsize == MIN_DICT_SIZE)
626 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
627 if (dict->dict == NULL) {
628 dict->dict = olddict;
631 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
634 /* If the two loops are merged, there would be situations where
635 a new entry needs to allocated and data copied into it from
636 the main dict. It is nicer to run through the array twice, first
637 copying all the elements in the main array (less probability of
638 allocate) and then the rest, so we only free in the second loop.
640 for (i = 0; i < oldsize; i++) {
641 if (olddict[i].valid == 0)
645 okey = olddict[i].okey;
647 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
648 key = okey % dict->size;
650 if (dict->dict[key].valid == 0) {
651 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
652 dict->dict[key].next = NULL;
653 dict->dict[key].okey = okey;
655 xmlDictEntryPtr entry;
657 entry = xmlMalloc(sizeof(xmlDictEntry));
659 entry->name = olddict[i].name;
660 entry->len = olddict[i].len;
662 entry->next = dict->dict[key].next;
664 dict->dict[key].next = entry;
667 * we don't have much ways to alert from herei
668 * result is loosing an entry and unicity garantee
678 for (i = 0; i < oldsize; i++) {
679 iter = olddict[i].next;
684 * put back the entry in the new dict
690 okey = xmlDictComputeKey(dict, iter->name, iter->len);
691 key = okey % dict->size;
692 if (dict->dict[key].valid == 0) {
693 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
694 dict->dict[key].next = NULL;
695 dict->dict[key].valid = 1;
696 dict->dict[key].okey = okey;
699 iter->next = dict->dict[key].next;
701 dict->dict[key].next = iter;
715 xmlGenericError(xmlGenericErrorContext,
716 "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
724 * @dict: the dictionnary
726 * Free the hash @dict and its contents. The userdata is
727 * deallocated with @f if provided.
730 xmlDictFree(xmlDictPtr dict) {
732 xmlDictEntryPtr iter;
733 xmlDictEntryPtr next;
735 xmlDictStringsPtr pool, nextp;
740 if (!xmlDictInitialized)
741 if (!xmlInitializeDict())
744 /* decrement the counter, it may be shared by a parser and docs */
745 xmlRMutexLock(xmlDictMutex);
747 if (dict->ref_counter > 0) {
748 xmlRMutexUnlock(xmlDictMutex);
752 xmlRMutexUnlock(xmlDictMutex);
754 if (dict->subdict != NULL) {
755 xmlDictFree(dict->subdict);
759 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
760 iter = &(dict->dict[i]);
761 if (iter->valid == 0)
775 pool = dict->strings;
776 while (pool != NULL) {
786 * @dict: the dictionnary
787 * @name: the name of the userdata
788 * @len: the length of the name, if -1 it is recomputed
790 * Add the @name to the dictionnary @dict if not present.
792 * Returns the internal copy of the name or NULL in case of internal error
795 xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
796 unsigned long key, okey, nbi = 0;
797 xmlDictEntryPtr entry;
798 xmlDictEntryPtr insert;
801 if ((dict == NULL) || (name == NULL))
805 len = strlen((const char *) name);
808 * Check for duplicate and insertion location.
810 okey = xmlDictComputeKey(dict, name, len);
811 key = okey % dict->size;
812 if (dict->dict[key].valid == 0) {
815 for (insert = &(dict->dict[key]); insert->next != NULL;
816 insert = insert->next) {
818 if ((insert->okey == okey) && (insert->len == len)) {
819 if (!memcmp(insert->name, name, len))
820 return(insert->name);
823 if ((insert->okey == okey) && (insert->len == len) &&
824 (!xmlStrncmp(insert->name, name, len)))
825 return(insert->name);
830 if ((insert->okey == okey) && (insert->len == len)) {
831 if (!memcmp(insert->name, name, len))
832 return(insert->name);
835 if ((insert->okey == okey) && (insert->len == len) &&
836 (!xmlStrncmp(insert->name, name, len)))
837 return(insert->name);
844 /* we cannot always reuse the same okey for the subdict */
845 if (((dict->size == MIN_DICT_SIZE) &&
846 (dict->subdict->size != MIN_DICT_SIZE)) ||
847 ((dict->size != MIN_DICT_SIZE) &&
848 (dict->subdict->size == MIN_DICT_SIZE)))
849 skey = xmlDictComputeKey(dict->subdict, name, len);
853 key = skey % dict->subdict->size;
854 if (dict->subdict->dict[key].valid != 0) {
857 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
860 if ((tmp->okey == skey) && (tmp->len == len)) {
861 if (!memcmp(tmp->name, name, len))
865 if ((tmp->okey == skey) && (tmp->len == len) &&
866 (!xmlStrncmp(tmp->name, name, len)))
872 if ((tmp->okey == skey) && (tmp->len == len)) {
873 if (!memcmp(tmp->name, name, len))
877 if ((tmp->okey == skey) && (tmp->len == len) &&
878 (!xmlStrncmp(tmp->name, name, len)))
882 key = okey % dict->size;
885 ret = xmlDictAddString(dict, name, len);
888 if (insert == NULL) {
889 entry = &(dict->dict[key]);
891 entry = xmlMalloc(sizeof(xmlDictEntry));
903 insert->next = entry;
907 if ((nbi > MAX_HASH_LEN) &&
908 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
909 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
912 /* Note that entry may have been freed at this point by xmlDictGrow */
919 * @dict: the dictionnary
920 * @name: the name of the userdata
921 * @len: the length of the name, if -1 it is recomputed
923 * Check if the @name exists in the dictionnary @dict.
925 * Returns the internal copy of the name or NULL if not found.
928 xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
929 unsigned long key, okey, nbi = 0;
930 xmlDictEntryPtr insert;
932 if ((dict == NULL) || (name == NULL))
936 len = strlen((const char *) name);
939 * Check for duplicate and insertion location.
941 okey = xmlDictComputeKey(dict, name, len);
942 key = okey % dict->size;
943 if (dict->dict[key].valid == 0) {
946 for (insert = &(dict->dict[key]); insert->next != NULL;
947 insert = insert->next) {
949 if ((insert->okey == okey) && (insert->len == len)) {
950 if (!memcmp(insert->name, name, len))
951 return(insert->name);
954 if ((insert->okey == okey) && (insert->len == len) &&
955 (!xmlStrncmp(insert->name, name, len)))
956 return(insert->name);
961 if ((insert->okey == okey) && (insert->len == len)) {
962 if (!memcmp(insert->name, name, len))
963 return(insert->name);
966 if ((insert->okey == okey) && (insert->len == len) &&
967 (!xmlStrncmp(insert->name, name, len)))
968 return(insert->name);
975 /* we cannot always reuse the same okey for the subdict */
976 if (((dict->size == MIN_DICT_SIZE) &&
977 (dict->subdict->size != MIN_DICT_SIZE)) ||
978 ((dict->size != MIN_DICT_SIZE) &&
979 (dict->subdict->size == MIN_DICT_SIZE)))
980 skey = xmlDictComputeKey(dict->subdict, name, len);
984 key = skey % dict->subdict->size;
985 if (dict->subdict->dict[key].valid != 0) {
988 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
991 if ((tmp->okey == skey) && (tmp->len == len)) {
992 if (!memcmp(tmp->name, name, len))
996 if ((tmp->okey == skey) && (tmp->len == len) &&
997 (!xmlStrncmp(tmp->name, name, len)))
1003 if ((tmp->okey == skey) && (tmp->len == len)) {
1004 if (!memcmp(tmp->name, name, len))
1008 if ((tmp->okey == skey) && (tmp->len == len) &&
1009 (!xmlStrncmp(tmp->name, name, len)))
1021 * @dict: the dictionnary
1022 * @prefix: the prefix
1025 * Add the QName @prefix:@name to the hash @dict if not present.
1027 * Returns the internal copy of the QName or NULL in case of internal error
1030 xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
1031 unsigned long okey, key, nbi = 0;
1032 xmlDictEntryPtr entry;
1033 xmlDictEntryPtr insert;
1037 if ((dict == NULL) || (name == NULL))
1040 return(xmlDictLookup(dict, name, -1));
1042 l = len = strlen((const char *) name);
1043 plen = strlen((const char *) prefix);
1047 * Check for duplicate and insertion location.
1049 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
1050 key = okey % dict->size;
1051 if (dict->dict[key].valid == 0) {
1054 for (insert = &(dict->dict[key]); insert->next != NULL;
1055 insert = insert->next) {
1056 if ((insert->okey == okey) && (insert->len == len) &&
1057 (xmlStrQEqual(prefix, name, insert->name)))
1058 return(insert->name);
1061 if ((insert->okey == okey) && (insert->len == len) &&
1062 (xmlStrQEqual(prefix, name, insert->name)))
1063 return(insert->name);
1066 if (dict->subdict) {
1069 /* we cannot always reuse the same okey for the subdict */
1070 if (((dict->size == MIN_DICT_SIZE) &&
1071 (dict->subdict->size != MIN_DICT_SIZE)) ||
1072 ((dict->size != MIN_DICT_SIZE) &&
1073 (dict->subdict->size == MIN_DICT_SIZE)))
1074 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
1078 key = skey % dict->subdict->size;
1079 if (dict->subdict->dict[key].valid != 0) {
1080 xmlDictEntryPtr tmp;
1081 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1083 if ((tmp->okey == skey) && (tmp->len == len) &&
1084 (xmlStrQEqual(prefix, name, tmp->name)))
1088 if ((tmp->okey == skey) && (tmp->len == len) &&
1089 (xmlStrQEqual(prefix, name, tmp->name)))
1092 key = okey % dict->size;
1095 ret = xmlDictAddQString(dict, prefix, plen, name, l);
1098 if (insert == NULL) {
1099 entry = &(dict->dict[key]);
1101 entry = xmlMalloc(sizeof(xmlDictEntry));
1112 insert->next = entry;
1116 if ((nbi > MAX_HASH_LEN) &&
1117 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1118 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1119 /* Note that entry may have been freed at this point by xmlDictGrow */
1126 * @dict: the dictionnary
1129 * check if a string is owned by the disctionary
1131 * Returns 1 if true, 0 if false and -1 in case of error
1132 * -1 in case of error
1135 xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1136 xmlDictStringsPtr pool;
1138 if ((dict == NULL) || (str == NULL))
1140 pool = dict->strings;
1141 while (pool != NULL) {
1142 if ((str >= &pool->array[0]) && (str <= pool->free))
1147 return(xmlDictOwns(dict->subdict, str));
1153 * @dict: the dictionnary
1155 * Query the number of elements installed in the hash @dict.
1157 * Returns the number of elements in the dictionnary or
1158 * -1 in case of error
1161 xmlDictSize(xmlDictPtr dict) {
1165 return(dict->nbElems + dict->subdict->nbElems);
1166 return(dict->nbElems);
1171 #include "elfgcchack.h"