2003-08-18 16:15:38 +04:00
/*
* dict . c : dictionary of reusable strings , just used to avoid allocation
* and freeing operations .
*
2012-02-04 15:07:44 +04:00
* Copyright ( C ) 2003 - 2012 Daniel Veillard .
2003-08-18 16:15:38 +04:00
*
* Permission to use , copy , modify , and distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THIS SOFTWARE IS PROVIDED ` ` AS IS ' ' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , WITHOUT LIMITATION , THE IMPLIED WARRANTIES OF
2020-03-08 19:19:42 +03:00
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE . THE AUTHORS AND
2003-08-18 16:15:38 +04:00
* CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER .
*
* Author : daniel @ veillard . com
*/
# define IN_LIBXML
# include "libxml.h"
2023-12-24 16:27:46 +03:00
# include <errno.h>
2012-07-25 12:32:18 +04:00
# include <limits.h>
2023-12-24 16:27:46 +03:00
# include <stdlib.h>
2023-09-01 15:52:04 +03:00
# include <string.h>
2012-02-04 15:07:44 +04:00
# include <time.h>
2023-12-24 16:27:46 +03:00
# ifdef HAVE_SYS_RANDOM_H
# include <sys/random.h>
# endif
# ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <bcrypt.h>
# endif
2012-02-04 15:07:44 +04:00
2022-08-26 02:22:33 +03:00
# include "private/dict.h"
2023-12-24 17:33:12 +03:00
# include "private/globals.h"
2022-11-24 22:54:18 +03:00
# include "private/threads.h"
2022-08-26 02:22:33 +03:00
2023-09-20 19:54:39 +03:00
# include <libxml/parser.h>
2023-09-01 15:52:04 +03:00
# include <libxml/dict.h>
# include <libxml/xmlmemory.h>
2023-09-11 06:37:55 +03:00
# include <libxml/xmlstring.h>
2023-09-01 15:52:04 +03:00
2023-09-11 06:37:55 +03:00
# ifndef SIZE_MAX
# define SIZE_MAX ((size_t) -1)
2012-02-04 15:07:44 +04:00
# endif
2023-09-11 06:37:55 +03:00
# define MAX_FILL_NUM 7
# define MAX_FILL_DENOM 8
# define MIN_HASH_SIZE 8
# define MAX_HASH_SIZE (1u << 31)
2003-08-18 16:15:38 +04:00
2003-09-17 03:17:26 +04:00
typedef struct _xmlDictStrings xmlDictStrings ;
typedef xmlDictStrings * xmlDictStringsPtr ;
struct _xmlDictStrings {
xmlDictStringsPtr next ;
xmlChar * free ;
xmlChar * end ;
2012-07-25 12:32:18 +04:00
size_t size ;
size_t nbStrings ;
2003-09-17 03:17:26 +04:00
xmlChar array [ 1 ] ;
} ;
2023-09-11 06:37:55 +03:00
2023-09-25 15:00:48 +03:00
typedef xmlHashedString xmlDictEntry ;
2003-08-18 16:15:38 +04:00
/*
2016-04-13 17:56:07 +03:00
* The entire dictionary
2003-08-18 16:15:38 +04:00
*/
struct _xmlDict {
2003-09-25 01:23:56 +04:00
int ref_counter ;
2023-09-11 06:37:55 +03:00
xmlDictEntry * table ;
2012-07-25 12:32:18 +04:00
size_t size ;
unsigned int nbElems ;
2003-09-17 03:17:26 +04:00
xmlDictStringsPtr strings ;
2004-01-23 16:15:13 +03:00
struct _xmlDict * subdict ;
2012-02-04 15:07:44 +04:00
/* used for randomization */
2023-09-01 15:52:04 +03:00
unsigned seed ;
2012-07-25 12:32:18 +04:00
/* used to impose a limit on size */
size_t limit ;
2003-08-18 16:15:38 +04:00
} ;
2005-01-22 02:53:26 +03:00
/*
* A mutex for modifying the reference counter for shared
* dictionaries .
*/
2022-11-24 22:54:18 +03:00
static xmlMutex xmlDictMutex ;
2005-01-22 02:53:26 +03:00
/**
2005-02-11 13:58:55 +03:00
* xmlInitializeDict :
2005-01-22 02:53:26 +03:00
*
2022-11-25 14:27:14 +03:00
* DEPRECATED : Alias for xmlInitParser .
2023-11-04 21:04:23 +03:00
*
* Returns 0.
2005-01-22 02:53:26 +03:00
*/
2023-09-01 15:52:04 +03:00
int
xmlInitializeDict ( void ) {
2022-11-25 14:27:14 +03:00
xmlInitParser ( ) ;
2013-04-05 19:10:41 +04:00
return ( 0 ) ;
}
/**
2023-11-04 21:04:23 +03:00
* xmlInitDictInternal :
2013-04-05 19:10:41 +04:00
*
2023-09-16 20:08:10 +03:00
* Initialize mutex .
2013-04-05 19:10:41 +04:00
*/
2023-09-01 15:52:04 +03:00
void
xmlInitDictInternal ( void ) {
2022-11-24 22:54:18 +03:00
xmlInitMutex ( & xmlDictMutex ) ;
2012-05-18 11:41:31 +04:00
}
2005-01-22 02:53:26 +03:00
/**
2005-01-26 02:45:06 +03:00
* xmlDictCleanup :
2005-01-22 02:53:26 +03:00
*
2022-11-25 14:27:14 +03:00
* DEPRECATED : This function is a no - op . Call xmlCleanupParser
2022-03-06 15:55:48 +03:00
* to free global state but see the warnings there . xmlCleanupParser
* should be only called once at program exit . In most cases , you don ' t
* have call cleanup functions at all .
2005-01-22 02:53:26 +03:00
*/
void
xmlDictCleanup ( void ) {
2022-11-25 14:27:14 +03:00
}
/**
* xmlCleanupDictInternal :
*
* Free the dictionary mutex .
*/
void
xmlCleanupDictInternal ( void ) {
2022-11-24 22:54:18 +03:00
xmlCleanupMutex ( & xmlDictMutex ) ;
2005-01-22 02:53:26 +03:00
}
2003-09-17 03:17:26 +04:00
/*
* xmlDictAddString :
2016-04-13 17:56:07 +03:00
* @ dict : the dictionary
2003-09-17 03:17:26 +04:00
* @ name : the name of the userdata
2012-07-25 12:32:18 +04:00
* @ len : the length of the name
2003-09-17 03:17:26 +04:00
*
* Add the string to the array [ s ]
*
* Returns the pointer of the local string , or NULL in case of error .
*/
static const xmlChar *
2012-07-25 12:32:18 +04:00
xmlDictAddString ( xmlDictPtr dict , const xmlChar * name , unsigned int namelen ) {
2003-09-17 03:17:26 +04:00
xmlDictStringsPtr pool ;
const xmlChar * ret ;
2012-07-25 12:32:18 +04:00
size_t size = 0 ; /* + sizeof(_xmlDictStrings) == 1024 */
size_t limit = 0 ;
2003-09-17 03:17:26 +04:00
pool = dict - > strings ;
while ( pool ! = NULL ) {
2017-10-09 17:50:57 +03:00
if ( ( size_t ) ( pool - > end - pool - > free ) > namelen )
2003-09-17 03:17:26 +04:00
goto found_pool ;
if ( pool - > size > size ) size = pool - > size ;
2012-07-25 12:32:18 +04:00
limit + = pool - > size ;
2003-09-17 03:17:26 +04:00
pool = pool - > next ;
}
/*
* Not found , need to allocate
*/
if ( pool = = NULL ) {
2012-07-25 12:32:18 +04:00
if ( ( dict - > limit > 0 ) & & ( limit > dict - > limit ) ) {
return ( NULL ) ;
}
2023-10-11 15:19:04 +03:00
if ( size = = 0 ) {
size = 1000 ;
} else {
if ( size < ( SIZE_MAX - sizeof ( xmlDictStrings ) ) / 4 )
size * = 4 ; /* exponential growth */
else
size = SIZE_MAX - sizeof ( xmlDictStrings ) ;
}
if ( size / 4 < namelen ) {
if ( ( size_t ) namelen + 0 < ( SIZE_MAX - sizeof ( xmlDictStrings ) ) / 4 )
size = 4 * ( size_t ) namelen ; /* just in case ! */
else
return ( NULL ) ;
}
2003-09-17 03:17:26 +04:00
pool = ( xmlDictStringsPtr ) xmlMalloc ( sizeof ( xmlDictStrings ) + size ) ;
if ( pool = = NULL )
return ( NULL ) ;
pool - > size = size ;
pool - > nbStrings = 0 ;
pool - > free = & pool - > array [ 0 ] ;
pool - > end = & pool - > array [ size ] ;
pool - > next = dict - > strings ;
dict - > strings = pool ;
}
found_pool :
ret = pool - > free ;
memcpy ( pool - > free , name , namelen ) ;
pool - > free + = namelen ;
* ( pool - > free + + ) = 0 ;
2008-08-06 13:35:25 +04:00
pool - > nbStrings + + ;
2003-09-17 03:17:26 +04:00
return ( ret ) ;
}
2003-09-19 16:44:05 +04:00
/*
* xmlDictAddQString :
2016-04-13 17:56:07 +03:00
* @ dict : the dictionary
2003-09-19 16:44:05 +04:00
* @ prefix : the prefix of the userdata
2008-08-07 20:33:49 +04:00
* @ plen : the prefix length
2003-09-19 16:44:05 +04:00
* @ name : the name of the userdata
2012-07-25 12:32:18 +04:00
* @ len : the length of the name
2003-09-19 16:44:05 +04:00
*
* Add the QName to the array [ s ]
*
* Returns the pointer of the local string , or NULL in case of error .
*/
static const xmlChar *
2012-07-25 12:32:18 +04:00
xmlDictAddQString ( xmlDictPtr dict , const xmlChar * prefix , unsigned int plen ,
const xmlChar * name , unsigned int namelen )
2003-09-19 16:44:05 +04:00
{
xmlDictStringsPtr pool ;
const xmlChar * ret ;
2012-07-25 12:32:18 +04:00
size_t size = 0 ; /* + sizeof(_xmlDictStrings) == 1024 */
size_t limit = 0 ;
2003-09-19 16:44:05 +04:00
pool = dict - > strings ;
while ( pool ! = NULL ) {
2017-10-09 17:50:57 +03:00
if ( ( size_t ) ( pool - > end - pool - > free ) > namelen + plen + 1 )
2003-09-19 16:44:05 +04:00
goto found_pool ;
if ( pool - > size > size ) size = pool - > size ;
2012-07-25 12:32:18 +04:00
limit + = pool - > size ;
2003-09-19 16:44:05 +04:00
pool = pool - > next ;
}
/*
* Not found , need to allocate
*/
if ( pool = = NULL ) {
2012-07-25 12:32:18 +04:00
if ( ( dict - > limit > 0 ) & & ( limit > dict - > limit ) ) {
return ( NULL ) ;
}
2003-09-19 16:44:05 +04:00
if ( size = = 0 ) size = 1000 ;
else size * = 4 ; /* exponential growth */
2008-08-07 20:33:49 +04:00
if ( size < 4 * ( namelen + plen + 1 ) )
size = 4 * ( namelen + plen + 1 ) ; /* just in case ! */
2003-09-19 16:44:05 +04:00
pool = ( xmlDictStringsPtr ) xmlMalloc ( sizeof ( xmlDictStrings ) + size ) ;
if ( pool = = NULL )
return ( NULL ) ;
pool - > size = size ;
pool - > nbStrings = 0 ;
pool - > free = & pool - > array [ 0 ] ;
pool - > end = & pool - > array [ size ] ;
pool - > next = dict - > strings ;
dict - > strings = pool ;
}
found_pool :
ret = pool - > free ;
memcpy ( pool - > free , prefix , plen ) ;
pool - > free + = plen ;
* ( pool - > free + + ) = ' : ' ;
memcpy ( pool - > free , name , namelen ) ;
pool - > free + = namelen ;
* ( pool - > free + + ) = 0 ;
2008-08-06 13:35:25 +04:00
pool - > nbStrings + + ;
2003-09-19 16:44:05 +04:00
return ( ret ) ;
}
2003-08-18 16:15:38 +04:00
/**
* xmlDictCreate :
*
* Create a new dictionary
*
2017-06-17 17:15:09 +03:00
* Returns the newly created dictionary , or NULL if an error occurred .
2003-08-18 16:15:38 +04:00
*/
xmlDictPtr
xmlDictCreate ( void ) {
xmlDictPtr dict ;
2005-01-22 02:53:26 +03:00
2022-11-25 14:33:25 +03:00
xmlInitParser ( ) ;
2008-08-06 13:35:25 +04:00
2003-08-18 16:15:38 +04:00
dict = xmlMalloc ( sizeof ( xmlDict ) ) ;
2023-09-11 06:37:55 +03:00
if ( dict = = NULL )
return ( NULL ) ;
dict - > ref_counter = 1 ;
dict - > limit = 0 ;
dict - > size = 0 ;
dict - > nbElems = 0 ;
dict - > table = NULL ;
dict - > strings = NULL ;
dict - > subdict = NULL ;
dict - > seed = xmlRandom ( ) ;
# ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
dict - > seed = 0 ;
2012-02-04 15:07:44 +04:00
# endif
2023-09-11 06:37:55 +03:00
return ( dict ) ;
2003-08-18 16:15:38 +04:00
}
2004-01-23 16:15:13 +03:00
/**
* xmlDictCreateSub :
2016-04-13 17:56:07 +03:00
* @ sub : an existing dictionary
2004-01-23 16:15:13 +03:00
*
* Create a new dictionary , inheriting strings from the read - only
2016-04-13 17:56:07 +03:00
* dictionary @ sub . On lookup , strings are first searched in the
* new dictionary , then in @ sub , and if not found are created in the
* new dictionary .
2004-01-23 16:15:13 +03:00
*
2017-06-17 17:15:09 +03:00
* Returns the newly created dictionary , or NULL if an error occurred .
2004-01-23 16:15:13 +03:00
*/
xmlDictPtr
xmlDictCreateSub ( xmlDictPtr sub ) {
xmlDictPtr dict = xmlDictCreate ( ) ;
2008-08-06 13:35:25 +04:00
2004-01-23 16:15:13 +03:00
if ( ( dict ! = NULL ) & & ( sub ! = NULL ) ) {
2012-02-04 15:07:44 +04:00
dict - > seed = sub - > seed ;
2004-01-23 16:15:13 +03:00
dict - > subdict = sub ;
xmlDictReference ( dict - > subdict ) ;
}
return ( dict ) ;
}
2003-09-25 01:23:56 +04:00
/**
* xmlDictReference :
2016-04-13 17:56:07 +03:00
* @ dict : the dictionary
2003-09-25 01:23:56 +04:00
*
* Increment the reference counter of a dictionary
*
* Returns 0 in case of success and - 1 in case of error
*/
int
xmlDictReference ( xmlDictPtr dict ) {
if ( dict = = NULL ) return - 1 ;
2022-11-24 22:54:18 +03:00
xmlMutexLock ( & xmlDictMutex ) ;
2003-09-25 01:23:56 +04:00
dict - > ref_counter + + ;
2022-11-24 22:54:18 +03:00
xmlMutexUnlock ( & xmlDictMutex ) ;
2003-09-25 01:23:56 +04:00
return ( 0 ) ;
}
2003-08-18 16:15:38 +04:00
/**
* xmlDictFree :
2016-04-13 17:56:07 +03:00
* @ dict : the dictionary
2003-08-18 16:15:38 +04:00
*
* Free the hash @ dict and its contents . The userdata is
* deallocated with @ f if provided .
*/
void
xmlDictFree ( xmlDictPtr dict ) {
2003-09-17 03:17:26 +04:00
xmlDictStringsPtr pool , nextp ;
2003-08-18 16:15:38 +04:00
if ( dict = = NULL )
return ;
2003-09-25 01:23:56 +04:00
/* decrement the counter, it may be shared by a parser and docs */
2022-11-24 22:54:18 +03:00
xmlMutexLock ( & xmlDictMutex ) ;
2003-09-25 01:23:56 +04:00
dict - > ref_counter - - ;
2005-01-21 19:55:41 +03:00
if ( dict - > ref_counter > 0 ) {
2022-11-24 22:54:18 +03:00
xmlMutexUnlock ( & xmlDictMutex ) ;
2005-01-21 19:55:41 +03:00
return ;
}
2022-11-24 22:54:18 +03:00
xmlMutexUnlock ( & xmlDictMutex ) ;
2003-09-25 01:23:56 +04:00
2004-01-23 16:15:13 +03:00
if ( dict - > subdict ! = NULL ) {
xmlDictFree ( dict - > subdict ) ;
}
2023-09-11 06:37:55 +03:00
if ( dict - > table ) {
xmlFree ( dict - > table ) ;
2003-08-18 16:15:38 +04:00
}
2003-09-17 03:17:26 +04:00
pool = dict - > strings ;
while ( pool ! = NULL ) {
nextp = pool - > next ;
xmlFree ( pool ) ;
pool = nextp ;
}
2003-08-18 16:15:38 +04:00
xmlFree ( dict ) ;
}
2003-09-17 03:17:26 +04:00
/**
* xmlDictOwns :
2016-04-13 17:56:07 +03:00
* @ dict : the dictionary
2003-09-17 03:17:26 +04:00
* @ str : the string
*
2019-09-30 18:04:54 +03:00
* check if a string is owned by the dictionary
2003-09-17 03:17:26 +04:00
*
* Returns 1 if true , 0 if false and - 1 in case of error
* - 1 in case of error
*/
int
xmlDictOwns ( xmlDictPtr dict , const xmlChar * str ) {
xmlDictStringsPtr pool ;
if ( ( dict = = NULL ) | | ( str = = NULL ) )
return ( - 1 ) ;
pool = dict - > strings ;
while ( pool ! = NULL ) {
2004-08-31 10:47:17 +04:00
if ( ( str > = & pool - > array [ 0 ] ) & & ( str < = pool - > free ) )
2003-09-17 03:17:26 +04:00
return ( 1 ) ;
pool = pool - > next ;
}
2004-01-23 16:15:13 +03:00
if ( dict - > subdict )
return ( xmlDictOwns ( dict - > subdict , str ) ) ;
2003-09-17 03:17:26 +04:00
return ( 0 ) ;
}
2003-09-25 01:23:56 +04:00
2003-08-18 16:15:38 +04:00
/**
* xmlDictSize :
2016-04-13 17:56:07 +03:00
* @ dict : the dictionary
2003-08-18 16:15:38 +04:00
*
* Query the number of elements installed in the hash @ dict .
*
2016-04-13 17:56:07 +03:00
* Returns the number of elements in the dictionary or
2003-08-18 16:15:38 +04:00
* - 1 in case of error
*/
int
xmlDictSize ( xmlDictPtr dict ) {
if ( dict = = NULL )
return ( - 1 ) ;
2004-01-23 16:15:13 +03:00
if ( dict - > subdict )
return ( dict - > nbElems + dict - > subdict - > nbElems ) ;
2003-08-18 16:15:38 +04:00
return ( dict - > nbElems ) ;
}
2012-07-25 12:32:18 +04:00
/**
* xmlDictSetLimit :
2016-04-13 17:56:07 +03:00
* @ dict : the dictionary
2012-07-25 12:32:18 +04:00
* @ limit : the limit in bytes
*
* Set a size limit for the dictionary
* Added in 2.9 .0
*
* Returns the previous limit of the dictionary or 0
*/
size_t
xmlDictSetLimit ( xmlDictPtr dict , size_t limit ) {
size_t ret ;
if ( dict = = NULL )
return ( 0 ) ;
ret = dict - > limit ;
dict - > limit = limit ;
return ( ret ) ;
}
/**
* xmlDictGetUsage :
2016-04-13 17:56:07 +03:00
* @ dict : the dictionary
2012-07-25 12:32:18 +04:00
*
* Get how much memory is used by a dictionary for strings
* Added in 2.9 .0
*
* Returns the amount of strings allocated
*/
size_t
xmlDictGetUsage ( xmlDictPtr dict ) {
xmlDictStringsPtr pool ;
size_t limit = 0 ;
if ( dict = = NULL )
return ( 0 ) ;
pool = dict - > strings ;
while ( pool ! = NULL ) {
limit + = pool - > size ;
pool = pool - > next ;
}
return ( limit ) ;
}
2003-08-18 16:15:38 +04:00
2023-09-11 06:37:55 +03:00
/*****************************************************************
*
* The code below was rewritten and is additionally licensed under
* the main license in file ' Copyright ' .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ATTRIBUTE_NO_SANITIZE_INTEGER
static unsigned
xmlDictHashName ( unsigned seed , const xmlChar * data , size_t maxLen ,
size_t * plen ) {
unsigned h1 , h2 ;
size_t i ;
HASH_INIT ( h1 , h2 , seed ) ;
for ( i = 0 ; i < maxLen & & data [ i ] ; i + + ) {
HASH_UPDATE ( h1 , h2 , data [ i ] ) ;
}
HASH_FINISH ( h1 , h2 ) ;
* plen = i ;
return ( h2 | MAX_HASH_SIZE ) ;
}
ATTRIBUTE_NO_SANITIZE_INTEGER
static unsigned
xmlDictHashQName ( unsigned seed , const xmlChar * prefix , const xmlChar * name ,
size_t * pplen , size_t * plen ) {
unsigned h1 , h2 ;
size_t i ;
HASH_INIT ( h1 , h2 , seed ) ;
for ( i = 0 ; prefix [ i ] ! = 0 ; i + + ) {
HASH_UPDATE ( h1 , h2 , prefix [ i ] ) ;
}
* pplen = i ;
HASH_UPDATE ( h1 , h2 , ' : ' ) ;
for ( i = 0 ; name [ i ] ! = 0 ; i + + ) {
HASH_UPDATE ( h1 , h2 , name [ i ] ) ;
}
* plen = i ;
HASH_FINISH ( h1 , h2 ) ;
2023-11-05 01:47:33 +03:00
/*
* Always set the upper bit of hash values since 0 means an unoccupied
* bucket .
*/
2023-09-11 06:37:55 +03:00
return ( h2 | MAX_HASH_SIZE ) ;
}
2023-09-25 15:00:48 +03:00
unsigned
xmlDictComputeHash ( const xmlDict * dict , const xmlChar * string ) {
size_t len ;
return ( xmlDictHashName ( dict - > seed , string , SIZE_MAX , & len ) ) ;
}
2023-11-05 01:47:33 +03:00
# define HASH_ROL31(x,n) ((x) << (n) | ((x) & 0x7FFFFFFF) >> (31 - (n)))
ATTRIBUTE_NO_SANITIZE_INTEGER
unsigned
xmlDictCombineHash ( unsigned v1 , unsigned v2 ) {
/*
* The upper bit of hash values is always set , so we have to operate on
* 31 - bit hashes here .
*/
v1 ^ = v2 ;
v1 + = HASH_ROL31 ( v2 , 5 ) ;
return ( ( v1 & 0xFFFFFFFF ) | 0x80000000 ) ;
}
2023-09-11 06:37:55 +03:00
/**
* xmlDictFindEntry :
* @ dict : dict
* @ prefix : optional QName prefix
* @ name : string
* @ len : length of string
* @ hashValue : valid hash value of string
* @ pfound : result of search
*
* Try to find a matching hash table entry . If an entry was found , set
* @ found to 1 and return the entry . Otherwise , set @ found to 0 and return
* the location where a new entry should be inserted .
*/
ATTRIBUTE_NO_SANITIZE_INTEGER
static xmlDictEntry *
xmlDictFindEntry ( const xmlDict * dict , const xmlChar * prefix ,
const xmlChar * name , int len , unsigned hashValue ,
int * pfound ) {
xmlDictEntry * entry ;
unsigned mask , pos , displ ;
int found = 0 ;
mask = dict - > size - 1 ;
pos = hashValue & mask ;
entry = & dict - > table [ pos ] ;
if ( entry - > hashValue ! = 0 ) {
/*
* Robin hood hashing : abort if the displacement of the entry
* is smaller than the displacement of the key we look for .
* This also stops at the correct position when inserting .
*/
displ = 0 ;
do {
if ( entry - > hashValue = = hashValue ) {
if ( prefix = = NULL ) {
/*
* name is not necessarily null - terminated .
*/
2023-10-02 15:42:51 +03:00
if ( ( strncmp ( ( const char * ) entry - > name ,
( const char * ) name , len ) = = 0 ) & &
2023-09-11 06:37:55 +03:00
( entry - > name [ len ] = = 0 ) ) {
found = 1 ;
break ;
}
} else {
if ( xmlStrQEqual ( prefix , name , entry - > name ) ) {
found = 1 ;
break ;
}
}
}
displ + + ;
pos + + ;
entry + + ;
if ( ( pos & mask ) = = 0 )
entry = dict - > table ;
} while ( ( entry - > hashValue ! = 0 ) & &
( ( ( pos - entry - > hashValue ) & mask ) > = displ ) ) ;
}
* pfound = found ;
return ( entry ) ;
}
/**
* xmlDictGrow :
* @ dict : dictionary
* @ size : new size of the dictionary
*
* Resize the dictionary hash table .
*
* Returns 0 in case of success , - 1 if a memory allocation failed .
*/
static int
xmlDictGrow ( xmlDictPtr dict , unsigned size ) {
const xmlDictEntry * oldentry , * oldend , * end ;
xmlDictEntry * table ;
unsigned oldsize , i ;
/* Add 0 to avoid spurious -Wtype-limits warning on 64-bit GCC */
if ( ( size_t ) size + 0 > SIZE_MAX / sizeof ( table [ 0 ] ) )
return ( - 1 ) ;
table = xmlMalloc ( size * sizeof ( table [ 0 ] ) ) ;
if ( table = = NULL )
return ( - 1 ) ;
memset ( table , 0 , size * sizeof ( table [ 0 ] ) ) ;
oldsize = dict - > size ;
if ( oldsize = = 0 )
goto done ;
oldend = & dict - > table [ oldsize ] ;
end = & table [ size ] ;
/*
* Robin Hood sorting order is maintained if we
*
* - compute dict indices with modulo
* - resize by an integer factor
* - start to copy from the beginning of a probe sequence
*/
oldentry = dict - > table ;
while ( oldentry - > hashValue ! = 0 ) {
if ( + + oldentry > = oldend )
oldentry = dict - > table ;
}
for ( i = 0 ; i < oldsize ; i + + ) {
if ( oldentry - > hashValue ! = 0 ) {
xmlDictEntry * entry = & table [ oldentry - > hashValue & ( size - 1 ) ] ;
while ( entry - > hashValue ! = 0 ) {
if ( + + entry > = end )
entry = table ;
}
* entry = * oldentry ;
}
if ( + + oldentry > = oldend )
oldentry = dict - > table ;
}
xmlFree ( dict - > table ) ;
done :
dict - > table = table ;
dict - > size = size ;
return ( 0 ) ;
}
/**
* xmlDictLookupInternal :
* @ dict : dict
* @ prefix : optional QName prefix
* @ name : string
* @ maybeLen : length of string or - 1 if unknown
* @ update : whether the string should be added
*
* Internal lookup and update function .
*/
ATTRIBUTE_NO_SANITIZE_INTEGER
2023-09-25 15:00:48 +03:00
static const xmlDictEntry *
2023-09-11 06:37:55 +03:00
xmlDictLookupInternal ( xmlDictPtr dict , const xmlChar * prefix ,
const xmlChar * name , int maybeLen , int update ) {
2023-09-25 15:00:48 +03:00
xmlDictEntry * entry = NULL ;
2023-09-11 06:37:55 +03:00
const xmlChar * ret ;
unsigned hashValue ;
size_t maxLen , len , plen , klen ;
int found = 0 ;
if ( ( dict = = NULL ) | | ( name = = NULL ) )
return ( NULL ) ;
maxLen = ( maybeLen < 0 ) ? SIZE_MAX : ( size_t ) maybeLen ;
if ( prefix = = NULL ) {
hashValue = xmlDictHashName ( dict - > seed , name , maxLen , & len ) ;
2023-10-11 15:19:04 +03:00
if ( len > INT_MAX / 2 )
2023-09-11 06:37:55 +03:00
return ( NULL ) ;
klen = len ;
} else {
hashValue = xmlDictHashQName ( dict - > seed , prefix , name , & plen , & len ) ;
2023-10-11 15:19:04 +03:00
if ( ( len > INT_MAX / 2 ) | | ( plen > = INT_MAX / 2 - len ) )
2023-09-11 06:37:55 +03:00
return ( NULL ) ;
klen = plen + 1 + len ;
}
if ( ( dict - > limit > 0 ) & & ( klen > = dict - > limit ) )
return ( NULL ) ;
/*
* Check for an existing entry
*/
if ( dict - > size > 0 )
entry = xmlDictFindEntry ( dict , prefix , name , klen , hashValue , & found ) ;
if ( found )
2023-09-25 15:00:48 +03:00
return ( entry ) ;
2023-09-11 06:37:55 +03:00
2023-09-30 18:05:47 +03:00
if ( ( dict - > subdict ! = NULL ) & & ( dict - > subdict - > size > 0 ) ) {
2023-09-11 06:37:55 +03:00
xmlDictEntry * subEntry ;
unsigned subHashValue ;
if ( prefix = = NULL )
subHashValue = xmlDictHashName ( dict - > subdict - > seed , name , len ,
& len ) ;
else
subHashValue = xmlDictHashQName ( dict - > subdict - > seed , prefix , name ,
& plen , & len ) ;
subEntry = xmlDictFindEntry ( dict - > subdict , prefix , name , klen ,
subHashValue , & found ) ;
if ( found )
2023-09-25 15:00:48 +03:00
return ( subEntry ) ;
2023-09-11 06:37:55 +03:00
}
if ( ! update )
return ( NULL ) ;
/*
* Grow the hash table if needed
*/
if ( dict - > nbElems + 1 > dict - > size / MAX_FILL_DENOM * MAX_FILL_NUM ) {
unsigned newSize , mask , displ , pos ;
if ( dict - > size = = 0 ) {
newSize = MIN_HASH_SIZE ;
} else {
if ( dict - > size > = MAX_HASH_SIZE )
return ( NULL ) ;
newSize = dict - > size * 2 ;
}
if ( xmlDictGrow ( dict , newSize ) ! = 0 )
return ( NULL ) ;
/*
* Find new entry
*/
mask = dict - > size - 1 ;
displ = 0 ;
pos = hashValue & mask ;
entry = & dict - > table [ pos ] ;
while ( ( entry - > hashValue ! = 0 ) & &
( ( pos - entry - > hashValue ) & mask ) > = displ ) {
displ + + ;
pos + + ;
entry + + ;
if ( ( pos & mask ) = = 0 )
entry = dict - > table ;
}
}
2023-09-30 18:02:46 +03:00
if ( prefix = = NULL )
ret = xmlDictAddString ( dict , name , len ) ;
else
ret = xmlDictAddQString ( dict , prefix , plen , name , len ) ;
if ( ret = = NULL )
return ( NULL ) ;
2023-09-11 06:37:55 +03:00
/*
* Shift the remainder of the probe sequence to the right
*/
if ( entry - > hashValue ! = 0 ) {
const xmlDictEntry * end = & dict - > table [ dict - > size ] ;
const xmlDictEntry * cur = entry ;
do {
cur + + ;
if ( cur > = end )
cur = dict - > table ;
} while ( cur - > hashValue ! = 0 ) ;
if ( cur < entry ) {
/*
* If we traversed the end of the buffer , handle the part
* at the start of the buffer .
*/
memmove ( & dict - > table [ 1 ] , dict - > table ,
( char * ) cur - ( char * ) dict - > table ) ;
cur = end - 1 ;
dict - > table [ 0 ] = * cur ;
}
memmove ( & entry [ 1 ] , entry , ( char * ) cur - ( char * ) entry ) ;
}
/*
* Populate entry
*/
entry - > hashValue = hashValue ;
entry - > name = ret ;
dict - > nbElems + + ;
2023-09-25 15:00:48 +03:00
return ( entry ) ;
2023-09-11 06:37:55 +03:00
}
/**
* xmlDictLookup :
* @ dict : dictionary
* @ name : string key
* @ len : length of the key , if - 1 it is recomputed
*
* Lookup a string and add it to the dictionary if it wasn ' t found .
*
* Returns the interned copy of the string or NULL if a memory allocation
* failed .
*/
const xmlChar *
xmlDictLookup ( xmlDictPtr dict , const xmlChar * name , int len ) {
2023-09-25 15:00:48 +03:00
const xmlDictEntry * entry ;
entry = xmlDictLookupInternal ( dict , NULL , name , len , 1 ) ;
if ( entry = = NULL )
return ( NULL ) ;
return ( entry - > name ) ;
}
/**
* xmlDictLookupHashed :
* @ dict : dictionary
* @ name : string key
* @ len : length of the key , if - 1 it is recomputed
*
* Lookup a dictionary entry and add the string to the dictionary if
* it wasn ' t found .
*
* Returns the dictionary entry .
*/
xmlHashedString
xmlDictLookupHashed ( xmlDictPtr dict , const xmlChar * name , int len ) {
const xmlDictEntry * entry ;
xmlHashedString ret ;
entry = xmlDictLookupInternal ( dict , NULL , name , len , 1 ) ;
if ( entry = = NULL ) {
ret . name = NULL ;
ret . hashValue = 0 ;
} else {
ret = * entry ;
}
return ( ret ) ;
2023-09-11 06:37:55 +03:00
}
/**
* xmlDictExists :
* @ dict : the dictionary
* @ name : the name of the userdata
* @ len : the length of the name , if - 1 it is recomputed
*
* Check if a string exists in the dictionary .
*
* Returns the internal copy of the name or NULL if not found .
*/
const xmlChar *
xmlDictExists ( xmlDictPtr dict , const xmlChar * name , int len ) {
2023-09-25 15:00:48 +03:00
const xmlDictEntry * entry ;
entry = xmlDictLookupInternal ( dict , NULL , name , len , 0 ) ;
if ( entry = = NULL )
return ( NULL ) ;
return ( entry - > name ) ;
2023-09-11 06:37:55 +03:00
}
/**
* xmlDictQLookup :
* @ dict : the dictionary
* @ prefix : the prefix
* @ name : the name
*
* Lookup the QName @ prefix : @ name and add it to the dictionary if
* it wasn ' t found .
*
* Returns the interned copy of the string or NULL if a memory allocation
* failed .
*/
const xmlChar *
xmlDictQLookup ( xmlDictPtr dict , const xmlChar * prefix , const xmlChar * name ) {
2023-09-25 15:00:48 +03:00
const xmlDictEntry * entry ;
entry = xmlDictLookupInternal ( dict , prefix , name , - 1 , 1 ) ;
if ( entry = = NULL )
return ( NULL ) ;
return ( entry - > name ) ;
2023-09-11 06:37:55 +03:00
}
2023-09-16 20:08:10 +03:00
/*
* Pseudo - random generator
*/
static xmlMutex xmlRngMutex ;
static unsigned globalRngState [ 2 ] ;
ATTRIBUTE_NO_SANITIZE_INTEGER
void
xmlInitRandom ( void ) {
xmlInitMutex ( & xmlRngMutex ) ;
2023-12-24 16:27:46 +03:00
{
# ifdef _WIN32
NTSTATUS status ;
status = BCryptGenRandom ( NULL , ( unsigned char * ) globalRngState ,
sizeof ( globalRngState ) ,
BCRYPT_USE_SYSTEM_PREFERRED_RNG ) ;
if ( ! BCRYPT_SUCCESS ( status ) ) {
fprintf ( stderr , " libxml2: BCryptGenRandom failed with "
" error code %lu \n " , GetLastError ( ) ) ;
abort ( ) ;
}
# elif defined(HAVE_GETENTROPY)
while ( 1 ) {
if ( getentropy ( globalRngState , sizeof ( globalRngState ) ) = = 0 )
break ;
if ( errno ! = EINTR ) {
fprintf ( stderr , " libxml2: getentropy failed with "
" error code %d \n " , errno ) ;
abort ( ) ;
}
}
# else
int var ;
globalRngState [ 0 ] =
( unsigned ) time ( NULL ) ^
HASH_ROL ( ( unsigned ) ( ( size_t ) & xmlInitRandom & 0xFFFFFFFF ) , 8 ) ;
globalRngState [ 1 ] =
HASH_ROL ( ( unsigned ) ( ( size_t ) & xmlRngMutex & 0xFFFFFFFF ) , 16 ) ^
HASH_ROL ( ( unsigned ) ( ( size_t ) & var & 0xFFFFFFFF ) , 24 ) ;
# endif
}
2023-09-16 20:08:10 +03:00
}
void
xmlCleanupRandom ( void ) {
xmlCleanupMutex ( & xmlRngMutex ) ;
}
ATTRIBUTE_NO_SANITIZE_INTEGER
static unsigned
xoroshiro64ss ( unsigned * s ) {
unsigned s0 = s [ 0 ] ;
unsigned s1 = s [ 1 ] ;
unsigned result = HASH_ROL ( s0 * 0x9E3779BB , 5 ) * 5 ;
s1 ^ = s0 ;
s [ 0 ] = HASH_ROL ( s0 , 26 ) ^ s1 ^ ( s1 < < 9 ) ;
s [ 1 ] = HASH_ROL ( s1 , 13 ) ;
return ( result & 0xFFFFFFFF ) ;
}
unsigned
2023-12-24 17:33:12 +03:00
xmlGlobalRandom ( void ) {
2023-09-16 20:08:10 +03:00
unsigned ret ;
xmlMutexLock ( & xmlRngMutex ) ;
ret = xoroshiro64ss ( globalRngState ) ;
xmlMutexUnlock ( & xmlRngMutex ) ;
return ( ret ) ;
2023-12-24 17:33:12 +03:00
}
unsigned
xmlRandom ( void ) {
# ifdef LIBXML_THREAD_ENABLED
return ( xoroshiro64ss ( xmlGetLocalRngState ( ) ) ) ;
# else
return ( xmlGlobalRandom ( ) ) ;
2023-09-16 20:08:10 +03:00
# endif
}