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"
2012-07-25 12:32:18 +04:00
# include <limits.h>
2012-02-04 15:07:44 +04:00
# include <stdlib.h>
# include <time.h>
2022-08-26 02:22:33 +03:00
# include "private/dict.h"
2022-11-24 22:54:18 +03:00
# include "private/threads.h"
2022-08-26 02:22:33 +03:00
2012-02-04 15:07:44 +04:00
/*
* Following http : //www.ocert.org/advisories/ocert-2011-003.html
* it seems that having hash randomization might be a good idea
* when using XML with untrusted data
* Note1 : that it works correctly only if compiled with WITH_BIG_KEY
* which is the default .
* Note2 : the fast function used for a small dict won ' t protect very
* well but since the attack is based on growing a very big hash
* list we will use the BigKey algo as soon as the hash size grows
* over MIN_DICT_SIZE so this actually works
*/
2022-03-02 03:14:08 +03:00
# if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
2012-02-04 15:07:44 +04:00
# define DICT_RANDOMIZATION
# endif
2003-08-18 16:15:38 +04:00
# include <string.h>
2008-05-03 16:34:25 +04:00
# ifdef HAVE_STDINT_H
2008-04-22 12:28:50 +04:00
# include <stdint.h>
2008-10-03 11:58:23 +04:00
# else
# ifdef HAVE_INTTYPES_H
# include <inttypes.h>
2017-10-09 01:20:01 +03:00
# elif defined(_WIN32)
2008-05-03 16:34:25 +04:00
typedef unsigned __int32 uint32_t ;
# endif
2008-10-03 11:58:23 +04:00
# endif
2003-08-18 16:15:38 +04:00
# include <libxml/tree.h>
# include <libxml/dict.h>
# include <libxml/xmlmemory.h>
# include <libxml/xmlerror.h>
# include <libxml/globals.h>
2008-08-06 13:35:25 +04:00
/* #define DEBUG_GROW */
/* #define DICT_DEBUG_PATTERNS */
2008-04-22 12:28:50 +04:00
# define MAX_HASH_LEN 3
2003-08-18 16:15:38 +04:00
# define MIN_DICT_SIZE 128
2023-05-03 04:20:14 +03:00
# define MAX_DICT_HASH 100000000
2008-08-06 13:35:25 +04:00
# define WITH_BIG_KEY
# ifdef WITH_BIG_KEY
2012-02-04 15:07:44 +04:00
# define xmlDictComputeKey(dict, name, len) \
( ( ( dict ) - > size = = MIN_DICT_SIZE ) ? \
xmlDictComputeFastKey ( name , len , ( dict ) - > seed ) : \
xmlDictComputeBigKey ( name , len , ( dict ) - > seed ) )
# define xmlDictComputeQKey(dict, prefix, plen, name, len) \
( ( ( prefix ) = = NULL ) ? \
( xmlDictComputeKey ( dict , name , len ) ) : \
( ( ( dict ) - > size = = MIN_DICT_SIZE ) ? \
xmlDictComputeFastQKey ( prefix , plen , name , len , ( dict ) - > seed ) : \
xmlDictComputeBigQKey ( prefix , plen , name , len , ( dict ) - > seed ) ) )
2008-08-06 13:35:25 +04:00
# else /* !WITH_BIG_KEY */
2012-02-04 15:07:44 +04:00
# define xmlDictComputeKey(dict, name, len) \
xmlDictComputeFastKey ( name , len , ( dict ) - > seed )
# define xmlDictComputeQKey(dict, prefix, plen, name, len) \
xmlDictComputeFastQKey ( prefix , plen , name , len , ( dict ) - > seed )
2008-08-06 13:35:25 +04:00
# endif /* WITH_BIG_KEY */
2003-08-18 16:15:38 +04:00
/*
2016-04-13 17:56:07 +03:00
* An entry in the dictionary
2003-08-18 16:15:38 +04:00
*/
typedef struct _xmlDictEntry xmlDictEntry ;
typedef xmlDictEntry * xmlDictEntryPtr ;
struct _xmlDictEntry {
struct _xmlDictEntry * next ;
2003-09-17 03:17:26 +04:00
const xmlChar * name ;
2012-07-25 12:32:18 +04:00
unsigned int len ;
2003-08-18 16:15:38 +04:00
int valid ;
2008-08-08 14:09:19 +04:00
unsigned long okey ;
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 ] ;
} ;
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 ;
2003-08-18 16:15:38 +04:00
struct _xmlDictEntry * dict ;
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 */
int 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
2012-05-18 11:41:31 +04:00
# ifdef DICT_RANDOMIZATION
# ifdef HAVE_RAND_R
/*
* Internal data for random function , protected by xmlDictMutex
*/
2012-09-14 10:39:42 +04:00
static unsigned int rand_seed = 0 ;
2012-05-18 11:41:31 +04:00
# endif
# endif
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 .
2005-01-22 02:53:26 +03:00
*/
2012-05-18 11:41:31 +04:00
int xmlInitializeDict ( void ) {
2022-11-25 14:27:14 +03:00
xmlInitParser ( ) ;
2013-04-05 19:10:41 +04:00
return ( 0 ) ;
}
/**
* __xmlInitializeDict :
*
* This function is not public
* Do the dictionary mutex initialization .
*/
int __xmlInitializeDict ( void ) {
2022-11-24 22:54:18 +03:00
xmlInitMutex ( & xmlDictMutex ) ;
2005-01-22 02:53:26 +03:00
2012-02-04 15:07:44 +04:00
# ifdef DICT_RANDOMIZATION
2012-05-18 11:41:31 +04:00
# ifdef HAVE_RAND_R
rand_seed = time ( NULL ) ;
rand_r ( & rand_seed ) ;
# else
2012-02-04 15:07:44 +04:00
srand ( time ( NULL ) ) ;
2012-05-18 11:41:31 +04:00
# endif
2012-02-04 15:07:44 +04:00
# endif
2005-01-22 02:53:26 +03:00
return ( 1 ) ;
}
2012-05-18 11:41:31 +04:00
# ifdef DICT_RANDOMIZATION
int __xmlRandom ( void ) {
int ret ;
2022-11-24 22:54:18 +03:00
xmlMutexLock ( & xmlDictMutex ) ;
2012-05-18 11:41:31 +04:00
# ifdef HAVE_RAND_R
ret = rand_r ( & rand_seed ) ;
# else
ret = rand ( ) ;
# endif
2022-11-24 22:54:18 +03:00
xmlMutexUnlock ( & xmlDictMutex ) ;
2012-05-18 11:41:31 +04:00
return ( ret ) ;
}
# endif
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
2008-08-06 13:35:25 +04:00
# ifdef DICT_DEBUG_PATTERNS
fprintf ( stderr , " - " ) ;
# endif
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 ) ;
}
2003-09-17 03:17:26 +04:00
if ( size = = 0 ) size = 1000 ;
else size * = 4 ; /* exponential growth */
2012-07-25 12:32:18 +04:00
if ( size < 4 * namelen )
2003-09-17 03:17:26 +04:00
size = 4 * namelen ; /* just in case ! */
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 ;
2008-08-06 13:35:25 +04:00
# ifdef DICT_DEBUG_PATTERNS
fprintf ( stderr , " + " ) ;
# endif
2003-09-17 03:17:26 +04:00
}
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
if ( prefix = = NULL ) return ( xmlDictAddString ( dict , name , namelen ) ) ;
2008-08-06 13:35:25 +04:00
# ifdef DICT_DEBUG_PATTERNS
fprintf ( stderr , " = " ) ;
# endif
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 ;
2008-08-06 13:35:25 +04:00
# ifdef DICT_DEBUG_PATTERNS
fprintf ( stderr , " + " ) ;
# endif
2003-09-19 16:44:05 +04:00
}
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 ) ;
}
2008-08-06 13:35:25 +04:00
# ifdef WITH_BIG_KEY
2003-08-18 16:15:38 +04:00
/*
2008-04-22 12:28:50 +04:00
* xmlDictComputeBigKey :
*
* Calculate a hash key using a good hash function that works well for
* larger hash table sizes .
*
2008-08-06 13:35:25 +04:00
* Hash function by " One-at-a-Time Hash " see
2008-04-22 12:28:50 +04:00
* http : //burtleburtle.net/bob/hash/doobs.html
*/
2019-10-14 16:38:28 +03:00
# ifdef __clang__
2019-05-16 22:17:28 +03:00
ATTRIBUTE_NO_SANITIZE ( " unsigned-integer-overflow " )
2023-03-12 16:45:14 +03:00
ATTRIBUTE_NO_SANITIZE ( " unsigned-shift-base " )
2019-10-14 16:38:28 +03:00
# endif
2008-04-22 12:28:50 +04:00
static uint32_t
2012-02-04 15:07:44 +04:00
xmlDictComputeBigKey ( const xmlChar * data , int namelen , int seed ) {
2008-08-06 13:35:25 +04:00
uint32_t hash ;
int i ;
2008-04-22 12:28:50 +04:00
2008-08-06 13:35:25 +04:00
if ( namelen < = 0 | | data = = NULL ) return ( 0 ) ;
2012-02-04 15:07:44 +04:00
hash = seed ;
2008-08-06 13:35:25 +04:00
for ( i = 0 ; i < namelen ; i + + ) {
hash + = data [ i ] ;
hash + = ( hash < < 10 ) ;
hash ^ = ( hash > > 6 ) ;
2008-04-22 12:28:50 +04:00
}
2008-08-06 13:35:25 +04:00
hash + = ( hash < < 3 ) ;
hash ^ = ( hash > > 11 ) ;
hash + = ( hash < < 15 ) ;
2008-04-22 12:28:50 +04:00
2008-08-06 13:35:25 +04:00
return hash ;
}
/*
* xmlDictComputeBigQKey :
*
* Calculate a hash key for two strings using a good hash function
* that works well for larger hash table sizes .
*
* Hash function by " One-at-a-Time Hash " see
* http : //burtleburtle.net/bob/hash/doobs.html
*
* Neither of the two strings must be NULL .
*/
2019-10-14 16:38:28 +03:00
# ifdef __clang__
2019-05-16 22:17:28 +03:00
ATTRIBUTE_NO_SANITIZE ( " unsigned-integer-overflow " )
2023-03-12 16:45:14 +03:00
ATTRIBUTE_NO_SANITIZE ( " unsigned-shift-base " )
2019-10-14 16:38:28 +03:00
# endif
2008-08-06 13:35:25 +04:00
static unsigned long
2008-08-07 20:33:49 +04:00
xmlDictComputeBigQKey ( const xmlChar * prefix , int plen ,
2012-02-04 15:07:44 +04:00
const xmlChar * name , int len , int seed )
2008-08-06 13:35:25 +04:00
{
uint32_t hash ;
int i ;
2012-02-04 15:07:44 +04:00
hash = seed ;
2008-08-06 13:35:25 +04:00
for ( i = 0 ; i < plen ; i + + ) {
hash + = prefix [ i ] ;
hash + = ( hash < < 10 ) ;
hash ^ = ( hash > > 6 ) ;
}
hash + = ' : ' ;
hash + = ( hash < < 10 ) ;
hash ^ = ( hash > > 6 ) ;
for ( i = 0 ; i < len ; i + + ) {
hash + = name [ i ] ;
hash + = ( hash < < 10 ) ;
hash ^ = ( hash > > 6 ) ;
}
hash + = ( hash < < 3 ) ;
hash ^ = ( hash > > 11 ) ;
hash + = ( hash < < 15 ) ;
2008-04-22 12:28:50 +04:00
return hash ;
}
2008-08-06 13:35:25 +04:00
# endif /* WITH_BIG_KEY */
2008-04-22 12:28:50 +04:00
/*
* xmlDictComputeFastKey :
*
* Calculate a hash key using a fast hash function that works well
* for low hash table fill .
2003-08-18 16:15:38 +04:00
*/
static unsigned long
2012-02-04 15:07:44 +04:00
xmlDictComputeFastKey ( const xmlChar * name , int namelen , int seed ) {
unsigned long value = seed ;
2008-08-06 13:35:25 +04:00
2023-04-07 12:49:27 +03:00
if ( ( name = = NULL ) | | ( namelen < = 0 ) )
return ( value ) ;
2019-11-07 15:59:10 +03:00
value + = * name ;
2004-01-23 16:15:13 +03:00
value < < = 5 ;
2003-08-18 16:15:38 +04:00
if ( namelen > 10 ) {
value + = name [ namelen - 1 ] ;
namelen = 10 ;
}
switch ( namelen ) {
case 10 : value + = name [ 9 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-08-18 16:15:38 +04:00
case 9 : value + = name [ 8 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-08-18 16:15:38 +04:00
case 8 : value + = name [ 7 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-08-18 16:15:38 +04:00
case 7 : value + = name [ 6 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-08-18 16:15:38 +04:00
case 6 : value + = name [ 5 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-08-18 16:15:38 +04:00
case 5 : value + = name [ 4 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-08-18 16:15:38 +04:00
case 4 : value + = name [ 3 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-08-18 16:15:38 +04:00
case 3 : value + = name [ 2 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-08-18 16:15:38 +04:00
case 2 : value + = name [ 1 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-08-18 16:15:38 +04:00
default : break ;
}
2004-01-23 16:15:13 +03:00
return ( value ) ;
2003-09-19 16:44:05 +04:00
}
/*
2008-04-22 12:28:50 +04:00
* xmlDictComputeFastQKey :
*
* Calculate a hash key for two strings using a fast hash function
* that works well for low hash table fill .
*
* Neither of the two strings must be NULL .
2003-09-19 16:44:05 +04:00
*/
static unsigned long
2008-08-07 20:33:49 +04:00
xmlDictComputeFastQKey ( const xmlChar * prefix , int plen ,
2012-02-04 15:07:44 +04:00
const xmlChar * name , int len , int seed )
2003-09-19 16:44:05 +04:00
{
2022-09-01 02:18:30 +03:00
unsigned long value = seed ;
2003-09-19 16:44:05 +04:00
if ( plen = = 0 )
2022-09-01 02:18:30 +03:00
value + = 30 * ' : ' ;
2003-09-19 16:44:05 +04:00
else
value + = 30 * ( * prefix ) ;
2008-08-06 13:35:25 +04:00
2003-09-19 16:44:05 +04:00
if ( len > 10 ) {
2015-11-20 05:47:12 +03:00
int offset = len - ( plen + 1 + 1 ) ;
if ( offset < 0 )
offset = len - ( 10 + 1 ) ;
value + = name [ offset ] ;
2003-09-19 16:44:05 +04:00
len = 10 ;
if ( plen > 10 )
plen = 10 ;
}
switch ( plen ) {
case 10 : value + = prefix [ 9 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 9 : value + = prefix [ 8 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 8 : value + = prefix [ 7 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 7 : value + = prefix [ 6 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 6 : value + = prefix [ 5 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 5 : value + = prefix [ 4 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 4 : value + = prefix [ 3 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 3 : value + = prefix [ 2 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 2 : value + = prefix [ 1 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 1 : value + = prefix [ 0 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
default : break ;
2003-08-18 16:15:38 +04:00
}
2003-09-19 16:44:05 +04:00
len - = plen ;
if ( len > 0 ) {
2022-09-01 02:18:30 +03:00
value + = ' : ' ;
2003-09-19 16:44:05 +04:00
len - - ;
}
switch ( len ) {
case 10 : value + = name [ 9 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 9 : value + = name [ 8 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 8 : value + = name [ 7 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 7 : value + = name [ 6 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 6 : value + = name [ 5 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 5 : value + = name [ 4 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 4 : value + = name [ 3 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 3 : value + = name [ 2 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 2 : value + = name [ 1 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
case 1 : value + = name [ 0 ] ;
2017-10-21 14:49:31 +03:00
/* Falls through. */
2003-09-19 16:44:05 +04:00
default : break ;
2003-08-18 16:15:38 +04:00
}
2004-01-23 16:15:13 +03:00
return ( value ) ;
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
# ifdef DICT_DEBUG_PATTERNS
fprintf ( stderr , " C " ) ;
# endif
2003-08-18 16:15:38 +04:00
dict = xmlMalloc ( sizeof ( xmlDict ) ) ;
if ( dict ) {
2003-09-25 01:23:56 +04:00
dict - > ref_counter = 1 ;
2012-07-25 12:32:18 +04:00
dict - > limit = 0 ;
2003-09-25 01:23:56 +04:00
2003-08-18 16:15:38 +04:00
dict - > size = MIN_DICT_SIZE ;
dict - > nbElems = 0 ;
dict - > dict = xmlMalloc ( MIN_DICT_SIZE * sizeof ( xmlDictEntry ) ) ;
2003-09-17 03:17:26 +04:00
dict - > strings = NULL ;
2004-01-23 16:15:13 +03:00
dict - > subdict = NULL ;
2003-08-18 16:15:38 +04:00
if ( dict - > dict ) {
2008-02-08 12:56:31 +03:00
memset ( dict - > dict , 0 , MIN_DICT_SIZE * sizeof ( xmlDictEntry ) ) ;
2012-02-04 15:07:44 +04:00
# ifdef DICT_RANDOMIZATION
2012-05-18 11:41:31 +04:00
dict - > seed = __xmlRandom ( ) ;
2012-02-04 15:07:44 +04:00
# else
dict - > seed = 0 ;
# endif
2008-02-08 12:56:31 +03:00
return ( dict ) ;
2003-08-18 16:15:38 +04:00
}
xmlFree ( dict ) ;
}
return ( NULL ) ;
}
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 ) ) {
2008-08-06 13:35:25 +04:00
# ifdef DICT_DEBUG_PATTERNS
fprintf ( stderr , " R " ) ;
# endif
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
/**
* xmlDictGrow :
2016-04-13 17:56:07 +03:00
* @ dict : the dictionary
* @ size : the new size of the dictionary
2003-08-18 16:15:38 +04:00
*
2016-04-13 17:56:07 +03:00
* resize the dictionary
2003-08-18 16:15:38 +04:00
*
* Returns 0 in case of success , - 1 in case of failure
*/
static int
2012-07-25 12:32:18 +04:00
xmlDictGrow ( xmlDictPtr dict , size_t size ) {
2008-08-08 14:09:19 +04:00
unsigned long key , okey ;
2012-07-25 12:32:18 +04:00
size_t oldsize , i ;
2003-08-18 16:15:38 +04:00
xmlDictEntryPtr iter , next ;
struct _xmlDictEntry * olddict ;
# ifdef DEBUG_GROW
unsigned long nbElem = 0 ;
# endif
2008-08-07 20:33:49 +04:00
int ret = 0 ;
2008-08-08 14:09:19 +04:00
int keep_keys = 1 ;
2008-08-06 13:35:25 +04:00
2003-08-18 16:15:38 +04:00
if ( dict = = NULL )
return ( - 1 ) ;
if ( size < 8 )
return ( - 1 ) ;
2023-05-03 04:20:14 +03:00
if ( size > MAX_DICT_HASH )
2003-08-18 16:15:38 +04:00
return ( - 1 ) ;
2008-08-06 13:35:25 +04:00
# ifdef DICT_DEBUG_PATTERNS
fprintf ( stderr , " * " ) ;
# endif
2003-08-18 16:15:38 +04:00
oldsize = dict - > size ;
olddict = dict - > dict ;
if ( olddict = = NULL )
return ( - 1 ) ;
2008-08-08 14:09:19 +04:00
if ( oldsize = = MIN_DICT_SIZE )
keep_keys = 0 ;
2008-08-06 13:35:25 +04:00
2003-08-18 16:15:38 +04:00
dict - > dict = xmlMalloc ( size * sizeof ( xmlDictEntry ) ) ;
if ( dict - > dict = = NULL ) {
dict - > dict = olddict ;
return ( - 1 ) ;
}
memset ( dict - > dict , 0 , size * sizeof ( xmlDictEntry ) ) ;
dict - > size = size ;
/* If the two loops are merged, there would be situations where
2008-08-06 13:35:25 +04:00
a new entry needs to allocated and data copied into it from
2008-08-07 20:33:49 +04:00
the main dict . It is nicer to run through the array twice , first
copying all the elements in the main array ( less probability of
allocate ) and then the rest , so we only free in the second loop .
2003-08-18 16:15:38 +04:00
*/
for ( i = 0 ; i < oldsize ; i + + ) {
2008-08-06 13:35:25 +04:00
if ( olddict [ i ] . valid = = 0 )
2003-08-18 16:15:38 +04:00
continue ;
2008-08-08 14:09:19 +04:00
if ( keep_keys )
okey = olddict [ i ] . okey ;
else
okey = xmlDictComputeKey ( dict , olddict [ i ] . name , olddict [ i ] . len ) ;
key = okey % dict - > size ;
2008-08-07 20:33:49 +04:00
if ( dict - > dict [ key ] . valid = = 0 ) {
memcpy ( & ( dict - > dict [ key ] ) , & ( olddict [ i ] ) , sizeof ( xmlDictEntry ) ) ;
dict - > dict [ key ] . next = NULL ;
2008-08-08 14:09:19 +04:00
dict - > dict [ key ] . okey = okey ;
2008-08-07 20:33:49 +04:00
} else {
xmlDictEntryPtr entry ;
entry = xmlMalloc ( sizeof ( xmlDictEntry ) ) ;
if ( entry ! = NULL ) {
entry - > name = olddict [ i ] . name ;
entry - > len = olddict [ i ] . len ;
2008-08-08 14:09:19 +04:00
entry - > okey = okey ;
2008-08-07 20:33:49 +04:00
entry - > next = dict - > dict [ key ] . next ;
entry - > valid = 1 ;
dict - > dict [ key ] . next = entry ;
} else {
2008-08-08 14:09:19 +04:00
/*
2019-09-30 18:04:54 +03:00
* we don ' t have much ways to alert from here
2017-06-17 17:15:09 +03:00
* result is losing an entry and unicity guarantee
2008-08-08 14:09:19 +04:00
*/
2008-08-07 20:33:49 +04:00
ret = - 1 ;
}
}
2003-08-18 16:15:38 +04:00
# ifdef DEBUG_GROW
nbElem + + ;
# endif
}
for ( i = 0 ; i < oldsize ; i + + ) {
iter = olddict [ i ] . next ;
while ( iter ) {
next = iter - > next ;
/*
* put back the entry in the new dict
*/
2008-08-08 14:09:19 +04:00
if ( keep_keys )
okey = iter - > okey ;
else
okey = xmlDictComputeKey ( dict , iter - > name , iter - > len ) ;
key = okey % dict - > size ;
2003-08-18 16:15:38 +04:00
if ( dict - > dict [ key ] . valid = = 0 ) {
memcpy ( & ( dict - > dict [ key ] ) , iter , sizeof ( xmlDictEntry ) ) ;
dict - > dict [ key ] . next = NULL ;
dict - > dict [ key ] . valid = 1 ;
2008-08-08 14:09:19 +04:00
dict - > dict [ key ] . okey = okey ;
2003-08-18 16:15:38 +04:00
xmlFree ( iter ) ;
} else {
2008-08-06 13:35:25 +04:00
iter - > next = dict - > dict [ key ] . next ;
2008-08-08 14:09:19 +04:00
iter - > okey = okey ;
2008-08-06 13:35:25 +04:00
dict - > dict [ key ] . next = iter ;
2003-08-18 16:15:38 +04:00
}
# ifdef DEBUG_GROW
nbElem + + ;
# endif
iter = next ;
}
}
xmlFree ( olddict ) ;
# ifdef DEBUG_GROW
xmlGenericError ( xmlGenericErrorContext ,
2012-07-25 12:32:18 +04:00
" xmlDictGrow : from %lu to %lu, %u elems \n " , oldsize , size , nbElem ) ;
2003-08-18 16:15:38 +04:00
# endif
2008-08-07 20:33:49 +04:00
return ( ret ) ;
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 ) {
2012-07-25 12:32:18 +04:00
size_t i ;
2003-08-18 16:15:38 +04:00
xmlDictEntryPtr iter ;
xmlDictEntryPtr next ;
int inside_dict = 0 ;
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 ) ;
}
2003-08-18 16:15:38 +04:00
if ( dict - > dict ) {
2003-08-19 19:01:28 +04:00
for ( i = 0 ; ( ( i < dict - > size ) & & ( dict - > nbElems > 0 ) ) ; i + + ) {
2003-08-18 16:15:38 +04:00
iter = & ( dict - > dict [ i ] ) ;
if ( iter - > valid = = 0 )
continue ;
inside_dict = 1 ;
while ( iter ) {
next = iter - > next ;
if ( ! inside_dict )
xmlFree ( iter ) ;
2003-08-19 19:01:28 +04:00
dict - > nbElems - - ;
2003-08-18 16:15:38 +04:00
inside_dict = 0 ;
iter = next ;
}
}
xmlFree ( dict - > dict ) ;
}
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 ) ;
}
/**
* xmlDictLookup :
2016-04-13 17:56:07 +03:00
* @ dict : the dictionary
2003-08-18 16:15:38 +04:00
* @ name : the name of the userdata
2003-09-07 13:14:37 +04:00
* @ len : the length of the name , if - 1 it is recomputed
2003-08-18 16:15:38 +04:00
*
2016-04-13 17:56:07 +03:00
* Add the @ name to the dictionary @ dict if not present .
2003-08-18 16:15:38 +04:00
*
* Returns the internal copy of the name or NULL in case of internal error
*/
const xmlChar *
xmlDictLookup ( xmlDictPtr dict , const xmlChar * name , int len ) {
2004-01-23 16:15:13 +03:00
unsigned long key , okey , nbi = 0 ;
2003-08-18 16:15:38 +04:00
xmlDictEntryPtr entry ;
xmlDictEntryPtr insert ;
const xmlChar * ret ;
2012-07-25 12:32:18 +04:00
unsigned int l ;
2003-08-18 16:15:38 +04:00
2003-09-07 13:14:37 +04:00
if ( ( dict = = NULL ) | | ( name = = NULL ) )
return ( NULL ) ;
if ( len < 0 )
2012-07-25 12:32:18 +04:00
l = strlen ( ( const char * ) name ) ;
else
l = len ;
if ( ( ( dict - > limit > 0 ) & & ( l > = dict - > limit ) ) | |
( l > INT_MAX / 2 ) )
return ( NULL ) ;
2003-08-18 16:15:38 +04:00
/*
* Check for duplicate and insertion location .
*/
2012-07-25 12:32:18 +04:00
okey = xmlDictComputeKey ( dict , name , l ) ;
2004-01-23 16:15:13 +03:00
key = okey % dict - > size ;
2003-08-18 16:15:38 +04:00
if ( dict - > dict [ key ] . valid = = 0 ) {
insert = NULL ;
} else {
for ( insert = & ( dict - > dict [ key ] ) ; insert - > next ! = NULL ;
insert = insert - > next ) {
2004-01-12 19:24:34 +03:00
# ifdef __GNUC__
2012-07-25 12:32:18 +04:00
if ( ( insert - > okey = = okey ) & & ( insert - > len = = l ) ) {
if ( ! memcmp ( insert - > name , name , l ) )
2004-01-12 19:24:34 +03:00
return ( insert - > name ) ;
}
# else
2012-08-13 13:54:20 +04:00
if ( ( insert - > okey = = okey ) & & ( insert - > len = = l ) & &
2012-07-25 12:32:18 +04:00
( ! xmlStrncmp ( insert - > name , name , l ) ) )
2003-08-18 16:15:38 +04:00
return ( insert - > name ) ;
2004-01-12 19:24:34 +03:00
# endif
2003-08-18 16:15:38 +04:00
nbi + + ;
}
2004-01-12 19:24:34 +03:00
# ifdef __GNUC__
2012-07-25 12:32:18 +04:00
if ( ( insert - > okey = = okey ) & & ( insert - > len = = l ) ) {
if ( ! memcmp ( insert - > name , name , l ) )
2004-01-12 19:24:34 +03:00
return ( insert - > name ) ;
}
# else
2012-07-25 12:32:18 +04:00
if ( ( insert - > okey = = okey ) & & ( insert - > len = = l ) & &
( ! xmlStrncmp ( insert - > name , name , l ) ) )
2003-08-18 16:15:38 +04:00
return ( insert - > name ) ;
2004-01-12 19:24:34 +03:00
# endif
2003-08-18 16:15:38 +04:00
}
2004-01-23 16:15:13 +03:00
if ( dict - > subdict ) {
2008-08-06 13:35:25 +04:00
unsigned long skey ;
/* we cannot always reuse the same okey for the subdict */
if ( ( ( dict - > size = = MIN_DICT_SIZE ) & &
( dict - > subdict - > size ! = MIN_DICT_SIZE ) ) | |
( ( dict - > size ! = MIN_DICT_SIZE ) & &
( dict - > subdict - > size = = MIN_DICT_SIZE ) ) )
2012-07-25 12:32:18 +04:00
skey = xmlDictComputeKey ( dict - > subdict , name , l ) ;
2008-08-06 13:35:25 +04:00
else
skey = okey ;
key = skey % dict - > subdict - > size ;
2004-01-23 16:15:13 +03:00
if ( dict - > subdict - > dict [ key ] . valid ! = 0 ) {
xmlDictEntryPtr tmp ;
for ( tmp = & ( dict - > subdict - > dict [ key ] ) ; tmp - > next ! = NULL ;
tmp = tmp - > next ) {
# ifdef __GNUC__
2012-07-25 12:32:18 +04:00
if ( ( tmp - > okey = = skey ) & & ( tmp - > len = = l ) ) {
if ( ! memcmp ( tmp - > name , name , l ) )
2004-01-23 16:15:13 +03:00
return ( tmp - > name ) ;
}
# else
2012-07-25 12:32:18 +04:00
if ( ( tmp - > okey = = skey ) & & ( tmp - > len = = l ) & &
( ! xmlStrncmp ( tmp - > name , name , l ) ) )
2004-01-23 16:15:13 +03:00
return ( tmp - > name ) ;
# endif
nbi + + ;
}
# ifdef __GNUC__
2012-07-25 12:32:18 +04:00
if ( ( tmp - > okey = = skey ) & & ( tmp - > len = = l ) ) {
if ( ! memcmp ( tmp - > name , name , l ) )
2004-01-23 16:15:13 +03:00
return ( tmp - > name ) ;
}
# else
2012-07-25 12:32:18 +04:00
if ( ( tmp - > okey = = skey ) & & ( tmp - > len = = l ) & &
( ! xmlStrncmp ( tmp - > name , name , l ) ) )
2004-01-23 16:15:13 +03:00
return ( tmp - > name ) ;
# endif
}
key = okey % dict - > size ;
}
2012-07-25 12:32:18 +04:00
ret = xmlDictAddString ( dict , name , l ) ;
2003-09-17 03:17:26 +04:00
if ( ret = = NULL )
return ( NULL ) ;
2003-08-18 16:15:38 +04:00
if ( insert = = NULL ) {
entry = & ( dict - > dict [ key ] ) ;
} else {
entry = xmlMalloc ( sizeof ( xmlDictEntry ) ) ;
if ( entry = = NULL )
return ( NULL ) ;
}
2003-09-17 03:17:26 +04:00
entry - > name = ret ;
2012-07-25 12:32:18 +04:00
entry - > len = l ;
2003-08-18 16:15:38 +04:00
entry - > next = NULL ;
entry - > valid = 1 ;
2008-08-08 14:09:19 +04:00
entry - > okey = okey ;
2003-08-18 16:15:38 +04:00
2012-07-25 12:32:18 +04:00
if ( insert ! = NULL )
2003-09-19 16:44:05 +04:00
insert - > next = entry ;
dict - > nbElems + + ;
if ( ( nbi > MAX_HASH_LEN ) & &
2008-08-07 20:33:49 +04:00
( dict - > size < = ( ( MAX_DICT_HASH / 2 ) / MAX_HASH_LEN ) ) ) {
if ( xmlDictGrow ( dict , MAX_HASH_LEN * 2 * dict - > size ) ! = 0 )
return ( NULL ) ;
}
2003-09-19 16:44:05 +04:00
/* Note that entry may have been freed at this point by xmlDictGrow */
return ( ret ) ;
}
2004-11-24 15:39:00 +03:00
/**
* xmlDictExists :
2016-04-13 17:56:07 +03:00
* @ dict : the dictionary
2004-11-24 15:39:00 +03:00
* @ name : the name of the userdata
* @ len : the length of the name , if - 1 it is recomputed
*
2016-04-13 17:56:07 +03:00
* Check if the @ name exists in the dictionary @ dict .
2004-11-24 15:39:00 +03:00
*
* Returns the internal copy of the name or NULL if not found .
*/
const xmlChar *
xmlDictExists ( xmlDictPtr dict , const xmlChar * name , int len ) {
2022-10-24 21:47:10 +03:00
unsigned long key , okey ;
2004-11-24 15:39:00 +03:00
xmlDictEntryPtr insert ;
2012-07-25 12:32:18 +04:00
unsigned int l ;
2004-11-24 15:39:00 +03:00
if ( ( dict = = NULL ) | | ( name = = NULL ) )
return ( NULL ) ;
if ( len < 0 )
2012-07-25 12:32:18 +04:00
l = strlen ( ( const char * ) name ) ;
else
l = len ;
if ( ( ( dict - > limit > 0 ) & & ( l > = dict - > limit ) ) | |
( l > INT_MAX / 2 ) )
return ( NULL ) ;
2004-11-24 15:39:00 +03:00
/*
* Check for duplicate and insertion location .
*/
2012-07-25 12:32:18 +04:00
okey = xmlDictComputeKey ( dict , name , l ) ;
2004-11-24 15:39:00 +03:00
key = okey % dict - > size ;
if ( dict - > dict [ key ] . valid = = 0 ) {
insert = NULL ;
} else {
for ( insert = & ( dict - > dict [ key ] ) ; insert - > next ! = NULL ;
insert = insert - > next ) {
# ifdef __GNUC__
2012-07-25 12:32:18 +04:00
if ( ( insert - > okey = = okey ) & & ( insert - > len = = l ) ) {
if ( ! memcmp ( insert - > name , name , l ) )
2004-11-24 15:39:00 +03:00
return ( insert - > name ) ;
}
# else
2012-07-25 12:32:18 +04:00
if ( ( insert - > okey = = okey ) & & ( insert - > len = = l ) & &
( ! xmlStrncmp ( insert - > name , name , l ) ) )
2004-11-24 15:39:00 +03:00
return ( insert - > name ) ;
# endif
}
# ifdef __GNUC__
2012-07-25 12:32:18 +04:00
if ( ( insert - > okey = = okey ) & & ( insert - > len = = l ) ) {
if ( ! memcmp ( insert - > name , name , l ) )
2004-11-24 15:39:00 +03:00
return ( insert - > name ) ;
}
# else
2012-07-25 12:32:18 +04:00
if ( ( insert - > okey = = okey ) & & ( insert - > len = = l ) & &
( ! xmlStrncmp ( insert - > name , name , l ) ) )
2004-11-24 15:39:00 +03:00
return ( insert - > name ) ;
# endif
}
if ( dict - > subdict ) {
2008-08-06 13:35:25 +04:00
unsigned long skey ;
/* we cannot always reuse the same okey for the subdict */
if ( ( ( dict - > size = = MIN_DICT_SIZE ) & &
( dict - > subdict - > size ! = MIN_DICT_SIZE ) ) | |
( ( dict - > size ! = MIN_DICT_SIZE ) & &
( dict - > subdict - > size = = MIN_DICT_SIZE ) ) )
2012-07-25 12:32:18 +04:00
skey = xmlDictComputeKey ( dict - > subdict , name , l ) ;
2008-08-06 13:35:25 +04:00
else
skey = okey ;
key = skey % dict - > subdict - > size ;
2004-11-24 15:39:00 +03:00
if ( dict - > subdict - > dict [ key ] . valid ! = 0 ) {
xmlDictEntryPtr tmp ;
for ( tmp = & ( dict - > subdict - > dict [ key ] ) ; tmp - > next ! = NULL ;
tmp = tmp - > next ) {
# ifdef __GNUC__
2012-07-25 12:32:18 +04:00
if ( ( tmp - > okey = = skey ) & & ( tmp - > len = = l ) ) {
if ( ! memcmp ( tmp - > name , name , l ) )
2004-11-24 15:39:00 +03:00
return ( tmp - > name ) ;
}
# else
2012-07-25 12:32:18 +04:00
if ( ( tmp - > okey = = skey ) & & ( tmp - > len = = l ) & &
( ! xmlStrncmp ( tmp - > name , name , l ) ) )
2004-11-24 15:39:00 +03:00
return ( tmp - > name ) ;
# endif
}
# ifdef __GNUC__
2012-07-25 12:32:18 +04:00
if ( ( tmp - > okey = = skey ) & & ( tmp - > len = = l ) ) {
if ( ! memcmp ( tmp - > name , name , l ) )
2004-11-24 15:39:00 +03:00
return ( tmp - > name ) ;
}
# else
2012-07-25 12:32:18 +04:00
if ( ( tmp - > okey = = skey ) & & ( tmp - > len = = l ) & &
( ! xmlStrncmp ( tmp - > name , name , l ) ) )
2004-11-24 15:39:00 +03:00
return ( tmp - > name ) ;
# endif
}
}
/* not found */
return ( NULL ) ;
}
2003-09-19 16:44:05 +04:00
/**
* xmlDictQLookup :
2016-04-13 17:56:07 +03:00
* @ dict : the dictionary
2008-08-08 14:09:19 +04:00
* @ prefix : the prefix
2003-09-19 16:44:05 +04:00
* @ name : the name
*
* Add the QName @ prefix : @ name to the hash @ dict if not present .
*
* Returns the internal copy of the QName or NULL in case of internal error
*/
const xmlChar *
xmlDictQLookup ( xmlDictPtr dict , const xmlChar * prefix , const xmlChar * name ) {
2004-01-23 16:15:13 +03:00
unsigned long okey , key , nbi = 0 ;
2003-09-19 16:44:05 +04:00
xmlDictEntryPtr entry ;
xmlDictEntryPtr insert ;
const xmlChar * ret ;
2012-07-25 12:32:18 +04:00
unsigned int len , plen , l ;
2003-09-19 16:44:05 +04:00
if ( ( dict = = NULL ) | | ( name = = NULL ) )
return ( NULL ) ;
2008-08-07 20:33:49 +04:00
if ( prefix = = NULL )
return ( xmlDictLookup ( dict , name , - 1 ) ) ;
2003-09-19 16:44:05 +04:00
2008-08-07 20:33:49 +04:00
l = len = strlen ( ( const char * ) name ) ;
plen = strlen ( ( const char * ) prefix ) ;
len + = 1 + plen ;
2003-09-19 16:44:05 +04:00
/*
* Check for duplicate and insertion location .
*/
2008-08-07 20:33:49 +04:00
okey = xmlDictComputeQKey ( dict , prefix , plen , name , l ) ;
2004-01-23 16:15:13 +03:00
key = okey % dict - > size ;
2003-09-19 16:44:05 +04:00
if ( dict - > dict [ key ] . valid = = 0 ) {
insert = NULL ;
} else {
for ( insert = & ( dict - > dict [ key ] ) ; insert - > next ! = NULL ;
insert = insert - > next ) {
2008-08-08 14:09:19 +04:00
if ( ( insert - > okey = = okey ) & & ( insert - > len = = len ) & &
2003-09-19 16:44:05 +04:00
( xmlStrQEqual ( prefix , name , insert - > name ) ) )
return ( insert - > name ) ;
nbi + + ;
}
2008-08-08 14:09:19 +04:00
if ( ( insert - > okey = = okey ) & & ( insert - > len = = len ) & &
2003-09-19 16:44:05 +04:00
( xmlStrQEqual ( prefix , name , insert - > name ) ) )
return ( insert - > name ) ;
}
2004-01-23 16:15:13 +03:00
if ( dict - > subdict ) {
2008-08-06 13:35:25 +04:00
unsigned long skey ;
/* we cannot always reuse the same okey for the subdict */
if ( ( ( dict - > size = = MIN_DICT_SIZE ) & &
( dict - > subdict - > size ! = MIN_DICT_SIZE ) ) | |
( ( dict - > size ! = MIN_DICT_SIZE ) & &
( dict - > subdict - > size = = MIN_DICT_SIZE ) ) )
2008-08-07 20:33:49 +04:00
skey = xmlDictComputeQKey ( dict - > subdict , prefix , plen , name , l ) ;
2008-08-06 13:35:25 +04:00
else
skey = okey ;
key = skey % dict - > subdict - > size ;
2004-01-23 16:15:13 +03:00
if ( dict - > subdict - > dict [ key ] . valid ! = 0 ) {
xmlDictEntryPtr tmp ;
for ( tmp = & ( dict - > subdict - > dict [ key ] ) ; tmp - > next ! = NULL ;
tmp = tmp - > next ) {
2008-08-08 14:09:19 +04:00
if ( ( tmp - > okey = = skey ) & & ( tmp - > len = = len ) & &
2004-01-23 16:15:13 +03:00
( xmlStrQEqual ( prefix , name , tmp - > name ) ) )
return ( tmp - > name ) ;
nbi + + ;
}
2008-08-08 14:09:19 +04:00
if ( ( tmp - > okey = = skey ) & & ( tmp - > len = = len ) & &
2004-01-23 16:15:13 +03:00
( xmlStrQEqual ( prefix , name , tmp - > name ) ) )
return ( tmp - > name ) ;
}
key = okey % dict - > size ;
}
2008-08-07 20:33:49 +04:00
ret = xmlDictAddQString ( dict , prefix , plen , name , l ) ;
2003-09-19 16:44:05 +04:00
if ( ret = = NULL )
return ( NULL ) ;
if ( insert = = NULL ) {
entry = & ( dict - > dict [ key ] ) ;
} else {
entry = xmlMalloc ( sizeof ( xmlDictEntry ) ) ;
if ( entry = = NULL )
return ( NULL ) ;
}
entry - > name = ret ;
entry - > len = len ;
entry - > next = NULL ;
entry - > valid = 1 ;
2008-08-08 14:09:19 +04:00
entry - > okey = okey ;
2003-09-19 16:44:05 +04:00
2012-07-25 12:32:18 +04:00
if ( insert ! = NULL )
2003-08-18 16:15:38 +04:00
insert - > next = entry ;
dict - > nbElems + + ;
if ( ( nbi > MAX_HASH_LEN ) & &
( dict - > size < = ( ( MAX_DICT_HASH / 2 ) / MAX_HASH_LEN ) ) )
xmlDictGrow ( dict , MAX_HASH_LEN * 2 * dict - > size ) ;
/* Note that entry may have been freed at this point by xmlDictGrow */
return ( ret ) ;
}
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