VirtualBox

source: vbox/trunk/src/libs/libxml2-2.12.6/dict.c

Last change on this file was 104237, checked in by vboxsync, 6 weeks ago

libs/libxml2-2.12.6: Try fixing the solaris builds where gcc chokes on the way the RNG is seeded, use our own IPRT API to get at a random value in xmlRandom(), bugref:10640

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

© 2023 Oracle
ContactPrivacy policyTerms of Use