VirtualBox

source: vbox/trunk/src/libs/libxml2-2.9.14/dict.c@ 100906

Last change on this file since 100906 was 95312, checked in by vboxsync, 2 years ago

libs/{curl,libxml2}: OSE export fixes, bugref:8515

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette