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
31 * Following http://www.ocert.org/advisories/ocert-2011-003.html
32 * it seems that having hash randomization might be a good idea
33 * when using XML with untrusted data
34 * Note1: that it works correctly only if compiled with WITH_BIG_KEY
35 * which is the default.
36 * Note2: the fast function used for a small dict won't protect very
37 * well but since the attack is based on growing a very big hash
38 * list we will use the BigKey algo as soon as the hash size grows
39 * over MIN_DICT_SIZE so this actually works
41 #if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME)
42 #define DICT_RANDOMIZATION
49 #ifdef HAVE_INTTYPES_H
52 typedef unsigned __int32 uint32_t;
55 #include <libxml/tree.h>
56 #include <libxml/dict.h>
57 #include <libxml/xmlmemory.h>
58 #include <libxml/xmlerror.h>
59 #include <libxml/globals.h>
61 /* #define DEBUG_GROW */
62 /* #define DICT_DEBUG_PATTERNS */
64 #define MAX_HASH_LEN 3
65 #define MIN_DICT_SIZE 128
66 #define MAX_DICT_HASH 8 * 2048
70 #define xmlDictComputeKey(dict, name, len) \
71 (((dict)->size == MIN_DICT_SIZE) ? \
72 xmlDictComputeFastKey(name, len, (dict)->seed) : \
73 xmlDictComputeBigKey(name, len, (dict)->seed))
75 #define xmlDictComputeQKey(dict, prefix, plen, name, len) \
76 (((prefix) == NULL) ? \
77 (xmlDictComputeKey(dict, name, len)) : \
78 (((dict)->size == MIN_DICT_SIZE) ? \
79 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) : \
80 xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
82 #else /* !WITH_BIG_KEY */
83 #define xmlDictComputeKey(dict, name, len) \
84 xmlDictComputeFastKey(name, len, (dict)->seed)
85 #define xmlDictComputeQKey(dict, prefix, plen, name, len) \
86 xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
87 #endif /* WITH_BIG_KEY */
90 * An entry in the dictionary
92 typedef struct _xmlDictEntry xmlDictEntry;
93 typedef xmlDictEntry *xmlDictEntryPtr;
94 struct _xmlDictEntry {
95 struct _xmlDictEntry *next;
102 typedef struct _xmlDictStrings xmlDictStrings;
103 typedef xmlDictStrings *xmlDictStringsPtr;
104 struct _xmlDictStrings {
105 xmlDictStringsPtr next;
113 * The entire dictionary
118 struct _xmlDictEntry *dict;
120 unsigned int nbElems;
121 xmlDictStringsPtr strings;
123 struct _xmlDict *subdict;
124 /* used for randomization */
126 /* used to impose a limit on size */
131 * A mutex for modifying the reference counter for shared
134 static xmlRMutexPtr xmlDictMutex = NULL;
137 * Whether the dictionary mutex was initialized.
139 static int xmlDictInitialized = 0;
141 #ifdef DICT_RANDOMIZATION
144 * Internal data for random function, protected by xmlDictMutex
146 static unsigned int rand_seed = 0;
153 * Do the dictionary mutex initialization.
154 * this function is deprecated
156 * Returns 0 if initialization was already done, and 1 if that
157 * call led to the initialization
159 int xmlInitializeDict(void) {
164 * __xmlInitializeDict:
166 * This function is not public
167 * Do the dictionary mutex initialization.
168 * this function is not thread safe, initialization should
169 * normally be done once at setup when called from xmlOnceInit()
170 * we may also land in this code if thread support is not compiled in
172 * Returns 0 if initialization was already done, and 1 if that
173 * call led to the initialization
175 int __xmlInitializeDict(void) {
176 if (xmlDictInitialized)
179 if ((xmlDictMutex = xmlNewRMutex()) == NULL)
181 xmlRMutexLock(xmlDictMutex);
183 #ifdef DICT_RANDOMIZATION
185 rand_seed = time(NULL);
191 xmlDictInitialized = 1;
192 xmlRMutexUnlock(xmlDictMutex);
196 #ifdef DICT_RANDOMIZATION
197 int __xmlRandom(void) {
200 if (xmlDictInitialized == 0)
201 __xmlInitializeDict();
203 xmlRMutexLock(xmlDictMutex);
205 ret = rand_r(& rand_seed);
209 xmlRMutexUnlock(xmlDictMutex);
217 * Free the dictionary mutex. Do not call unless sure the library
218 * is not in use anymore !
221 xmlDictCleanup(void) {
222 if (!xmlDictInitialized)
225 xmlFreeRMutex(xmlDictMutex);
227 xmlDictInitialized = 0;
232 * @dict: the dictionary
233 * @name: the name of the userdata
234 * @len: the length of the name
236 * Add the string to the array[s]
238 * Returns the pointer of the local string, or NULL in case of error.
240 static const xmlChar *
241 xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
242 xmlDictStringsPtr pool;
244 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
247 #ifdef DICT_DEBUG_PATTERNS
248 fprintf(stderr, "-");
250 pool = dict->strings;
251 while (pool != NULL) {
252 if ((size_t)(pool->end - pool->free) > namelen)
254 if (pool->size > size) size = pool->size;
259 * Not found, need to allocate
262 if ((dict->limit > 0) && (limit > dict->limit)) {
266 if (size == 0) size = 1000;
267 else size *= 4; /* exponential growth */
268 if (size < 4 * namelen)
269 size = 4 * namelen; /* just in case ! */
270 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
275 pool->free = &pool->array[0];
276 pool->end = &pool->array[size];
277 pool->next = dict->strings;
278 dict->strings = pool;
279 #ifdef DICT_DEBUG_PATTERNS
280 fprintf(stderr, "+");
285 memcpy(pool->free, name, namelen);
286 pool->free += namelen;
294 * @dict: the dictionary
295 * @prefix: the prefix of the userdata
296 * @plen: the prefix length
297 * @name: the name of the userdata
298 * @len: the length of the name
300 * Add the QName to the array[s]
302 * Returns the pointer of the local string, or NULL in case of error.
304 static const xmlChar *
305 xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
306 const xmlChar *name, unsigned int namelen)
308 xmlDictStringsPtr pool;
310 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
313 if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
315 #ifdef DICT_DEBUG_PATTERNS
316 fprintf(stderr, "=");
318 pool = dict->strings;
319 while (pool != NULL) {
320 if ((size_t)(pool->end - pool->free) > namelen + plen + 1)
322 if (pool->size > size) size = pool->size;
327 * Not found, need to allocate
330 if ((dict->limit > 0) && (limit > dict->limit)) {
334 if (size == 0) size = 1000;
335 else size *= 4; /* exponential growth */
336 if (size < 4 * (namelen + plen + 1))
337 size = 4 * (namelen + plen + 1); /* just in case ! */
338 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
343 pool->free = &pool->array[0];
344 pool->end = &pool->array[size];
345 pool->next = dict->strings;
346 dict->strings = pool;
347 #ifdef DICT_DEBUG_PATTERNS
348 fprintf(stderr, "+");
353 memcpy(pool->free, prefix, plen);
355 *(pool->free++) = ':';
356 memcpy(pool->free, name, namelen);
357 pool->free += namelen;
365 * xmlDictComputeBigKey:
367 * Calculate a hash key using a good hash function that works well for
368 * larger hash table sizes.
370 * Hash function by "One-at-a-Time Hash" see
371 * http://burtleburtle.net/bob/hash/doobs.html
375 xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
379 if (namelen <= 0 || data == NULL) return(0);
383 for (i = 0;i < namelen; i++) {
385 hash += (hash << 10);
389 hash ^= (hash >> 11);
390 hash += (hash << 15);
396 * xmlDictComputeBigQKey:
398 * Calculate a hash key for two strings using a good hash function
399 * that works well for larger hash table sizes.
401 * Hash function by "One-at-a-Time Hash" see
402 * http://burtleburtle.net/bob/hash/doobs.html
404 * Neither of the two strings must be NULL.
407 xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
408 const xmlChar *name, int len, int seed)
415 for (i = 0;i < plen; i++) {
417 hash += (hash << 10);
421 hash += (hash << 10);
424 for (i = 0;i < len; i++) {
426 hash += (hash << 10);
430 hash ^= (hash >> 11);
431 hash += (hash << 15);
435 #endif /* WITH_BIG_KEY */
438 * xmlDictComputeFastKey:
440 * Calculate a hash key using a fast hash function that works well
441 * for low hash table fill.
444 xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
445 unsigned long value = seed;
447 if (name == NULL) return(0);
451 value += name[namelen - 1];
455 case 10: value += name[9];
457 case 9: value += name[8];
459 case 8: value += name[7];
461 case 7: value += name[6];
463 case 6: value += name[5];
465 case 5: value += name[4];
467 case 4: value += name[3];
469 case 3: value += name[2];
471 case 2: value += name[1];
479 * xmlDictComputeFastQKey:
481 * Calculate a hash key for two strings using a fast hash function
482 * that works well for low hash table fill.
484 * Neither of the two strings must be NULL.
487 xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
488 const xmlChar *name, int len, int seed)
490 unsigned long value = (unsigned long) seed;
493 value += 30 * (unsigned long) ':';
495 value += 30 * (*prefix);
498 int offset = len - (plen + 1 + 1);
500 offset = len - (10 + 1);
501 value += name[offset];
507 case 10: value += prefix[9];
509 case 9: value += prefix[8];
511 case 8: value += prefix[7];
513 case 7: value += prefix[6];
515 case 6: value += prefix[5];
517 case 5: value += prefix[4];
519 case 4: value += prefix[3];
521 case 3: value += prefix[2];
523 case 2: value += prefix[1];
525 case 1: value += prefix[0];
531 value += (unsigned long) ':';
535 case 10: value += name[9];
537 case 9: value += name[8];
539 case 8: value += name[7];
541 case 7: value += name[6];
543 case 6: value += name[5];
545 case 5: value += name[4];
547 case 4: value += name[3];
549 case 3: value += name[2];
551 case 2: value += name[1];
553 case 1: value += name[0];
563 * Create a new dictionary
565 * Returns the newly created dictionary, or NULL if an error occurred.
568 xmlDictCreate(void) {
571 if (!xmlDictInitialized)
572 if (!__xmlInitializeDict())
575 #ifdef DICT_DEBUG_PATTERNS
576 fprintf(stderr, "C");
579 dict = xmlMalloc(sizeof(xmlDict));
581 dict->ref_counter = 1;
584 dict->size = MIN_DICT_SIZE;
586 dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
587 dict->strings = NULL;
588 dict->subdict = NULL;
590 memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
591 #ifdef DICT_RANDOMIZATION
592 dict->seed = __xmlRandom();
605 * @sub: an existing dictionary
607 * Create a new dictionary, inheriting strings from the read-only
608 * dictionary @sub. On lookup, strings are first searched in the
609 * new dictionary, then in @sub, and if not found are created in the
612 * Returns the newly created dictionary, or NULL if an error occurred.
615 xmlDictCreateSub(xmlDictPtr sub) {
616 xmlDictPtr dict = xmlDictCreate();
618 if ((dict != NULL) && (sub != NULL)) {
619 #ifdef DICT_DEBUG_PATTERNS
620 fprintf(stderr, "R");
622 dict->seed = sub->seed;
624 xmlDictReference(dict->subdict);
631 * @dict: the dictionary
633 * Increment the reference counter of a dictionary
635 * Returns 0 in case of success and -1 in case of error
638 xmlDictReference(xmlDictPtr dict) {
639 if (!xmlDictInitialized)
640 if (!__xmlInitializeDict())
643 if (dict == NULL) return -1;
644 xmlRMutexLock(xmlDictMutex);
646 xmlRMutexUnlock(xmlDictMutex);
652 * @dict: the dictionary
653 * @size: the new size of the dictionary
655 * resize the dictionary
657 * Returns 0 in case of success, -1 in case of failure
660 xmlDictGrow(xmlDictPtr dict, size_t size) {
661 unsigned long key, okey;
663 xmlDictEntryPtr iter, next;
664 struct _xmlDictEntry *olddict;
666 unsigned long nbElem = 0;
678 #ifdef DICT_DEBUG_PATTERNS
679 fprintf(stderr, "*");
682 oldsize = dict->size;
683 olddict = dict->dict;
686 if (oldsize == MIN_DICT_SIZE)
689 dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
690 if (dict->dict == NULL) {
691 dict->dict = olddict;
694 memset(dict->dict, 0, size * sizeof(xmlDictEntry));
697 /* If the two loops are merged, there would be situations where
698 a new entry needs to allocated and data copied into it from
699 the main dict. It is nicer to run through the array twice, first
700 copying all the elements in the main array (less probability of
701 allocate) and then the rest, so we only free in the second loop.
703 for (i = 0; i < oldsize; i++) {
704 if (olddict[i].valid == 0)
708 okey = olddict[i].okey;
710 okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
711 key = okey % dict->size;
713 if (dict->dict[key].valid == 0) {
714 memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
715 dict->dict[key].next = NULL;
716 dict->dict[key].okey = okey;
718 xmlDictEntryPtr entry;
720 entry = xmlMalloc(sizeof(xmlDictEntry));
722 entry->name = olddict[i].name;
723 entry->len = olddict[i].len;
725 entry->next = dict->dict[key].next;
727 dict->dict[key].next = entry;
730 * we don't have much ways to alert from herei
731 * result is losing an entry and unicity guarantee
741 for (i = 0; i < oldsize; i++) {
742 iter = olddict[i].next;
747 * put back the entry in the new dict
753 okey = xmlDictComputeKey(dict, iter->name, iter->len);
754 key = okey % dict->size;
755 if (dict->dict[key].valid == 0) {
756 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
757 dict->dict[key].next = NULL;
758 dict->dict[key].valid = 1;
759 dict->dict[key].okey = okey;
762 iter->next = dict->dict[key].next;
764 dict->dict[key].next = iter;
778 xmlGenericError(xmlGenericErrorContext,
779 "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
787 * @dict: the dictionary
789 * Free the hash @dict and its contents. The userdata is
790 * deallocated with @f if provided.
793 xmlDictFree(xmlDictPtr dict) {
795 xmlDictEntryPtr iter;
796 xmlDictEntryPtr next;
798 xmlDictStringsPtr pool, nextp;
803 if (!xmlDictInitialized)
804 if (!__xmlInitializeDict())
807 /* decrement the counter, it may be shared by a parser and docs */
808 xmlRMutexLock(xmlDictMutex);
810 if (dict->ref_counter > 0) {
811 xmlRMutexUnlock(xmlDictMutex);
815 xmlRMutexUnlock(xmlDictMutex);
817 if (dict->subdict != NULL) {
818 xmlDictFree(dict->subdict);
822 for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
823 iter = &(dict->dict[i]);
824 if (iter->valid == 0)
838 pool = dict->strings;
839 while (pool != NULL) {
849 * @dict: the dictionary
850 * @name: the name of the userdata
851 * @len: the length of the name, if -1 it is recomputed
853 * Add the @name to the dictionary @dict if not present.
855 * Returns the internal copy of the name or NULL in case of internal error
858 xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
859 unsigned long key, okey, nbi = 0;
860 xmlDictEntryPtr entry;
861 xmlDictEntryPtr insert;
865 if ((dict == NULL) || (name == NULL))
869 l = strlen((const char *) name);
873 if (((dict->limit > 0) && (l >= dict->limit)) ||
878 * Check for duplicate and insertion location.
880 okey = xmlDictComputeKey(dict, name, l);
881 key = okey % dict->size;
882 if (dict->dict[key].valid == 0) {
885 for (insert = &(dict->dict[key]); insert->next != NULL;
886 insert = insert->next) {
888 if ((insert->okey == okey) && (insert->len == l)) {
889 if (!memcmp(insert->name, name, l))
890 return(insert->name);
893 if ((insert->okey == okey) && (insert->len == l) &&
894 (!xmlStrncmp(insert->name, name, l)))
895 return(insert->name);
900 if ((insert->okey == okey) && (insert->len == l)) {
901 if (!memcmp(insert->name, name, l))
902 return(insert->name);
905 if ((insert->okey == okey) && (insert->len == l) &&
906 (!xmlStrncmp(insert->name, name, l)))
907 return(insert->name);
914 /* we cannot always reuse the same okey for the subdict */
915 if (((dict->size == MIN_DICT_SIZE) &&
916 (dict->subdict->size != MIN_DICT_SIZE)) ||
917 ((dict->size != MIN_DICT_SIZE) &&
918 (dict->subdict->size == MIN_DICT_SIZE)))
919 skey = xmlDictComputeKey(dict->subdict, name, l);
923 key = skey % dict->subdict->size;
924 if (dict->subdict->dict[key].valid != 0) {
927 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
930 if ((tmp->okey == skey) && (tmp->len == l)) {
931 if (!memcmp(tmp->name, name, l))
935 if ((tmp->okey == skey) && (tmp->len == l) &&
936 (!xmlStrncmp(tmp->name, name, l)))
942 if ((tmp->okey == skey) && (tmp->len == l)) {
943 if (!memcmp(tmp->name, name, l))
947 if ((tmp->okey == skey) && (tmp->len == l) &&
948 (!xmlStrncmp(tmp->name, name, l)))
952 key = okey % dict->size;
955 ret = xmlDictAddString(dict, name, l);
958 if (insert == NULL) {
959 entry = &(dict->dict[key]);
961 entry = xmlMalloc(sizeof(xmlDictEntry));
973 insert->next = entry;
977 if ((nbi > MAX_HASH_LEN) &&
978 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
979 if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
982 /* Note that entry may have been freed at this point by xmlDictGrow */
989 * @dict: the dictionary
990 * @name: the name of the userdata
991 * @len: the length of the name, if -1 it is recomputed
993 * Check if the @name exists in the dictionary @dict.
995 * Returns the internal copy of the name or NULL if not found.
998 xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
999 unsigned long key, okey, nbi = 0;
1000 xmlDictEntryPtr insert;
1003 if ((dict == NULL) || (name == NULL))
1007 l = strlen((const char *) name);
1010 if (((dict->limit > 0) && (l >= dict->limit)) ||
1015 * Check for duplicate and insertion location.
1017 okey = xmlDictComputeKey(dict, name, l);
1018 key = okey % dict->size;
1019 if (dict->dict[key].valid == 0) {
1022 for (insert = &(dict->dict[key]); insert->next != NULL;
1023 insert = insert->next) {
1025 if ((insert->okey == okey) && (insert->len == l)) {
1026 if (!memcmp(insert->name, name, l))
1027 return(insert->name);
1030 if ((insert->okey == okey) && (insert->len == l) &&
1031 (!xmlStrncmp(insert->name, name, l)))
1032 return(insert->name);
1037 if ((insert->okey == okey) && (insert->len == l)) {
1038 if (!memcmp(insert->name, name, l))
1039 return(insert->name);
1042 if ((insert->okey == okey) && (insert->len == l) &&
1043 (!xmlStrncmp(insert->name, name, l)))
1044 return(insert->name);
1048 if (dict->subdict) {
1051 /* we cannot always reuse the same okey for the subdict */
1052 if (((dict->size == MIN_DICT_SIZE) &&
1053 (dict->subdict->size != MIN_DICT_SIZE)) ||
1054 ((dict->size != MIN_DICT_SIZE) &&
1055 (dict->subdict->size == MIN_DICT_SIZE)))
1056 skey = xmlDictComputeKey(dict->subdict, name, l);
1060 key = skey % dict->subdict->size;
1061 if (dict->subdict->dict[key].valid != 0) {
1062 xmlDictEntryPtr tmp;
1064 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1067 if ((tmp->okey == skey) && (tmp->len == l)) {
1068 if (!memcmp(tmp->name, name, l))
1072 if ((tmp->okey == skey) && (tmp->len == l) &&
1073 (!xmlStrncmp(tmp->name, name, l)))
1079 if ((tmp->okey == skey) && (tmp->len == l)) {
1080 if (!memcmp(tmp->name, name, l))
1084 if ((tmp->okey == skey) && (tmp->len == l) &&
1085 (!xmlStrncmp(tmp->name, name, l)))
1097 * @dict: the dictionary
1098 * @prefix: the prefix
1101 * Add the QName @prefix:@name to the hash @dict if not present.
1103 * Returns the internal copy of the QName or NULL in case of internal error
1106 xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
1107 unsigned long okey, key, nbi = 0;
1108 xmlDictEntryPtr entry;
1109 xmlDictEntryPtr insert;
1111 unsigned int len, plen, l;
1113 if ((dict == NULL) || (name == NULL))
1116 return(xmlDictLookup(dict, name, -1));
1118 l = len = strlen((const char *) name);
1119 plen = strlen((const char *) prefix);
1123 * Check for duplicate and insertion location.
1125 okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
1126 key = okey % dict->size;
1127 if (dict->dict[key].valid == 0) {
1130 for (insert = &(dict->dict[key]); insert->next != NULL;
1131 insert = insert->next) {
1132 if ((insert->okey == okey) && (insert->len == len) &&
1133 (xmlStrQEqual(prefix, name, insert->name)))
1134 return(insert->name);
1137 if ((insert->okey == okey) && (insert->len == len) &&
1138 (xmlStrQEqual(prefix, name, insert->name)))
1139 return(insert->name);
1142 if (dict->subdict) {
1145 /* we cannot always reuse the same okey for the subdict */
1146 if (((dict->size == MIN_DICT_SIZE) &&
1147 (dict->subdict->size != MIN_DICT_SIZE)) ||
1148 ((dict->size != MIN_DICT_SIZE) &&
1149 (dict->subdict->size == MIN_DICT_SIZE)))
1150 skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
1154 key = skey % dict->subdict->size;
1155 if (dict->subdict->dict[key].valid != 0) {
1156 xmlDictEntryPtr tmp;
1157 for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1159 if ((tmp->okey == skey) && (tmp->len == len) &&
1160 (xmlStrQEqual(prefix, name, tmp->name)))
1164 if ((tmp->okey == skey) && (tmp->len == len) &&
1165 (xmlStrQEqual(prefix, name, tmp->name)))
1168 key = okey % dict->size;
1171 ret = xmlDictAddQString(dict, prefix, plen, name, l);
1174 if (insert == NULL) {
1175 entry = &(dict->dict[key]);
1177 entry = xmlMalloc(sizeof(xmlDictEntry));
1188 insert->next = entry;
1192 if ((nbi > MAX_HASH_LEN) &&
1193 (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1194 xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1195 /* Note that entry may have been freed at this point by xmlDictGrow */
1202 * @dict: the dictionary
1205 * check if a string is owned by the disctionary
1207 * Returns 1 if true, 0 if false and -1 in case of error
1208 * -1 in case of error
1211 xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1212 xmlDictStringsPtr pool;
1214 if ((dict == NULL) || (str == NULL))
1216 pool = dict->strings;
1217 while (pool != NULL) {
1218 if ((str >= &pool->array[0]) && (str <= pool->free))
1223 return(xmlDictOwns(dict->subdict, str));
1229 * @dict: the dictionary
1231 * Query the number of elements installed in the hash @dict.
1233 * Returns the number of elements in the dictionary or
1234 * -1 in case of error
1237 xmlDictSize(xmlDictPtr dict) {
1241 return(dict->nbElems + dict->subdict->nbElems);
1242 return(dict->nbElems);
1247 * @dict: the dictionary
1248 * @limit: the limit in bytes
1250 * Set a size limit for the dictionary
1253 * Returns the previous limit of the dictionary or 0
1256 xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
1262 dict->limit = limit;
1268 * @dict: the dictionary
1270 * Get how much memory is used by a dictionary for strings
1273 * Returns the amount of strings allocated
1276 xmlDictGetUsage(xmlDictPtr dict) {
1277 xmlDictStringsPtr pool;
1282 pool = dict->strings;
1283 while (pool != NULL) {
1284 limit += pool->size;
1291 #include "elfgcchack.h"