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 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
16 * Author: daniel@veillard.com
26 #include "private/dict.h"
27 #include "private/threads.h"
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(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
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 dictionary
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 dictionary
117 struct _xmlDictEntry
*dict
;
119 unsigned int nbElems
;
120 xmlDictStringsPtr strings
;
122 struct _xmlDict
*subdict
;
123 /* used for randomization */
125 /* used to impose a limit on size */
130 * A mutex for modifying the reference counter for shared
133 static xmlMutex xmlDictMutex
;
135 #ifdef DICT_RANDOMIZATION
138 * Internal data for random function, protected by xmlDictMutex
140 static unsigned int rand_seed
= 0;
147 * DEPRECATED: Alias for xmlInitParser.
149 int xmlInitializeDict(void) {
155 * __xmlInitializeDict:
157 * This function is not public
158 * Do the dictionary mutex initialization.
160 int __xmlInitializeDict(void) {
161 xmlInitMutex(&xmlDictMutex
);
163 #ifdef DICT_RANDOMIZATION
165 rand_seed
= time(NULL
);
174 #ifdef DICT_RANDOMIZATION
175 int __xmlRandom(void) {
178 xmlMutexLock(&xmlDictMutex
);
180 ret
= rand_r(& rand_seed
);
184 xmlMutexUnlock(&xmlDictMutex
);
192 * DEPRECATED: This function is a no-op. Call xmlCleanupParser
193 * to free global state but see the warnings there. xmlCleanupParser
194 * should be only called once at program exit. In most cases, you don't
195 * have call cleanup functions at all.
198 xmlDictCleanup(void) {
202 * xmlCleanupDictInternal:
204 * Free the dictionary mutex.
207 xmlCleanupDictInternal(void) {
208 xmlCleanupMutex(&xmlDictMutex
);
213 * @dict: the dictionary
214 * @name: the name of the userdata
215 * @len: the length of the name
217 * Add the string to the array[s]
219 * Returns the pointer of the local string, or NULL in case of error.
221 static const xmlChar
*
222 xmlDictAddString(xmlDictPtr dict
, const xmlChar
*name
, unsigned int namelen
) {
223 xmlDictStringsPtr pool
;
225 size_t size
= 0; /* + sizeof(_xmlDictStrings) == 1024 */
228 #ifdef DICT_DEBUG_PATTERNS
229 fprintf(stderr
, "-");
231 pool
= dict
->strings
;
232 while (pool
!= NULL
) {
233 if ((size_t)(pool
->end
- pool
->free
) > namelen
)
235 if (pool
->size
> size
) size
= pool
->size
;
240 * Not found, need to allocate
243 if ((dict
->limit
> 0) && (limit
> dict
->limit
)) {
247 if (size
== 0) size
= 1000;
248 else size
*= 4; /* exponential growth */
249 if (size
< 4 * namelen
)
250 size
= 4 * namelen
; /* just in case ! */
251 pool
= (xmlDictStringsPtr
) xmlMalloc(sizeof(xmlDictStrings
) + size
);
256 pool
->free
= &pool
->array
[0];
257 pool
->end
= &pool
->array
[size
];
258 pool
->next
= dict
->strings
;
259 dict
->strings
= pool
;
260 #ifdef DICT_DEBUG_PATTERNS
261 fprintf(stderr
, "+");
266 memcpy(pool
->free
, name
, namelen
);
267 pool
->free
+= namelen
;
275 * @dict: the dictionary
276 * @prefix: the prefix of the userdata
277 * @plen: the prefix length
278 * @name: the name of the userdata
279 * @len: the length of the name
281 * Add the QName to the array[s]
283 * Returns the pointer of the local string, or NULL in case of error.
285 static const xmlChar
*
286 xmlDictAddQString(xmlDictPtr dict
, const xmlChar
*prefix
, unsigned int plen
,
287 const xmlChar
*name
, unsigned int namelen
)
289 xmlDictStringsPtr pool
;
291 size_t size
= 0; /* + sizeof(_xmlDictStrings) == 1024 */
294 if (prefix
== NULL
) return(xmlDictAddString(dict
, name
, namelen
));
296 #ifdef DICT_DEBUG_PATTERNS
297 fprintf(stderr
, "=");
299 pool
= dict
->strings
;
300 while (pool
!= NULL
) {
301 if ((size_t)(pool
->end
- pool
->free
) > namelen
+ plen
+ 1)
303 if (pool
->size
> size
) size
= pool
->size
;
308 * Not found, need to allocate
311 if ((dict
->limit
> 0) && (limit
> dict
->limit
)) {
315 if (size
== 0) size
= 1000;
316 else size
*= 4; /* exponential growth */
317 if (size
< 4 * (namelen
+ plen
+ 1))
318 size
= 4 * (namelen
+ plen
+ 1); /* just in case ! */
319 pool
= (xmlDictStringsPtr
) xmlMalloc(sizeof(xmlDictStrings
) + size
);
324 pool
->free
= &pool
->array
[0];
325 pool
->end
= &pool
->array
[size
];
326 pool
->next
= dict
->strings
;
327 dict
->strings
= pool
;
328 #ifdef DICT_DEBUG_PATTERNS
329 fprintf(stderr
, "+");
334 memcpy(pool
->free
, prefix
, plen
);
336 *(pool
->free
++) = ':';
337 memcpy(pool
->free
, name
, namelen
);
338 pool
->free
+= namelen
;
346 * xmlDictComputeBigKey:
348 * Calculate a hash key using a good hash function that works well for
349 * larger hash table sizes.
351 * Hash function by "One-at-a-Time Hash" see
352 * http://burtleburtle.net/bob/hash/doobs.html
356 ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
357 ATTRIBUTE_NO_SANITIZE("unsigned-shift-base")
360 xmlDictComputeBigKey(const xmlChar
* data
, int namelen
, int seed
) {
364 if (namelen
<= 0 || data
== NULL
) return(0);
368 for (i
= 0;i
< namelen
; i
++) {
370 hash
+= (hash
<< 10);
374 hash
^= (hash
>> 11);
375 hash
+= (hash
<< 15);
381 * xmlDictComputeBigQKey:
383 * Calculate a hash key for two strings using a good hash function
384 * that works well for larger hash table sizes.
386 * Hash function by "One-at-a-Time Hash" see
387 * http://burtleburtle.net/bob/hash/doobs.html
389 * Neither of the two strings must be NULL.
392 ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
393 ATTRIBUTE_NO_SANITIZE("unsigned-shift-base")
396 xmlDictComputeBigQKey(const xmlChar
*prefix
, int plen
,
397 const xmlChar
*name
, int len
, int seed
)
404 for (i
= 0;i
< plen
; i
++) {
406 hash
+= (hash
<< 10);
410 hash
+= (hash
<< 10);
413 for (i
= 0;i
< len
; i
++) {
415 hash
+= (hash
<< 10);
419 hash
^= (hash
>> 11);
420 hash
+= (hash
<< 15);
424 #endif /* WITH_BIG_KEY */
427 * xmlDictComputeFastKey:
429 * Calculate a hash key using a fast hash function that works well
430 * for low hash table fill.
433 xmlDictComputeFastKey(const xmlChar
*name
, int namelen
, int seed
) {
434 unsigned long value
= seed
;
436 if ((name
== NULL
) || (namelen
<= 0))
441 value
+= name
[namelen
- 1];
445 case 10: value
+= name
[9];
447 case 9: value
+= name
[8];
449 case 8: value
+= name
[7];
451 case 7: value
+= name
[6];
453 case 6: value
+= name
[5];
455 case 5: value
+= name
[4];
457 case 4: value
+= name
[3];
459 case 3: value
+= name
[2];
461 case 2: value
+= name
[1];
469 * xmlDictComputeFastQKey:
471 * Calculate a hash key for two strings using a fast hash function
472 * that works well for low hash table fill.
474 * Neither of the two strings must be NULL.
477 xmlDictComputeFastQKey(const xmlChar
*prefix
, int plen
,
478 const xmlChar
*name
, int len
, int seed
)
480 unsigned long value
= seed
;
485 value
+= 30 * (*prefix
);
488 int offset
= len
- (plen
+ 1 + 1);
490 offset
= len
- (10 + 1);
491 value
+= name
[offset
];
497 case 10: value
+= prefix
[9];
499 case 9: value
+= prefix
[8];
501 case 8: value
+= prefix
[7];
503 case 7: value
+= prefix
[6];
505 case 6: value
+= prefix
[5];
507 case 5: value
+= prefix
[4];
509 case 4: value
+= prefix
[3];
511 case 3: value
+= prefix
[2];
513 case 2: value
+= prefix
[1];
515 case 1: value
+= prefix
[0];
525 case 10: value
+= name
[9];
527 case 9: value
+= name
[8];
529 case 8: value
+= name
[7];
531 case 7: value
+= name
[6];
533 case 6: value
+= name
[5];
535 case 5: value
+= name
[4];
537 case 4: value
+= name
[3];
539 case 3: value
+= name
[2];
541 case 2: value
+= name
[1];
543 case 1: value
+= name
[0];
553 * Create a new dictionary
555 * Returns the newly created dictionary, or NULL if an error occurred.
558 xmlDictCreate(void) {
563 #ifdef DICT_DEBUG_PATTERNS
564 fprintf(stderr
, "C");
567 dict
= xmlMalloc(sizeof(xmlDict
));
569 dict
->ref_counter
= 1;
572 dict
->size
= MIN_DICT_SIZE
;
574 dict
->dict
= xmlMalloc(MIN_DICT_SIZE
* sizeof(xmlDictEntry
));
575 dict
->strings
= NULL
;
576 dict
->subdict
= NULL
;
578 memset(dict
->dict
, 0, MIN_DICT_SIZE
* sizeof(xmlDictEntry
));
579 #ifdef DICT_RANDOMIZATION
580 dict
->seed
= __xmlRandom();
593 * @sub: an existing dictionary
595 * Create a new dictionary, inheriting strings from the read-only
596 * dictionary @sub. On lookup, strings are first searched in the
597 * new dictionary, then in @sub, and if not found are created in the
600 * Returns the newly created dictionary, or NULL if an error occurred.
603 xmlDictCreateSub(xmlDictPtr sub
) {
604 xmlDictPtr dict
= xmlDictCreate();
606 if ((dict
!= NULL
) && (sub
!= NULL
)) {
607 #ifdef DICT_DEBUG_PATTERNS
608 fprintf(stderr
, "R");
610 dict
->seed
= sub
->seed
;
612 xmlDictReference(dict
->subdict
);
619 * @dict: the dictionary
621 * Increment the reference counter of a dictionary
623 * Returns 0 in case of success and -1 in case of error
626 xmlDictReference(xmlDictPtr dict
) {
627 if (dict
== NULL
) return -1;
628 xmlMutexLock(&xmlDictMutex
);
630 xmlMutexUnlock(&xmlDictMutex
);
636 * @dict: the dictionary
637 * @size: the new size of the dictionary
639 * resize the dictionary
641 * Returns 0 in case of success, -1 in case of failure
644 xmlDictGrow(xmlDictPtr dict
, size_t size
) {
645 unsigned long key
, okey
;
647 xmlDictEntryPtr iter
, next
;
648 struct _xmlDictEntry
*olddict
;
650 unsigned long nbElem
= 0;
662 #ifdef DICT_DEBUG_PATTERNS
663 fprintf(stderr
, "*");
666 oldsize
= dict
->size
;
667 olddict
= dict
->dict
;
670 if (oldsize
== MIN_DICT_SIZE
)
673 dict
->dict
= xmlMalloc(size
* sizeof(xmlDictEntry
));
674 if (dict
->dict
== NULL
) {
675 dict
->dict
= olddict
;
678 memset(dict
->dict
, 0, size
* sizeof(xmlDictEntry
));
681 /* If the two loops are merged, there would be situations where
682 a new entry needs to allocated and data copied into it from
683 the main dict. It is nicer to run through the array twice, first
684 copying all the elements in the main array (less probability of
685 allocate) and then the rest, so we only free in the second loop.
687 for (i
= 0; i
< oldsize
; i
++) {
688 if (olddict
[i
].valid
== 0)
692 okey
= olddict
[i
].okey
;
694 okey
= xmlDictComputeKey(dict
, olddict
[i
].name
, olddict
[i
].len
);
695 key
= okey
% dict
->size
;
697 if (dict
->dict
[key
].valid
== 0) {
698 memcpy(&(dict
->dict
[key
]), &(olddict
[i
]), sizeof(xmlDictEntry
));
699 dict
->dict
[key
].next
= NULL
;
700 dict
->dict
[key
].okey
= okey
;
702 xmlDictEntryPtr entry
;
704 entry
= xmlMalloc(sizeof(xmlDictEntry
));
706 entry
->name
= olddict
[i
].name
;
707 entry
->len
= olddict
[i
].len
;
709 entry
->next
= dict
->dict
[key
].next
;
711 dict
->dict
[key
].next
= entry
;
714 * we don't have much ways to alert from here
715 * result is losing an entry and unicity guarantee
725 for (i
= 0; i
< oldsize
; i
++) {
726 iter
= olddict
[i
].next
;
731 * put back the entry in the new dict
737 okey
= xmlDictComputeKey(dict
, iter
->name
, iter
->len
);
738 key
= okey
% dict
->size
;
739 if (dict
->dict
[key
].valid
== 0) {
740 memcpy(&(dict
->dict
[key
]), iter
, sizeof(xmlDictEntry
));
741 dict
->dict
[key
].next
= NULL
;
742 dict
->dict
[key
].valid
= 1;
743 dict
->dict
[key
].okey
= okey
;
746 iter
->next
= dict
->dict
[key
].next
;
748 dict
->dict
[key
].next
= iter
;
762 xmlGenericError(xmlGenericErrorContext
,
763 "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize
, size
, nbElem
);
771 * @dict: the dictionary
773 * Free the hash @dict and its contents. The userdata is
774 * deallocated with @f if provided.
777 xmlDictFree(xmlDictPtr dict
) {
779 xmlDictEntryPtr iter
;
780 xmlDictEntryPtr next
;
782 xmlDictStringsPtr pool
, nextp
;
787 /* decrement the counter, it may be shared by a parser and docs */
788 xmlMutexLock(&xmlDictMutex
);
790 if (dict
->ref_counter
> 0) {
791 xmlMutexUnlock(&xmlDictMutex
);
795 xmlMutexUnlock(&xmlDictMutex
);
797 if (dict
->subdict
!= NULL
) {
798 xmlDictFree(dict
->subdict
);
802 for(i
= 0; ((i
< dict
->size
) && (dict
->nbElems
> 0)); i
++) {
803 iter
= &(dict
->dict
[i
]);
804 if (iter
->valid
== 0)
818 pool
= dict
->strings
;
819 while (pool
!= NULL
) {
829 * @dict: the dictionary
830 * @name: the name of the userdata
831 * @len: the length of the name, if -1 it is recomputed
833 * Add the @name to the dictionary @dict if not present.
835 * Returns the internal copy of the name or NULL in case of internal error
838 xmlDictLookup(xmlDictPtr dict
, const xmlChar
*name
, int len
) {
839 unsigned long key
, okey
, nbi
= 0;
840 xmlDictEntryPtr entry
;
841 xmlDictEntryPtr insert
;
845 if ((dict
== NULL
) || (name
== NULL
))
849 l
= strlen((const char *) name
);
853 if (((dict
->limit
> 0) && (l
>= dict
->limit
)) ||
858 * Check for duplicate and insertion location.
860 okey
= xmlDictComputeKey(dict
, name
, l
);
861 key
= okey
% dict
->size
;
862 if (dict
->dict
[key
].valid
== 0) {
865 for (insert
= &(dict
->dict
[key
]); insert
->next
!= NULL
;
866 insert
= insert
->next
) {
868 if ((insert
->okey
== okey
) && (insert
->len
== l
)) {
869 if (!memcmp(insert
->name
, name
, l
))
870 return(insert
->name
);
873 if ((insert
->okey
== okey
) && (insert
->len
== l
) &&
874 (!xmlStrncmp(insert
->name
, name
, l
)))
875 return(insert
->name
);
880 if ((insert
->okey
== okey
) && (insert
->len
== l
)) {
881 if (!memcmp(insert
->name
, name
, l
))
882 return(insert
->name
);
885 if ((insert
->okey
== okey
) && (insert
->len
== l
) &&
886 (!xmlStrncmp(insert
->name
, name
, l
)))
887 return(insert
->name
);
894 /* we cannot always reuse the same okey for the subdict */
895 if (((dict
->size
== MIN_DICT_SIZE
) &&
896 (dict
->subdict
->size
!= MIN_DICT_SIZE
)) ||
897 ((dict
->size
!= MIN_DICT_SIZE
) &&
898 (dict
->subdict
->size
== MIN_DICT_SIZE
)))
899 skey
= xmlDictComputeKey(dict
->subdict
, name
, l
);
903 key
= skey
% dict
->subdict
->size
;
904 if (dict
->subdict
->dict
[key
].valid
!= 0) {
907 for (tmp
= &(dict
->subdict
->dict
[key
]); tmp
->next
!= NULL
;
910 if ((tmp
->okey
== skey
) && (tmp
->len
== l
)) {
911 if (!memcmp(tmp
->name
, name
, l
))
915 if ((tmp
->okey
== skey
) && (tmp
->len
== l
) &&
916 (!xmlStrncmp(tmp
->name
, name
, l
)))
922 if ((tmp
->okey
== skey
) && (tmp
->len
== l
)) {
923 if (!memcmp(tmp
->name
, name
, l
))
927 if ((tmp
->okey
== skey
) && (tmp
->len
== l
) &&
928 (!xmlStrncmp(tmp
->name
, name
, l
)))
932 key
= okey
% dict
->size
;
935 ret
= xmlDictAddString(dict
, name
, l
);
938 if (insert
== NULL
) {
939 entry
= &(dict
->dict
[key
]);
941 entry
= xmlMalloc(sizeof(xmlDictEntry
));
953 insert
->next
= entry
;
957 if ((nbi
> MAX_HASH_LEN
) &&
958 (dict
->size
<= ((MAX_DICT_HASH
/ 2) / MAX_HASH_LEN
))) {
959 if (xmlDictGrow(dict
, MAX_HASH_LEN
* 2 * dict
->size
) != 0)
962 /* Note that entry may have been freed at this point by xmlDictGrow */
969 * @dict: the dictionary
970 * @name: the name of the userdata
971 * @len: the length of the name, if -1 it is recomputed
973 * Check if the @name exists in the dictionary @dict.
975 * Returns the internal copy of the name or NULL if not found.
978 xmlDictExists(xmlDictPtr dict
, const xmlChar
*name
, int len
) {
979 unsigned long key
, okey
;
980 xmlDictEntryPtr insert
;
983 if ((dict
== NULL
) || (name
== NULL
))
987 l
= strlen((const char *) name
);
990 if (((dict
->limit
> 0) && (l
>= dict
->limit
)) ||
995 * Check for duplicate and insertion location.
997 okey
= xmlDictComputeKey(dict
, name
, l
);
998 key
= okey
% dict
->size
;
999 if (dict
->dict
[key
].valid
== 0) {
1002 for (insert
= &(dict
->dict
[key
]); insert
->next
!= NULL
;
1003 insert
= insert
->next
) {
1005 if ((insert
->okey
== okey
) && (insert
->len
== l
)) {
1006 if (!memcmp(insert
->name
, name
, l
))
1007 return(insert
->name
);
1010 if ((insert
->okey
== okey
) && (insert
->len
== l
) &&
1011 (!xmlStrncmp(insert
->name
, name
, l
)))
1012 return(insert
->name
);
1016 if ((insert
->okey
== okey
) && (insert
->len
== l
)) {
1017 if (!memcmp(insert
->name
, name
, l
))
1018 return(insert
->name
);
1021 if ((insert
->okey
== okey
) && (insert
->len
== l
) &&
1022 (!xmlStrncmp(insert
->name
, name
, l
)))
1023 return(insert
->name
);
1027 if (dict
->subdict
) {
1030 /* we cannot always reuse the same okey for the subdict */
1031 if (((dict
->size
== MIN_DICT_SIZE
) &&
1032 (dict
->subdict
->size
!= MIN_DICT_SIZE
)) ||
1033 ((dict
->size
!= MIN_DICT_SIZE
) &&
1034 (dict
->subdict
->size
== MIN_DICT_SIZE
)))
1035 skey
= xmlDictComputeKey(dict
->subdict
, name
, l
);
1039 key
= skey
% dict
->subdict
->size
;
1040 if (dict
->subdict
->dict
[key
].valid
!= 0) {
1041 xmlDictEntryPtr tmp
;
1043 for (tmp
= &(dict
->subdict
->dict
[key
]); tmp
->next
!= NULL
;
1046 if ((tmp
->okey
== skey
) && (tmp
->len
== l
)) {
1047 if (!memcmp(tmp
->name
, name
, l
))
1051 if ((tmp
->okey
== skey
) && (tmp
->len
== l
) &&
1052 (!xmlStrncmp(tmp
->name
, name
, l
)))
1057 if ((tmp
->okey
== skey
) && (tmp
->len
== l
)) {
1058 if (!memcmp(tmp
->name
, name
, l
))
1062 if ((tmp
->okey
== skey
) && (tmp
->len
== l
) &&
1063 (!xmlStrncmp(tmp
->name
, name
, l
)))
1075 * @dict: the dictionary
1076 * @prefix: the prefix
1079 * Add the QName @prefix:@name to the hash @dict if not present.
1081 * Returns the internal copy of the QName or NULL in case of internal error
1084 xmlDictQLookup(xmlDictPtr dict
, const xmlChar
*prefix
, const xmlChar
*name
) {
1085 unsigned long okey
, key
, nbi
= 0;
1086 xmlDictEntryPtr entry
;
1087 xmlDictEntryPtr insert
;
1089 unsigned int len
, plen
, l
;
1091 if ((dict
== NULL
) || (name
== NULL
))
1094 return(xmlDictLookup(dict
, name
, -1));
1096 l
= len
= strlen((const char *) name
);
1097 plen
= strlen((const char *) prefix
);
1101 * Check for duplicate and insertion location.
1103 okey
= xmlDictComputeQKey(dict
, prefix
, plen
, name
, l
);
1104 key
= okey
% dict
->size
;
1105 if (dict
->dict
[key
].valid
== 0) {
1108 for (insert
= &(dict
->dict
[key
]); insert
->next
!= NULL
;
1109 insert
= insert
->next
) {
1110 if ((insert
->okey
== okey
) && (insert
->len
== len
) &&
1111 (xmlStrQEqual(prefix
, name
, insert
->name
)))
1112 return(insert
->name
);
1115 if ((insert
->okey
== okey
) && (insert
->len
== len
) &&
1116 (xmlStrQEqual(prefix
, name
, insert
->name
)))
1117 return(insert
->name
);
1120 if (dict
->subdict
) {
1123 /* we cannot always reuse the same okey for the subdict */
1124 if (((dict
->size
== MIN_DICT_SIZE
) &&
1125 (dict
->subdict
->size
!= MIN_DICT_SIZE
)) ||
1126 ((dict
->size
!= MIN_DICT_SIZE
) &&
1127 (dict
->subdict
->size
== MIN_DICT_SIZE
)))
1128 skey
= xmlDictComputeQKey(dict
->subdict
, prefix
, plen
, name
, l
);
1132 key
= skey
% dict
->subdict
->size
;
1133 if (dict
->subdict
->dict
[key
].valid
!= 0) {
1134 xmlDictEntryPtr tmp
;
1135 for (tmp
= &(dict
->subdict
->dict
[key
]); tmp
->next
!= NULL
;
1137 if ((tmp
->okey
== skey
) && (tmp
->len
== len
) &&
1138 (xmlStrQEqual(prefix
, name
, tmp
->name
)))
1142 if ((tmp
->okey
== skey
) && (tmp
->len
== len
) &&
1143 (xmlStrQEqual(prefix
, name
, tmp
->name
)))
1146 key
= okey
% dict
->size
;
1149 ret
= xmlDictAddQString(dict
, prefix
, plen
, name
, l
);
1152 if (insert
== NULL
) {
1153 entry
= &(dict
->dict
[key
]);
1155 entry
= xmlMalloc(sizeof(xmlDictEntry
));
1166 insert
->next
= entry
;
1170 if ((nbi
> MAX_HASH_LEN
) &&
1171 (dict
->size
<= ((MAX_DICT_HASH
/ 2) / MAX_HASH_LEN
)))
1172 xmlDictGrow(dict
, MAX_HASH_LEN
* 2 * dict
->size
);
1173 /* Note that entry may have been freed at this point by xmlDictGrow */
1180 * @dict: the dictionary
1183 * check if a string is owned by the dictionary
1185 * Returns 1 if true, 0 if false and -1 in case of error
1186 * -1 in case of error
1189 xmlDictOwns(xmlDictPtr dict
, const xmlChar
*str
) {
1190 xmlDictStringsPtr pool
;
1192 if ((dict
== NULL
) || (str
== NULL
))
1194 pool
= dict
->strings
;
1195 while (pool
!= NULL
) {
1196 if ((str
>= &pool
->array
[0]) && (str
<= pool
->free
))
1201 return(xmlDictOwns(dict
->subdict
, str
));
1207 * @dict: the dictionary
1209 * Query the number of elements installed in the hash @dict.
1211 * Returns the number of elements in the dictionary or
1212 * -1 in case of error
1215 xmlDictSize(xmlDictPtr dict
) {
1219 return(dict
->nbElems
+ dict
->subdict
->nbElems
);
1220 return(dict
->nbElems
);
1225 * @dict: the dictionary
1226 * @limit: the limit in bytes
1228 * Set a size limit for the dictionary
1231 * Returns the previous limit of the dictionary or 0
1234 xmlDictSetLimit(xmlDictPtr dict
, size_t limit
) {
1240 dict
->limit
= limit
;
1246 * @dict: the dictionary
1248 * Get how much memory is used by a dictionary for strings
1251 * Returns the amount of strings allocated
1254 xmlDictGetUsage(xmlDictPtr dict
) {
1255 xmlDictStringsPtr pool
;
1260 pool
= dict
->strings
;
1261 while (pool
!= NULL
) {
1262 limit
+= pool
->size
;