Sync with tizen 2.4
[platform/upstream/libxml2.git] / dict.c
1 /*
2  * dict.c: dictionary of reusable strings, just used to avoid allocation
3  *         and freeing operations.
4  *
5  * Copyright (C) 2003-2012 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 <limits.h>
23 #ifdef HAVE_STDLIB_H
24 #include <stdlib.h>
25 #endif
26 #ifdef HAVE_TIME_H
27 #include <time.h>
28 #endif
29
30 /*
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
40  */
41 #if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME)
42 #define DICT_RANDOMIZATION
43 #endif
44
45 #include <string.h>
46 #ifdef HAVE_STDINT_H
47 #include <stdint.h>
48 #else
49 #ifdef HAVE_INTTYPES_H
50 #include <inttypes.h>
51 #elif defined(WIN32)
52 typedef unsigned __int32 uint32_t;
53 #endif
54 #endif
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>
60
61 /* #define DEBUG_GROW */
62 /* #define DICT_DEBUG_PATTERNS */
63
64 #define MAX_HASH_LEN 3
65 #define MIN_DICT_SIZE 128
66 #define MAX_DICT_HASH 8 * 2048
67 #define WITH_BIG_KEY
68
69 #ifdef WITH_BIG_KEY
70 #define xmlDictComputeKey(dict, name, len)                              \
71     (((dict)->size == MIN_DICT_SIZE) ?                                  \
72      xmlDictComputeFastKey(name, len, (dict)->seed) :                   \
73      xmlDictComputeBigKey(name, len, (dict)->seed))
74
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)))
81
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 */
88
89 /*
90  * An entry in the dictionnary
91  */
92 typedef struct _xmlDictEntry xmlDictEntry;
93 typedef xmlDictEntry *xmlDictEntryPtr;
94 struct _xmlDictEntry {
95     struct _xmlDictEntry *next;
96     const xmlChar *name;
97     unsigned int len;
98     int valid;
99     unsigned long okey;
100 };
101
102 typedef struct _xmlDictStrings xmlDictStrings;
103 typedef xmlDictStrings *xmlDictStringsPtr;
104 struct _xmlDictStrings {
105     xmlDictStringsPtr next;
106     xmlChar *free;
107     xmlChar *end;
108     size_t size;
109     size_t nbStrings;
110     xmlChar array[1];
111 };
112 /*
113  * The entire dictionnary
114  */
115 struct _xmlDict {
116     int ref_counter;
117
118     struct _xmlDictEntry *dict;
119     size_t size;
120     unsigned int nbElems;
121     xmlDictStringsPtr strings;
122
123     struct _xmlDict *subdict;
124     /* used for randomization */
125     int seed;
126     /* used to impose a limit on size */
127     size_t limit;
128 };
129
130 /*
131  * A mutex for modifying the reference counter for shared
132  * dictionaries.
133  */
134 static xmlRMutexPtr xmlDictMutex = NULL;
135
136 /*
137  * Whether the dictionary mutex was initialized.
138  */
139 static int xmlDictInitialized = 0;
140
141 #ifdef DICT_RANDOMIZATION
142 #ifdef HAVE_RAND_R
143 /*
144  * Internal data for random function, protected by xmlDictMutex
145  */
146 static unsigned int rand_seed = 0;
147 #endif
148 #endif
149
150 /**
151  * xmlInitializeDict:
152  *
153  * Do the dictionary mutex initialization.
154  * this function is deprecated
155  *
156  * Returns 0 if initialization was already done, and 1 if that
157  * call led to the initialization
158  */
159 int xmlInitializeDict(void) {
160     return(0);
161 }
162
163 /**
164  * __xmlInitializeDict:
165  *
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
171  *
172  * Returns 0 if initialization was already done, and 1 if that
173  * call led to the initialization
174  */
175 int __xmlInitializeDict(void) {
176     if (xmlDictInitialized)
177         return(1);
178
179     if ((xmlDictMutex = xmlNewRMutex()) == NULL)
180         return(0);
181     xmlRMutexLock(xmlDictMutex);
182
183 #ifdef DICT_RANDOMIZATION
184 #ifdef HAVE_RAND_R
185     rand_seed = time(NULL);
186     rand_r(& rand_seed);
187 #else
188     srand(time(NULL));
189 #endif
190 #endif
191     xmlDictInitialized = 1;
192     xmlRMutexUnlock(xmlDictMutex);
193     return(1);
194 }
195
196 #ifdef DICT_RANDOMIZATION
197 int __xmlRandom(void) {
198     int ret;
199
200     if (xmlDictInitialized == 0)
201         __xmlInitializeDict();
202
203     xmlRMutexLock(xmlDictMutex);
204 #ifdef HAVE_RAND_R
205     ret = rand_r(& rand_seed);
206 #else
207     ret = rand();
208 #endif
209     xmlRMutexUnlock(xmlDictMutex);
210     return(ret);
211 }
212 #endif
213
214 /**
215  * xmlDictCleanup:
216  *
217  * Free the dictionary mutex. Do not call unless sure the library
218  * is not in use anymore !
219  */
220 void
221 xmlDictCleanup(void) {
222     if (!xmlDictInitialized)
223         return;
224
225     xmlFreeRMutex(xmlDictMutex);
226
227     xmlDictInitialized = 0;
228 }
229
230 /*
231  * xmlDictAddString:
232  * @dict: the dictionnary
233  * @name: the name of the userdata
234  * @len: the length of the name
235  *
236  * Add the string to the array[s]
237  *
238  * Returns the pointer of the local string, or NULL in case of error.
239  */
240 static const xmlChar *
241 xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
242     xmlDictStringsPtr pool;
243     const xmlChar *ret;
244     size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
245     size_t limit = 0;
246
247 #ifdef DICT_DEBUG_PATTERNS
248     fprintf(stderr, "-");
249 #endif
250     pool = dict->strings;
251     while (pool != NULL) {
252         if (pool->end - pool->free > namelen)
253             goto found_pool;
254         if (pool->size > size) size = pool->size;
255         limit += pool->size;
256         pool = pool->next;
257     }
258     /*
259      * Not found, need to allocate
260      */
261     if (pool == NULL) {
262         if ((dict->limit > 0) && (limit > dict->limit)) {
263             return(NULL);
264         }
265
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);
271         if (pool == NULL)
272             return(NULL);
273         pool->size = size;
274         pool->nbStrings = 0;
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, "+");
281 #endif
282     }
283 found_pool:
284     ret = pool->free;
285     memcpy(pool->free, name, namelen);
286     pool->free += namelen;
287     *(pool->free++) = 0;
288     pool->nbStrings++;
289     return(ret);
290 }
291
292 /*
293  * xmlDictAddQString:
294  * @dict: the dictionnary
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
299  *
300  * Add the QName to the array[s]
301  *
302  * Returns the pointer of the local string, or NULL in case of error.
303  */
304 static const xmlChar *
305 xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
306                  const xmlChar *name, unsigned int namelen)
307 {
308     xmlDictStringsPtr pool;
309     const xmlChar *ret;
310     size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
311     size_t limit = 0;
312
313     if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
314
315 #ifdef DICT_DEBUG_PATTERNS
316     fprintf(stderr, "=");
317 #endif
318     pool = dict->strings;
319     while (pool != NULL) {
320         if (pool->end - pool->free > namelen + plen + 1)
321             goto found_pool;
322         if (pool->size > size) size = pool->size;
323         limit += pool->size;
324         pool = pool->next;
325     }
326     /*
327      * Not found, need to allocate
328      */
329     if (pool == NULL) {
330         if ((dict->limit > 0) && (limit > dict->limit)) {
331             return(NULL);
332         }
333
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);
339         if (pool == NULL)
340             return(NULL);
341         pool->size = size;
342         pool->nbStrings = 0;
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, "+");
349 #endif
350     }
351 found_pool:
352     ret = pool->free;
353     memcpy(pool->free, prefix, plen);
354     pool->free += plen;
355     *(pool->free++) = ':';
356     memcpy(pool->free, name, namelen);
357     pool->free += namelen;
358     *(pool->free++) = 0;
359     pool->nbStrings++;
360     return(ret);
361 }
362
363 #ifdef WITH_BIG_KEY
364 /*
365  * xmlDictComputeBigKey:
366  *
367  * Calculate a hash key using a good hash function that works well for
368  * larger hash table sizes.
369  *
370  * Hash function by "One-at-a-Time Hash" see
371  * http://burtleburtle.net/bob/hash/doobs.html
372  */
373
374 static uint32_t
375 xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
376     uint32_t hash;
377     int i;
378
379     if (namelen <= 0 || data == NULL) return(0);
380
381     hash = seed;
382
383     for (i = 0;i < namelen; i++) {
384         hash += data[i];
385         hash += (hash << 10);
386         hash ^= (hash >> 6);
387     }
388     hash += (hash << 3);
389     hash ^= (hash >> 11);
390     hash += (hash << 15);
391
392     return hash;
393 }
394
395 /*
396  * xmlDictComputeBigQKey:
397  *
398  * Calculate a hash key for two strings using a good hash function
399  * that works well for larger hash table sizes.
400  *
401  * Hash function by "One-at-a-Time Hash" see
402  * http://burtleburtle.net/bob/hash/doobs.html
403  *
404  * Neither of the two strings must be NULL.
405  */
406 static unsigned long
407 xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
408                       const xmlChar *name, int len, int seed)
409 {
410     uint32_t hash;
411     int i;
412
413     hash = seed;
414
415     for (i = 0;i < plen; i++) {
416         hash += prefix[i];
417         hash += (hash << 10);
418         hash ^= (hash >> 6);
419     }
420     hash += ':';
421     hash += (hash << 10);
422     hash ^= (hash >> 6);
423
424     for (i = 0;i < len; i++) {
425         hash += name[i];
426         hash += (hash << 10);
427         hash ^= (hash >> 6);
428     }
429     hash += (hash << 3);
430     hash ^= (hash >> 11);
431     hash += (hash << 15);
432
433     return hash;
434 }
435 #endif /* WITH_BIG_KEY */
436
437 /*
438  * xmlDictComputeFastKey:
439  *
440  * Calculate a hash key using a fast hash function that works well
441  * for low hash table fill.
442  */
443 static unsigned long
444 xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
445     unsigned long value = seed;
446
447     if (name == NULL) return(0);
448     value = *name;
449     value <<= 5;
450     if (namelen > 10) {
451         value += name[namelen - 1];
452         namelen = 10;
453     }
454     switch (namelen) {
455         case 10: value += name[9];
456         case 9: value += name[8];
457         case 8: value += name[7];
458         case 7: value += name[6];
459         case 6: value += name[5];
460         case 5: value += name[4];
461         case 4: value += name[3];
462         case 3: value += name[2];
463         case 2: value += name[1];
464         default: break;
465     }
466     return(value);
467 }
468
469 /*
470  * xmlDictComputeFastQKey:
471  *
472  * Calculate a hash key for two strings using a fast hash function
473  * that works well for low hash table fill.
474  *
475  * Neither of the two strings must be NULL.
476  */
477 static unsigned long
478 xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
479                        const xmlChar *name, int len, int seed)
480 {
481     unsigned long value = (unsigned long) seed;
482
483     if (plen == 0)
484         value += 30 * (unsigned long) ':';
485     else
486         value += 30 * (*prefix);
487
488     if (len > 10) {
489         value += name[len - (plen + 1 + 1)];
490         len = 10;
491         if (plen > 10)
492             plen = 10;
493     }
494     switch (plen) {
495         case 10: value += prefix[9];
496         case 9: value += prefix[8];
497         case 8: value += prefix[7];
498         case 7: value += prefix[6];
499         case 6: value += prefix[5];
500         case 5: value += prefix[4];
501         case 4: value += prefix[3];
502         case 3: value += prefix[2];
503         case 2: value += prefix[1];
504         case 1: value += prefix[0];
505         default: break;
506     }
507     len -= plen;
508     if (len > 0) {
509         value += (unsigned long) ':';
510         len--;
511     }
512     switch (len) {
513         case 10: value += name[9];
514         case 9: value += name[8];
515         case 8: value += name[7];
516         case 7: value += name[6];
517         case 6: value += name[5];
518         case 5: value += name[4];
519         case 4: value += name[3];
520         case 3: value += name[2];
521         case 2: value += name[1];
522         case 1: value += name[0];
523         default: break;
524     }
525     return(value);
526 }
527
528 /**
529  * xmlDictCreate:
530  *
531  * Create a new dictionary
532  *
533  * Returns the newly created dictionnary, or NULL if an error occured.
534  */
535 xmlDictPtr
536 xmlDictCreate(void) {
537     xmlDictPtr dict;
538
539     if (!xmlDictInitialized)
540         if (!__xmlInitializeDict())
541             return(NULL);
542
543 #ifdef DICT_DEBUG_PATTERNS
544     fprintf(stderr, "C");
545 #endif
546
547     dict = xmlMalloc(sizeof(xmlDict));
548     if (dict) {
549         dict->ref_counter = 1;
550         dict->limit = 0;
551
552         dict->size = MIN_DICT_SIZE;
553         dict->nbElems = 0;
554         dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
555         dict->strings = NULL;
556         dict->subdict = NULL;
557         if (dict->dict) {
558             memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
559 #ifdef DICT_RANDOMIZATION
560             dict->seed = __xmlRandom();
561 #else
562             dict->seed = 0;
563 #endif
564             return(dict);
565         }
566         xmlFree(dict);
567     }
568     return(NULL);
569 }
570
571 /**
572  * xmlDictCreateSub:
573  * @sub: an existing dictionnary
574  *
575  * Create a new dictionary, inheriting strings from the read-only
576  * dictionnary @sub. On lookup, strings are first searched in the
577  * new dictionnary, then in @sub, and if not found are created in the
578  * new dictionnary.
579  *
580  * Returns the newly created dictionnary, or NULL if an error occured.
581  */
582 xmlDictPtr
583 xmlDictCreateSub(xmlDictPtr sub) {
584     xmlDictPtr dict = xmlDictCreate();
585
586     if ((dict != NULL) && (sub != NULL)) {
587 #ifdef DICT_DEBUG_PATTERNS
588         fprintf(stderr, "R");
589 #endif
590         dict->seed = sub->seed;
591         dict->subdict = sub;
592         xmlDictReference(dict->subdict);
593     }
594     return(dict);
595 }
596
597 /**
598  * xmlDictReference:
599  * @dict: the dictionnary
600  *
601  * Increment the reference counter of a dictionary
602  *
603  * Returns 0 in case of success and -1 in case of error
604  */
605 int
606 xmlDictReference(xmlDictPtr dict) {
607     if (!xmlDictInitialized)
608         if (!__xmlInitializeDict())
609             return(-1);
610
611     if (dict == NULL) return -1;
612     xmlRMutexLock(xmlDictMutex);
613     dict->ref_counter++;
614     xmlRMutexUnlock(xmlDictMutex);
615     return(0);
616 }
617
618 /**
619  * xmlDictGrow:
620  * @dict: the dictionnary
621  * @size: the new size of the dictionnary
622  *
623  * resize the dictionnary
624  *
625  * Returns 0 in case of success, -1 in case of failure
626  */
627 static int
628 xmlDictGrow(xmlDictPtr dict, size_t size) {
629     unsigned long key, okey;
630     size_t oldsize, i;
631     xmlDictEntryPtr iter, next;
632     struct _xmlDictEntry *olddict;
633 #ifdef DEBUG_GROW
634     unsigned long nbElem = 0;
635 #endif
636     int ret = 0;
637     int keep_keys = 1;
638
639     if (dict == NULL)
640         return(-1);
641     if (size < 8)
642         return(-1);
643     if (size > 8 * 2048)
644         return(-1);
645
646 #ifdef DICT_DEBUG_PATTERNS
647     fprintf(stderr, "*");
648 #endif
649
650     oldsize = dict->size;
651     olddict = dict->dict;
652     if (olddict == NULL)
653         return(-1);
654     if (oldsize == MIN_DICT_SIZE)
655         keep_keys = 0;
656
657     dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
658     if (dict->dict == NULL) {
659         dict->dict = olddict;
660         return(-1);
661     }
662     memset(dict->dict, 0, size * sizeof(xmlDictEntry));
663     dict->size = size;
664
665     /*  If the two loops are merged, there would be situations where
666         a new entry needs to allocated and data copied into it from
667         the main dict. It is nicer to run through the array twice, first
668         copying all the elements in the main array (less probability of
669         allocate) and then the rest, so we only free in the second loop.
670     */
671     for (i = 0; i < oldsize; i++) {
672         if (olddict[i].valid == 0)
673             continue;
674
675         if (keep_keys)
676             okey = olddict[i].okey;
677         else
678             okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
679         key = okey % dict->size;
680
681         if (dict->dict[key].valid == 0) {
682             memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
683             dict->dict[key].next = NULL;
684             dict->dict[key].okey = okey;
685         } else {
686             xmlDictEntryPtr entry;
687
688             entry = xmlMalloc(sizeof(xmlDictEntry));
689             if (entry != NULL) {
690                 entry->name = olddict[i].name;
691                 entry->len = olddict[i].len;
692                 entry->okey = okey;
693                 entry->next = dict->dict[key].next;
694                 entry->valid = 1;
695                 dict->dict[key].next = entry;
696             } else {
697                 /*
698                  * we don't have much ways to alert from herei
699                  * result is loosing an entry and unicity garantee
700                  */
701                 ret = -1;
702             }
703         }
704 #ifdef DEBUG_GROW
705         nbElem++;
706 #endif
707     }
708
709     for (i = 0; i < oldsize; i++) {
710         iter = olddict[i].next;
711         while (iter) {
712             next = iter->next;
713
714             /*
715              * put back the entry in the new dict
716              */
717
718             if (keep_keys)
719                 okey = iter->okey;
720             else
721                 okey = xmlDictComputeKey(dict, iter->name, iter->len);
722             key = okey % dict->size;
723             if (dict->dict[key].valid == 0) {
724                 memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
725                 dict->dict[key].next = NULL;
726                 dict->dict[key].valid = 1;
727                 dict->dict[key].okey = okey;
728                 xmlFree(iter);
729             } else {
730                 iter->next = dict->dict[key].next;
731                 iter->okey = okey;
732                 dict->dict[key].next = iter;
733             }
734
735 #ifdef DEBUG_GROW
736             nbElem++;
737 #endif
738
739             iter = next;
740         }
741     }
742
743     xmlFree(olddict);
744
745 #ifdef DEBUG_GROW
746     xmlGenericError(xmlGenericErrorContext,
747             "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
748 #endif
749
750     return(ret);
751 }
752
753 /**
754  * xmlDictFree:
755  * @dict: the dictionnary
756  *
757  * Free the hash @dict and its contents. The userdata is
758  * deallocated with @f if provided.
759  */
760 void
761 xmlDictFree(xmlDictPtr dict) {
762     size_t i;
763     xmlDictEntryPtr iter;
764     xmlDictEntryPtr next;
765     int inside_dict = 0;
766     xmlDictStringsPtr pool, nextp;
767
768     if (dict == NULL)
769         return;
770
771     if (!xmlDictInitialized)
772         if (!__xmlInitializeDict())
773             return;
774
775     /* decrement the counter, it may be shared by a parser and docs */
776     xmlRMutexLock(xmlDictMutex);
777     dict->ref_counter--;
778     if (dict->ref_counter > 0) {
779         xmlRMutexUnlock(xmlDictMutex);
780         return;
781     }
782
783     xmlRMutexUnlock(xmlDictMutex);
784
785     if (dict->subdict != NULL) {
786         xmlDictFree(dict->subdict);
787     }
788
789     if (dict->dict) {
790         for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
791             iter = &(dict->dict[i]);
792             if (iter->valid == 0)
793                 continue;
794             inside_dict = 1;
795             while (iter) {
796                 next = iter->next;
797                 if (!inside_dict)
798                     xmlFree(iter);
799                 dict->nbElems--;
800                 inside_dict = 0;
801                 iter = next;
802             }
803         }
804         xmlFree(dict->dict);
805     }
806     pool = dict->strings;
807     while (pool != NULL) {
808         nextp = pool->next;
809         xmlFree(pool);
810         pool = nextp;
811     }
812     xmlFree(dict);
813 }
814
815 /**
816  * xmlDictLookup:
817  * @dict: the dictionnary
818  * @name: the name of the userdata
819  * @len: the length of the name, if -1 it is recomputed
820  *
821  * Add the @name to the dictionnary @dict if not present.
822  *
823  * Returns the internal copy of the name or NULL in case of internal error
824  */
825 const xmlChar *
826 xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
827     unsigned long key, okey, nbi = 0;
828     xmlDictEntryPtr entry;
829     xmlDictEntryPtr insert;
830     const xmlChar *ret;
831     unsigned int l;
832
833     if ((dict == NULL) || (name == NULL))
834         return(NULL);
835
836     if (len < 0)
837         l = strlen((const char *) name);
838     else
839         l = len;
840
841     if (((dict->limit > 0) && (l >= dict->limit)) ||
842         (l > INT_MAX / 2))
843         return(NULL);
844
845     /*
846      * Check for duplicate and insertion location.
847      */
848     okey = xmlDictComputeKey(dict, name, l);
849     key = okey % dict->size;
850     if (dict->dict[key].valid == 0) {
851         insert = NULL;
852     } else {
853         for (insert = &(dict->dict[key]); insert->next != NULL;
854              insert = insert->next) {
855 #ifdef __GNUC__
856             if ((insert->okey == okey) && (insert->len == l)) {
857                 if (!memcmp(insert->name, name, l))
858                     return(insert->name);
859             }
860 #else
861             if ((insert->okey == okey) && (insert->len == l) &&
862                 (!xmlStrncmp(insert->name, name, l)))
863                 return(insert->name);
864 #endif
865             nbi++;
866         }
867 #ifdef __GNUC__
868         if ((insert->okey == okey) && (insert->len == l)) {
869             if (!memcmp(insert->name, name, l))
870                 return(insert->name);
871         }
872 #else
873         if ((insert->okey == okey) && (insert->len == l) &&
874             (!xmlStrncmp(insert->name, name, l)))
875             return(insert->name);
876 #endif
877     }
878
879     if (dict->subdict) {
880         unsigned long skey;
881
882         /* we cannot always reuse the same okey for the subdict */
883         if (((dict->size == MIN_DICT_SIZE) &&
884              (dict->subdict->size != MIN_DICT_SIZE)) ||
885             ((dict->size != MIN_DICT_SIZE) &&
886              (dict->subdict->size == MIN_DICT_SIZE)))
887             skey = xmlDictComputeKey(dict->subdict, name, l);
888         else
889             skey = okey;
890
891         key = skey % dict->subdict->size;
892         if (dict->subdict->dict[key].valid != 0) {
893             xmlDictEntryPtr tmp;
894
895             for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
896                  tmp = tmp->next) {
897 #ifdef __GNUC__
898                 if ((tmp->okey == skey) && (tmp->len == l)) {
899                     if (!memcmp(tmp->name, name, l))
900                         return(tmp->name);
901                 }
902 #else
903                 if ((tmp->okey == skey) && (tmp->len == l) &&
904                     (!xmlStrncmp(tmp->name, name, l)))
905                     return(tmp->name);
906 #endif
907                 nbi++;
908             }
909 #ifdef __GNUC__
910             if ((tmp->okey == skey) && (tmp->len == l)) {
911                 if (!memcmp(tmp->name, name, l))
912                     return(tmp->name);
913             }
914 #else
915             if ((tmp->okey == skey) && (tmp->len == l) &&
916                 (!xmlStrncmp(tmp->name, name, l)))
917                 return(tmp->name);
918 #endif
919         }
920         key = okey % dict->size;
921     }
922
923     ret = xmlDictAddString(dict, name, l);
924     if (ret == NULL)
925         return(NULL);
926     if (insert == NULL) {
927         entry = &(dict->dict[key]);
928     } else {
929         entry = xmlMalloc(sizeof(xmlDictEntry));
930         if (entry == NULL)
931              return(NULL);
932     }
933     entry->name = ret;
934     entry->len = l;
935     entry->next = NULL;
936     entry->valid = 1;
937     entry->okey = okey;
938
939
940     if (insert != NULL)
941         insert->next = entry;
942
943     dict->nbElems++;
944
945     if ((nbi > MAX_HASH_LEN) &&
946         (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
947         if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
948             return(NULL);
949     }
950     /* Note that entry may have been freed at this point by xmlDictGrow */
951
952     return(ret);
953 }
954
955 /**
956  * xmlDictExists:
957  * @dict: the dictionnary
958  * @name: the name of the userdata
959  * @len: the length of the name, if -1 it is recomputed
960  *
961  * Check if the @name exists in the dictionnary @dict.
962  *
963  * Returns the internal copy of the name or NULL if not found.
964  */
965 const xmlChar *
966 xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
967     unsigned long key, okey, nbi = 0;
968     xmlDictEntryPtr insert;
969     unsigned int l;
970
971     if ((dict == NULL) || (name == NULL))
972         return(NULL);
973
974     if (len < 0)
975         l = strlen((const char *) name);
976     else
977         l = len;
978     if (((dict->limit > 0) && (l >= dict->limit)) ||
979         (l > INT_MAX / 2))
980         return(NULL);
981
982     /*
983      * Check for duplicate and insertion location.
984      */
985     okey = xmlDictComputeKey(dict, name, l);
986     key = okey % dict->size;
987     if (dict->dict[key].valid == 0) {
988         insert = NULL;
989     } else {
990         for (insert = &(dict->dict[key]); insert->next != NULL;
991              insert = insert->next) {
992 #ifdef __GNUC__
993             if ((insert->okey == okey) && (insert->len == l)) {
994                 if (!memcmp(insert->name, name, l))
995                     return(insert->name);
996             }
997 #else
998             if ((insert->okey == okey) && (insert->len == l) &&
999                 (!xmlStrncmp(insert->name, name, l)))
1000                 return(insert->name);
1001 #endif
1002             nbi++;
1003         }
1004 #ifdef __GNUC__
1005         if ((insert->okey == okey) && (insert->len == l)) {
1006             if (!memcmp(insert->name, name, l))
1007                 return(insert->name);
1008         }
1009 #else
1010         if ((insert->okey == okey) && (insert->len == l) &&
1011             (!xmlStrncmp(insert->name, name, l)))
1012             return(insert->name);
1013 #endif
1014     }
1015
1016     if (dict->subdict) {
1017         unsigned long skey;
1018
1019         /* we cannot always reuse the same okey for the subdict */
1020         if (((dict->size == MIN_DICT_SIZE) &&
1021              (dict->subdict->size != MIN_DICT_SIZE)) ||
1022             ((dict->size != MIN_DICT_SIZE) &&
1023              (dict->subdict->size == MIN_DICT_SIZE)))
1024             skey = xmlDictComputeKey(dict->subdict, name, l);
1025         else
1026             skey = okey;
1027
1028         key = skey % dict->subdict->size;
1029         if (dict->subdict->dict[key].valid != 0) {
1030             xmlDictEntryPtr tmp;
1031
1032             for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1033                  tmp = tmp->next) {
1034 #ifdef __GNUC__
1035                 if ((tmp->okey == skey) && (tmp->len == l)) {
1036                     if (!memcmp(tmp->name, name, l))
1037                         return(tmp->name);
1038                 }
1039 #else
1040                 if ((tmp->okey == skey) && (tmp->len == l) &&
1041                     (!xmlStrncmp(tmp->name, name, l)))
1042                     return(tmp->name);
1043 #endif
1044                 nbi++;
1045             }
1046 #ifdef __GNUC__
1047             if ((tmp->okey == skey) && (tmp->len == l)) {
1048                 if (!memcmp(tmp->name, name, l))
1049                     return(tmp->name);
1050             }
1051 #else
1052             if ((tmp->okey == skey) && (tmp->len == l) &&
1053                 (!xmlStrncmp(tmp->name, name, l)))
1054                 return(tmp->name);
1055 #endif
1056         }
1057     }
1058
1059     /* not found */
1060     return(NULL);
1061 }
1062
1063 /**
1064  * xmlDictQLookup:
1065  * @dict: the dictionnary
1066  * @prefix: the prefix
1067  * @name: the name
1068  *
1069  * Add the QName @prefix:@name to the hash @dict if not present.
1070  *
1071  * Returns the internal copy of the QName or NULL in case of internal error
1072  */
1073 const xmlChar *
1074 xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
1075     unsigned long okey, key, nbi = 0;
1076     xmlDictEntryPtr entry;
1077     xmlDictEntryPtr insert;
1078     const xmlChar *ret;
1079     unsigned int len, plen, l;
1080
1081     if ((dict == NULL) || (name == NULL))
1082         return(NULL);
1083     if (prefix == NULL)
1084         return(xmlDictLookup(dict, name, -1));
1085
1086     l = len = strlen((const char *) name);
1087     plen = strlen((const char *) prefix);
1088     len += 1 + plen;
1089
1090     /*
1091      * Check for duplicate and insertion location.
1092      */
1093     okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
1094     key = okey % dict->size;
1095     if (dict->dict[key].valid == 0) {
1096         insert = NULL;
1097     } else {
1098         for (insert = &(dict->dict[key]); insert->next != NULL;
1099              insert = insert->next) {
1100             if ((insert->okey == okey) && (insert->len == len) &&
1101                 (xmlStrQEqual(prefix, name, insert->name)))
1102                 return(insert->name);
1103             nbi++;
1104         }
1105         if ((insert->okey == okey) && (insert->len == len) &&
1106             (xmlStrQEqual(prefix, name, insert->name)))
1107             return(insert->name);
1108     }
1109
1110     if (dict->subdict) {
1111         unsigned long skey;
1112
1113         /* we cannot always reuse the same okey for the subdict */
1114         if (((dict->size == MIN_DICT_SIZE) &&
1115              (dict->subdict->size != MIN_DICT_SIZE)) ||
1116             ((dict->size != MIN_DICT_SIZE) &&
1117              (dict->subdict->size == MIN_DICT_SIZE)))
1118             skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
1119         else
1120             skey = okey;
1121
1122         key = skey % dict->subdict->size;
1123         if (dict->subdict->dict[key].valid != 0) {
1124             xmlDictEntryPtr tmp;
1125             for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
1126                  tmp = tmp->next) {
1127                 if ((tmp->okey == skey) && (tmp->len == len) &&
1128                     (xmlStrQEqual(prefix, name, tmp->name)))
1129                     return(tmp->name);
1130                 nbi++;
1131             }
1132             if ((tmp->okey == skey) && (tmp->len == len) &&
1133                 (xmlStrQEqual(prefix, name, tmp->name)))
1134                 return(tmp->name);
1135         }
1136         key = okey % dict->size;
1137     }
1138
1139     ret = xmlDictAddQString(dict, prefix, plen, name, l);
1140     if (ret == NULL)
1141         return(NULL);
1142     if (insert == NULL) {
1143         entry = &(dict->dict[key]);
1144     } else {
1145         entry = xmlMalloc(sizeof(xmlDictEntry));
1146         if (entry == NULL)
1147              return(NULL);
1148     }
1149     entry->name = ret;
1150     entry->len = len;
1151     entry->next = NULL;
1152     entry->valid = 1;
1153     entry->okey = okey;
1154
1155     if (insert != NULL)
1156         insert->next = entry;
1157
1158     dict->nbElems++;
1159
1160     if ((nbi > MAX_HASH_LEN) &&
1161         (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
1162         xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
1163     /* Note that entry may have been freed at this point by xmlDictGrow */
1164
1165     return(ret);
1166 }
1167
1168 /**
1169  * xmlDictOwns:
1170  * @dict: the dictionnary
1171  * @str: the string
1172  *
1173  * check if a string is owned by the disctionary
1174  *
1175  * Returns 1 if true, 0 if false and -1 in case of error
1176  * -1 in case of error
1177  */
1178 int
1179 xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
1180     xmlDictStringsPtr pool;
1181
1182     if ((dict == NULL) || (str == NULL))
1183         return(-1);
1184     pool = dict->strings;
1185     while (pool != NULL) {
1186         if ((str >= &pool->array[0]) && (str <= pool->free))
1187             return(1);
1188         pool = pool->next;
1189     }
1190     if (dict->subdict)
1191         return(xmlDictOwns(dict->subdict, str));
1192     return(0);
1193 }
1194
1195 /**
1196  * xmlDictSize:
1197  * @dict: the dictionnary
1198  *
1199  * Query the number of elements installed in the hash @dict.
1200  *
1201  * Returns the number of elements in the dictionnary or
1202  * -1 in case of error
1203  */
1204 int
1205 xmlDictSize(xmlDictPtr dict) {
1206     if (dict == NULL)
1207         return(-1);
1208     if (dict->subdict)
1209         return(dict->nbElems + dict->subdict->nbElems);
1210     return(dict->nbElems);
1211 }
1212
1213 /**
1214  * xmlDictSetLimit:
1215  * @dict: the dictionnary
1216  * @limit: the limit in bytes
1217  *
1218  * Set a size limit for the dictionary
1219  * Added in 2.9.0
1220  *
1221  * Returns the previous limit of the dictionary or 0
1222  */
1223 size_t
1224 xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
1225     size_t ret;
1226
1227     if (dict == NULL)
1228         return(0);
1229     ret = dict->limit;
1230     dict->limit = limit;
1231     return(ret);
1232 }
1233
1234 /**
1235  * xmlDictGetUsage:
1236  * @dict: the dictionnary
1237  *
1238  * Get how much memory is used by a dictionary for strings
1239  * Added in 2.9.0
1240  *
1241  * Returns the amount of strings allocated
1242  */
1243 size_t
1244 xmlDictGetUsage(xmlDictPtr dict) {
1245     xmlDictStringsPtr pool;
1246     size_t limit = 0;
1247
1248     if (dict == NULL)
1249         return(0);
1250     pool = dict->strings;
1251     while (pool != NULL) {
1252         limit += pool->size;
1253         pool = pool->next;
1254     }
1255     return(limit);
1256 }
1257
1258 #define bottom_dict
1259 #include "elfgcchack.h"