VirtualBox

source: vbox/trunk/src/libs/libxml2-2.13.2/dict.c@ 105770

Last change on this file since 105770 was 105448, checked in by vboxsync, 4 months ago

libxml2-2.13.2: builds and runs on Linux. bugref:10730

  • Property svn:eol-style set to native
File size: 24.4 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: daniel@veillard.com
17 */
18
19#define IN_LIBXML
20#include "libxml.h"
21
22#include <errno.h>
23#include <limits.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include "private/dict.h"
28#include "private/globals.h"
29#include "private/threads.h"
30
31#include <libxml/parser.h>
32#include <libxml/dict.h>
33#include <libxml/xmlmemory.h>
34#include <libxml/xmlstring.h>
35
36#ifdef VBOX
37# include <iprt/rand.h>
38#endif
39
40#ifndef SIZE_MAX
41 #define SIZE_MAX ((size_t) -1)
42#endif
43
44#define MAX_FILL_NUM 7
45#define MAX_FILL_DENOM 8
46#define MIN_HASH_SIZE 8
47#define MAX_HASH_SIZE (1u << 31)
48
49typedef struct _xmlDictStrings xmlDictStrings;
50typedef xmlDictStrings *xmlDictStringsPtr;
51struct _xmlDictStrings {
52 xmlDictStringsPtr next;
53 xmlChar *free;
54 xmlChar *end;
55 size_t size;
56 size_t nbStrings;
57 xmlChar array[1];
58};
59
60typedef xmlHashedString xmlDictEntry;
61
62/*
63 * The entire dictionary
64 */
65struct _xmlDict {
66 int ref_counter;
67
68 xmlDictEntry *table;
69 size_t size;
70 unsigned int nbElems;
71 xmlDictStringsPtr strings;
72
73 struct _xmlDict *subdict;
74 /* used for randomization */
75 unsigned seed;
76 /* used to impose a limit on size */
77 size_t limit;
78};
79
80/*
81 * A mutex for modifying the reference counter for shared
82 * dictionaries.
83 */
84static xmlMutex xmlDictMutex;
85
86/**
87 * xmlInitializeDict:
88 *
89 * DEPRECATED: Alias for xmlInitParser.
90 *
91 * Returns 0.
92 */
93int
94xmlInitializeDict(void) {
95 xmlInitParser();
96 return(0);
97}
98
99/**
100 * xmlInitDictInternal:
101 *
102 * Initialize mutex.
103 */
104void
105xmlInitDictInternal(void) {
106 xmlInitMutex(&xmlDictMutex);
107}
108
109/**
110 * xmlDictCleanup:
111 *
112 * DEPRECATED: This function is a no-op. Call xmlCleanupParser
113 * to free global state but see the warnings there. xmlCleanupParser
114 * should be only called once at program exit. In most cases, you don't
115 * have call cleanup functions at all.
116 */
117void
118xmlDictCleanup(void) {
119}
120
121/**
122 * xmlCleanupDictInternal:
123 *
124 * Free the dictionary mutex.
125 */
126void
127xmlCleanupDictInternal(void) {
128 xmlCleanupMutex(&xmlDictMutex);
129}
130
131/*
132 * xmlDictAddString:
133 * @dict: the dictionary
134 * @name: the name of the userdata
135 * @len: the length of the name
136 *
137 * Add the string to the array[s]
138 *
139 * Returns the pointer of the local string, or NULL in case of error.
140 */
141static const xmlChar *
142xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
143 xmlDictStringsPtr pool;
144 const xmlChar *ret;
145 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
146 size_t limit = 0;
147
148 pool = dict->strings;
149 while (pool != NULL) {
150 if ((size_t)(pool->end - pool->free) > namelen)
151 goto found_pool;
152 if (pool->size > size) size = pool->size;
153 limit += pool->size;
154 pool = pool->next;
155 }
156 /*
157 * Not found, need to allocate
158 */
159 if (pool == NULL) {
160 if ((dict->limit > 0) && (limit > dict->limit)) {
161 return(NULL);
162 }
163
164 if (size == 0) {
165 size = 1000;
166 } else {
167 if (size < (SIZE_MAX - sizeof(xmlDictStrings)) / 4)
168 size *= 4; /* exponential growth */
169 else
170 size = SIZE_MAX - sizeof(xmlDictStrings);
171 }
172 if (size / 4 < namelen) {
173 if ((size_t) namelen + 0 < (SIZE_MAX - sizeof(xmlDictStrings)) / 4)
174 size = 4 * (size_t) namelen; /* just in case ! */
175 else
176 return(NULL);
177 }
178 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
179 if (pool == NULL)
180 return(NULL);
181 pool->size = size;
182 pool->nbStrings = 0;
183 pool->free = &pool->array[0];
184 pool->end = &pool->array[size];
185 pool->next = dict->strings;
186 dict->strings = pool;
187 }
188found_pool:
189 ret = pool->free;
190 memcpy(pool->free, name, namelen);
191 pool->free += namelen;
192 *(pool->free++) = 0;
193 pool->nbStrings++;
194 return(ret);
195}
196
197/*
198 * xmlDictAddQString:
199 * @dict: the dictionary
200 * @prefix: the prefix of the userdata
201 * @plen: the prefix length
202 * @name: the name of the userdata
203 * @len: the length of the name
204 *
205 * Add the QName to the array[s]
206 *
207 * Returns the pointer of the local string, or NULL in case of error.
208 */
209static const xmlChar *
210xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
211 const xmlChar *name, unsigned int namelen)
212{
213 xmlDictStringsPtr pool;
214 const xmlChar *ret;
215 size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
216 size_t limit = 0;
217
218 pool = dict->strings;
219 while (pool != NULL) {
220 if ((size_t)(pool->end - pool->free) > namelen + plen + 1)
221 goto found_pool;
222 if (pool->size > size) size = pool->size;
223 limit += pool->size;
224 pool = pool->next;
225 }
226 /*
227 * Not found, need to allocate
228 */
229 if (pool == NULL) {
230 if ((dict->limit > 0) && (limit > dict->limit)) {
231 return(NULL);
232 }
233
234 if (size == 0) size = 1000;
235 else size *= 4; /* exponential growth */
236 if (size < 4 * (namelen + plen + 1))
237 size = 4 * (namelen + plen + 1); /* just in case ! */
238 pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
239 if (pool == NULL)
240 return(NULL);
241 pool->size = size;
242 pool->nbStrings = 0;
243 pool->free = &pool->array[0];
244 pool->end = &pool->array[size];
245 pool->next = dict->strings;
246 dict->strings = pool;
247 }
248found_pool:
249 ret = pool->free;
250 memcpy(pool->free, prefix, plen);
251 pool->free += plen;
252 *(pool->free++) = ':';
253 memcpy(pool->free, name, namelen);
254 pool->free += namelen;
255 *(pool->free++) = 0;
256 pool->nbStrings++;
257 return(ret);
258}
259
260/**
261 * xmlDictCreate:
262 *
263 * Create a new dictionary
264 *
265 * Returns the newly created dictionary, or NULL if an error occurred.
266 */
267xmlDictPtr
268xmlDictCreate(void) {
269 xmlDictPtr dict;
270
271 xmlInitParser();
272
273 dict = xmlMalloc(sizeof(xmlDict));
274 if (dict == NULL)
275 return(NULL);
276 dict->ref_counter = 1;
277 dict->limit = 0;
278
279 dict->size = 0;
280 dict->nbElems = 0;
281 dict->table = NULL;
282 dict->strings = NULL;
283 dict->subdict = NULL;
284 dict->seed = xmlRandom();
285#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
286 dict->seed = 0;
287#endif
288 return(dict);
289}
290
291/**
292 * xmlDictCreateSub:
293 * @sub: an existing dictionary
294 *
295 * Create a new dictionary, inheriting strings from the read-only
296 * dictionary @sub. On lookup, strings are first searched in the
297 * new dictionary, then in @sub, and if not found are created in the
298 * new dictionary.
299 *
300 * Returns the newly created dictionary, or NULL if an error occurred.
301 */
302xmlDictPtr
303xmlDictCreateSub(xmlDictPtr sub) {
304 xmlDictPtr dict = xmlDictCreate();
305
306 if ((dict != NULL) && (sub != NULL)) {
307 dict->seed = sub->seed;
308 dict->subdict = sub;
309 xmlDictReference(dict->subdict);
310 }
311 return(dict);
312}
313
314/**
315 * xmlDictReference:
316 * @dict: the dictionary
317 *
318 * Increment the reference counter of a dictionary
319 *
320 * Returns 0 in case of success and -1 in case of error
321 */
322int
323xmlDictReference(xmlDictPtr dict) {
324 if (dict == NULL) return -1;
325 xmlMutexLock(&xmlDictMutex);
326 dict->ref_counter++;
327 xmlMutexUnlock(&xmlDictMutex);
328 return(0);
329}
330
331/**
332 * xmlDictFree:
333 * @dict: the dictionary
334 *
335 * Free the hash @dict and its contents. The userdata is
336 * deallocated with @f if provided.
337 */
338void
339xmlDictFree(xmlDictPtr dict) {
340 xmlDictStringsPtr pool, nextp;
341
342 if (dict == NULL)
343 return;
344
345 /* decrement the counter, it may be shared by a parser and docs */
346 xmlMutexLock(&xmlDictMutex);
347 dict->ref_counter--;
348 if (dict->ref_counter > 0) {
349 xmlMutexUnlock(&xmlDictMutex);
350 return;
351 }
352
353 xmlMutexUnlock(&xmlDictMutex);
354
355 if (dict->subdict != NULL) {
356 xmlDictFree(dict->subdict);
357 }
358
359 if (dict->table) {
360 xmlFree(dict->table);
361 }
362 pool = dict->strings;
363 while (pool != NULL) {
364 nextp = pool->next;
365 xmlFree(pool);
366 pool = nextp;
367 }
368 xmlFree(dict);
369}
370
371/**
372 * xmlDictOwns:
373 * @dict: the dictionary
374 * @str: the string
375 *
376 * check if a string is owned by the dictionary
377 *
378 * Returns 1 if true, 0 if false and -1 in case of error
379 * -1 in case of error
380 */
381int
382xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
383 xmlDictStringsPtr pool;
384
385 if ((dict == NULL) || (str == NULL))
386 return(-1);
387 pool = dict->strings;
388 while (pool != NULL) {
389 if ((str >= &pool->array[0]) && (str <= pool->free))
390 return(1);
391 pool = pool->next;
392 }
393 if (dict->subdict)
394 return(xmlDictOwns(dict->subdict, str));
395 return(0);
396}
397
398/**
399 * xmlDictSize:
400 * @dict: the dictionary
401 *
402 * Query the number of elements installed in the hash @dict.
403 *
404 * Returns the number of elements in the dictionary or
405 * -1 in case of error
406 */
407int
408xmlDictSize(xmlDictPtr dict) {
409 if (dict == NULL)
410 return(-1);
411 if (dict->subdict)
412 return(dict->nbElems + dict->subdict->nbElems);
413 return(dict->nbElems);
414}
415
416/**
417 * xmlDictSetLimit:
418 * @dict: the dictionary
419 * @limit: the limit in bytes
420 *
421 * Set a size limit for the dictionary
422 * Added in 2.9.0
423 *
424 * Returns the previous limit of the dictionary or 0
425 */
426size_t
427xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
428 size_t ret;
429
430 if (dict == NULL)
431 return(0);
432 ret = dict->limit;
433 dict->limit = limit;
434 return(ret);
435}
436
437/**
438 * xmlDictGetUsage:
439 * @dict: the dictionary
440 *
441 * Get how much memory is used by a dictionary for strings
442 * Added in 2.9.0
443 *
444 * Returns the amount of strings allocated
445 */
446size_t
447xmlDictGetUsage(xmlDictPtr dict) {
448 xmlDictStringsPtr pool;
449 size_t limit = 0;
450
451 if (dict == NULL)
452 return(0);
453 pool = dict->strings;
454 while (pool != NULL) {
455 limit += pool->size;
456 pool = pool->next;
457 }
458 return(limit);
459}
460
461/*****************************************************************
462 *
463 * The code below was rewritten and is additionally licensed under
464 * the main license in file 'Copyright'.
465 *
466 *****************************************************************/
467
468ATTRIBUTE_NO_SANITIZE_INTEGER
469static unsigned
470xmlDictHashName(unsigned seed, const xmlChar* data, size_t maxLen,
471 size_t *plen) {
472 unsigned h1, h2;
473 size_t i;
474
475 HASH_INIT(h1, h2, seed);
476
477 for (i = 0; i < maxLen && data[i]; i++) {
478 HASH_UPDATE(h1, h2, data[i]);
479 }
480
481 HASH_FINISH(h1, h2);
482
483 *plen = i;
484 return(h2 | MAX_HASH_SIZE);
485}
486
487ATTRIBUTE_NO_SANITIZE_INTEGER
488static unsigned
489xmlDictHashQName(unsigned seed, const xmlChar *prefix, const xmlChar *name,
490 size_t *pplen, size_t *plen) {
491 unsigned h1, h2;
492 size_t i;
493
494 HASH_INIT(h1, h2, seed);
495
496 for (i = 0; prefix[i] != 0; i++) {
497 HASH_UPDATE(h1, h2, prefix[i]);
498 }
499 *pplen = i;
500
501 HASH_UPDATE(h1, h2, ':');
502
503 for (i = 0; name[i] != 0; i++) {
504 HASH_UPDATE(h1, h2, name[i]);
505 }
506 *plen = i;
507
508 HASH_FINISH(h1, h2);
509
510 /*
511 * Always set the upper bit of hash values since 0 means an unoccupied
512 * bucket.
513 */
514 return(h2 | MAX_HASH_SIZE);
515}
516
517/**
518 * xmlDictComputeHash:
519 * @dict: dictionary
520 * @string: C string
521 *
522 * Compute the hash value of a C string.
523 *
524 * Returns the hash value.
525 */
526unsigned
527xmlDictComputeHash(const xmlDict *dict, const xmlChar *string) {
528 size_t len;
529 return(xmlDictHashName(dict->seed, string, SIZE_MAX, &len));
530}
531
532#define HASH_ROL31(x,n) ((x) << (n) | ((x) & 0x7FFFFFFF) >> (31 - (n)))
533
534/**
535 * xmlDictCombineHash:
536 * @v1: first hash value
537 * @v2: second hash value
538 *
539 * Combine two hash values.
540 *
541 * Returns the combined hash value.
542 */
543ATTRIBUTE_NO_SANITIZE_INTEGER
544unsigned
545xmlDictCombineHash(unsigned v1, unsigned v2) {
546 /*
547 * The upper bit of hash values is always set, so we have to operate on
548 * 31-bit hashes here.
549 */
550 v1 ^= v2;
551 v1 += HASH_ROL31(v2, 5);
552
553 return((v1 & 0xFFFFFFFF) | 0x80000000);
554}
555
556/**
557 * xmlDictFindEntry:
558 * @dict: dict
559 * @prefix: optional QName prefix
560 * @name: string
561 * @len: length of string
562 * @hashValue: valid hash value of string
563 * @pfound: result of search
564 *
565 * Try to find a matching hash table entry. If an entry was found, set
566 * @found to 1 and return the entry. Otherwise, set @found to 0 and return
567 * the location where a new entry should be inserted.
568 */
569ATTRIBUTE_NO_SANITIZE_INTEGER
570static xmlDictEntry *
571xmlDictFindEntry(const xmlDict *dict, const xmlChar *prefix,
572 const xmlChar *name, int len, unsigned hashValue,
573 int *pfound) {
574 xmlDictEntry *entry;
575 unsigned mask, pos, displ;
576 int found = 0;
577
578 mask = dict->size - 1;
579 pos = hashValue & mask;
580 entry = &dict->table[pos];
581
582 if (entry->hashValue != 0) {
583 /*
584 * Robin hood hashing: abort if the displacement of the entry
585 * is smaller than the displacement of the key we look for.
586 * This also stops at the correct position when inserting.
587 */
588 displ = 0;
589
590 do {
591 if (entry->hashValue == hashValue) {
592 if (prefix == NULL) {
593 /*
594 * name is not necessarily null-terminated.
595 */
596 if ((strncmp((const char *) entry->name,
597 (const char *) name, len) == 0) &&
598 (entry->name[len] == 0)) {
599 found = 1;
600 break;
601 }
602 } else {
603 if (xmlStrQEqual(prefix, name, entry->name)) {
604 found = 1;
605 break;
606 }
607 }
608 }
609
610 displ++;
611 pos++;
612 entry++;
613 if ((pos & mask) == 0)
614 entry = dict->table;
615 } while ((entry->hashValue != 0) &&
616 (((pos - entry->hashValue) & mask) >= displ));
617 }
618
619 *pfound = found;
620 return(entry);
621}
622
623/**
624 * xmlDictGrow:
625 * @dict: dictionary
626 * @size: new size of the dictionary
627 *
628 * Resize the dictionary hash table.
629 *
630 * Returns 0 in case of success, -1 if a memory allocation failed.
631 */
632static int
633xmlDictGrow(xmlDictPtr dict, unsigned size) {
634 const xmlDictEntry *oldentry, *oldend, *end;
635 xmlDictEntry *table;
636 unsigned oldsize, i;
637
638 /* Add 0 to avoid spurious -Wtype-limits warning on 64-bit GCC */
639 if ((size_t) size + 0 > SIZE_MAX / sizeof(table[0]))
640 return(-1);
641 table = xmlMalloc(size * sizeof(table[0]));
642 if (table == NULL)
643 return(-1);
644 memset(table, 0, size * sizeof(table[0]));
645
646 oldsize = dict->size;
647 if (oldsize == 0)
648 goto done;
649
650 oldend = &dict->table[oldsize];
651 end = &table[size];
652
653 /*
654 * Robin Hood sorting order is maintained if we
655 *
656 * - compute dict indices with modulo
657 * - resize by an integer factor
658 * - start to copy from the beginning of a probe sequence
659 */
660 oldentry = dict->table;
661 while (oldentry->hashValue != 0) {
662 if (++oldentry >= oldend)
663 oldentry = dict->table;
664 }
665
666 for (i = 0; i < oldsize; i++) {
667 if (oldentry->hashValue != 0) {
668 xmlDictEntry *entry = &table[oldentry->hashValue & (size - 1)];
669
670 while (entry->hashValue != 0) {
671 if (++entry >= end)
672 entry = table;
673 }
674 *entry = *oldentry;
675 }
676
677 if (++oldentry >= oldend)
678 oldentry = dict->table;
679 }
680
681 xmlFree(dict->table);
682
683done:
684 dict->table = table;
685 dict->size = size;
686
687 return(0);
688}
689
690/**
691 * xmlDictLookupInternal:
692 * @dict: dict
693 * @prefix: optional QName prefix
694 * @name: string
695 * @maybeLen: length of string or -1 if unknown
696 * @update: whether the string should be added
697 *
698 * Internal lookup and update function.
699 */
700ATTRIBUTE_NO_SANITIZE_INTEGER
701static const xmlDictEntry *
702xmlDictLookupInternal(xmlDictPtr dict, const xmlChar *prefix,
703 const xmlChar *name, int maybeLen, int update) {
704 xmlDictEntry *entry = NULL;
705 const xmlChar *ret;
706 unsigned hashValue;
707 size_t maxLen, len, plen, klen;
708 int found = 0;
709
710 if ((dict == NULL) || (name == NULL))
711 return(NULL);
712
713 maxLen = (maybeLen < 0) ? SIZE_MAX : (size_t) maybeLen;
714
715 if (prefix == NULL) {
716 hashValue = xmlDictHashName(dict->seed, name, maxLen, &len);
717 if (len > INT_MAX / 2)
718 return(NULL);
719 klen = len;
720 } else {
721 hashValue = xmlDictHashQName(dict->seed, prefix, name, &plen, &len);
722 if ((len > INT_MAX / 2) || (plen >= INT_MAX / 2 - len))
723 return(NULL);
724 klen = plen + 1 + len;
725 }
726
727 if ((dict->limit > 0) && (klen >= dict->limit))
728 return(NULL);
729
730 /*
731 * Check for an existing entry
732 */
733 if (dict->size > 0)
734 entry = xmlDictFindEntry(dict, prefix, name, klen, hashValue, &found);
735 if (found)
736 return(entry);
737
738 if ((dict->subdict != NULL) && (dict->subdict->size > 0)) {
739 xmlDictEntry *subEntry;
740 unsigned subHashValue;
741
742 if (prefix == NULL)
743 subHashValue = xmlDictHashName(dict->subdict->seed, name, len,
744 &len);
745 else
746 subHashValue = xmlDictHashQName(dict->subdict->seed, prefix, name,
747 &plen, &len);
748 subEntry = xmlDictFindEntry(dict->subdict, prefix, name, klen,
749 subHashValue, &found);
750 if (found)
751 return(subEntry);
752 }
753
754 if (!update)
755 return(NULL);
756
757 /*
758 * Grow the hash table if needed
759 */
760 if (dict->nbElems + 1 > dict->size / MAX_FILL_DENOM * MAX_FILL_NUM) {
761 unsigned newSize, mask, displ, pos;
762
763 if (dict->size == 0) {
764 newSize = MIN_HASH_SIZE;
765 } else {
766 if (dict->size >= MAX_HASH_SIZE)
767 return(NULL);
768 newSize = dict->size * 2;
769 }
770 if (xmlDictGrow(dict, newSize) != 0)
771 return(NULL);
772
773 /*
774 * Find new entry
775 */
776 mask = dict->size - 1;
777 displ = 0;
778 pos = hashValue & mask;
779 entry = &dict->table[pos];
780
781 while ((entry->hashValue != 0) &&
782 ((pos - entry->hashValue) & mask) >= displ) {
783 displ++;
784 pos++;
785 entry++;
786 if ((pos & mask) == 0)
787 entry = dict->table;
788 }
789 }
790
791 if (prefix == NULL)
792 ret = xmlDictAddString(dict, name, len);
793 else
794 ret = xmlDictAddQString(dict, prefix, plen, name, len);
795 if (ret == NULL)
796 return(NULL);
797
798 /*
799 * Shift the remainder of the probe sequence to the right
800 */
801 if (entry->hashValue != 0) {
802 const xmlDictEntry *end = &dict->table[dict->size];
803 const xmlDictEntry *cur = entry;
804
805 do {
806 cur++;
807 if (cur >= end)
808 cur = dict->table;
809 } while (cur->hashValue != 0);
810
811 if (cur < entry) {
812 /*
813 * If we traversed the end of the buffer, handle the part
814 * at the start of the buffer.
815 */
816 memmove(&dict->table[1], dict->table,
817 (char *) cur - (char *) dict->table);
818 cur = end - 1;
819 dict->table[0] = *cur;
820 }
821
822 memmove(&entry[1], entry, (char *) cur - (char *) entry);
823 }
824
825 /*
826 * Populate entry
827 */
828 entry->hashValue = hashValue;
829 entry->name = ret;
830
831 dict->nbElems++;
832
833 return(entry);
834}
835
836/**
837 * xmlDictLookup:
838 * @dict: dictionary
839 * @name: string key
840 * @len: length of the key, if -1 it is recomputed
841 *
842 * Lookup a string and add it to the dictionary if it wasn't found.
843 *
844 * Returns the interned copy of the string or NULL if a memory allocation
845 * failed.
846 */
847const xmlChar *
848xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
849 const xmlDictEntry *entry;
850
851 entry = xmlDictLookupInternal(dict, NULL, name, len, 1);
852 if (entry == NULL)
853 return(NULL);
854 return(entry->name);
855}
856
857/**
858 * xmlDictLookupHashed:
859 * @dict: dictionary
860 * @name: string key
861 * @len: length of the key, if -1 it is recomputed
862 *
863 * Lookup a dictionary entry and add the string to the dictionary if
864 * it wasn't found.
865 *
866 * Returns the dictionary entry.
867 */
868xmlHashedString
869xmlDictLookupHashed(xmlDictPtr dict, const xmlChar *name, int len) {
870 const xmlDictEntry *entry;
871 xmlHashedString ret;
872
873 entry = xmlDictLookupInternal(dict, NULL, name, len, 1);
874
875 if (entry == NULL) {
876 ret.name = NULL;
877 ret.hashValue = 0;
878 } else {
879 ret = *entry;
880 }
881
882 return(ret);
883}
884
885/**
886 * xmlDictExists:
887 * @dict: the dictionary
888 * @name: the name of the userdata
889 * @len: the length of the name, if -1 it is recomputed
890 *
891 * Check if a string exists in the dictionary.
892 *
893 * Returns the internal copy of the name or NULL if not found.
894 */
895const xmlChar *
896xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
897 const xmlDictEntry *entry;
898
899 entry = xmlDictLookupInternal(dict, NULL, name, len, 0);
900 if (entry == NULL)
901 return(NULL);
902 return(entry->name);
903}
904
905/**
906 * xmlDictQLookup:
907 * @dict: the dictionary
908 * @prefix: the prefix
909 * @name: the name
910 *
911 * Lookup the QName @prefix:@name and add it to the dictionary if
912 * it wasn't found.
913 *
914 * Returns the interned copy of the string or NULL if a memory allocation
915 * failed.
916 */
917const xmlChar *
918xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
919 const xmlDictEntry *entry;
920
921 entry = xmlDictLookupInternal(dict, prefix, name, -1, 1);
922 if (entry == NULL)
923 return(NULL);
924 return(entry->name);
925}
926
927#ifndef VBOX
928/*
929 * Pseudo-random generator
930 */
931
932#ifdef _WIN32
933 #define WIN32_LEAN_AND_MEAN
934 #include <windows.h>
935 #include <bcrypt.h>
936#elif defined(HAVE_GETENTROPY)
937 #ifdef HAVE_UNISTD_H
938 #include <unistd.h>
939 #endif
940 #ifdef HAVE_SYS_RANDOM_H
941 #include <sys/random.h>
942 #endif
943#else
944 #include <time.h>
945#endif
946
947static xmlMutex xmlRngMutex;
948
949static unsigned globalRngState[2];
950
951/*
952 * xmlInitRandom:
953 *
954 * Initialize the PRNG.
955 */
956ATTRIBUTE_NO_SANITIZE_INTEGER
957void
958xmlInitRandom(void) {
959 xmlInitMutex(&xmlRngMutex);
960
961 {
962#ifdef _WIN32
963 NTSTATUS status;
964
965 status = BCryptGenRandom(NULL, (unsigned char *) globalRngState,
966 sizeof(globalRngState),
967 BCRYPT_USE_SYSTEM_PREFERRED_RNG);
968 if (!BCRYPT_SUCCESS(status)) {
969 fprintf(stderr, "libxml2: BCryptGenRandom failed with "
970 "error code %lu\n", GetLastError());
971 abort();
972 }
973#elif defined(HAVE_GETENTROPY)
974 while (1) {
975 if (getentropy(globalRngState, sizeof(globalRngState)) == 0)
976 break;
977
978 if (errno != EINTR) {
979 fprintf(stderr, "libxml2: getentropy failed with "
980 "error code %d\n", errno);
981 abort();
982 }
983 }
984#else
985 int var;
986
987 globalRngState[0] =
988 (unsigned) time(NULL) ^
989 HASH_ROL((unsigned) ((size_t) &xmlInitRandom & 0xFFFFFFFF), 8);
990 globalRngState[1] =
991 HASH_ROL((unsigned) ((size_t) &xmlRngMutex & 0xFFFFFFFF), 16) ^
992 HASH_ROL((unsigned) ((size_t) &var & 0xFFFFFFFF), 24);
993#endif
994 }
995}
996
997/*
998 * xmlCleanupRandom:
999 *
1000 * Clean up PRNG globals.
1001 */
1002void
1003xmlCleanupRandom(void) {
1004 xmlCleanupMutex(&xmlRngMutex);
1005}
1006
1007ATTRIBUTE_NO_SANITIZE_INTEGER
1008static unsigned
1009xoroshiro64ss(unsigned *s) {
1010 unsigned s0 = s[0];
1011 unsigned s1 = s[1];
1012 unsigned result = HASH_ROL(s0 * 0x9E3779BB, 5) * 5;
1013
1014 s1 ^= s0;
1015 s[0] = HASH_ROL(s0, 26) ^ s1 ^ (s1 << 9);
1016 s[1] = HASH_ROL(s1, 13);
1017
1018 return(result & 0xFFFFFFFF);
1019}
1020#endif
1021
1022/*
1023 * xmlGlobalRandom:
1024 *
1025 * Generate a pseudo-random value using the global PRNG.
1026 *
1027 * Returns a random value.
1028 */
1029unsigned
1030xmlGlobalRandom(void) {
1031#ifndef VBOX
1032 unsigned ret;
1033
1034 xmlMutexLock(&xmlRngMutex);
1035 ret = xoroshiro64ss(globalRngState);
1036 xmlMutexUnlock(&xmlRngMutex);
1037
1038 return(ret);
1039#else
1040 return RTRandU32();
1041#endif
1042}
1043
1044/*
1045 * xmlRandom:
1046 *
1047 * Generate a pseudo-random value using the thread-local PRNG.
1048 *
1049 * Returns a random value.
1050 */
1051unsigned
1052xmlRandom(void) {
1053#ifndef VBOX
1054#ifdef LIBXML_THREAD_ENABLED
1055 return(xoroshiro64ss(xmlGetLocalRngState()));
1056#else
1057 return(xmlGlobalRandom());
1058#endif
1059#else
1060 return RTRandU32();
1061#endif
1062}
1063
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