2001-02-23 20:55:21 +03:00
/*
2023-09-16 20:12:25 +03:00
* hash . c : hash tables
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Hash table with open addressing , linear probing and
* Robin Hood reordering .
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* See Copyright for the status of this software .
2001-02-23 20:55:21 +03:00
*/
2002-03-18 22:37:11 +03:00
# define IN_LIBXML
2001-04-21 20:57:29 +04:00
# include "libxml.h"
2001-02-23 20:55:21 +03:00
# include <string.h>
2023-09-16 20:12:25 +03:00
# include <limits.h>
2012-02-04 15:07:44 +04:00
2003-09-10 14:50:59 +04:00
# include <libxml/parser.h>
2001-02-23 20:55:21 +03:00
# include <libxml/hash.h>
2023-09-16 20:12:25 +03:00
# include <libxml/dict.h>
2001-02-23 20:55:21 +03:00
# include <libxml/xmlmemory.h>
2023-09-16 20:12:25 +03:00
# include <libxml/xmlstring.h>
2001-04-18 17:09:01 +04:00
2022-08-26 02:22:33 +03:00
# include "private/dict.h"
2023-09-16 20:12:25 +03:00
# ifndef SIZE_MAX
# define SIZE_MAX ((size_t) -1)
# endif
2001-04-18 17:09:01 +04:00
2023-09-16 20:12:25 +03:00
# define MAX_FILL_NUM 7
# define MAX_FILL_DENOM 8
# define MIN_HASH_SIZE 8
# define MAX_HASH_SIZE (1u << 31)
2001-02-23 20:55:21 +03:00
/*
* A single entry in the hash table
*/
2023-09-16 20:12:25 +03:00
typedef struct {
unsigned hashValue ; /* 0 means unoccupied, occupied entries have the
* MAX_HASH_SIZE bit set to 1 */
xmlChar * key ;
xmlChar * key2 ; /* TODO: Don't allocate possibly empty keys */
xmlChar * key3 ;
2001-02-23 20:55:21 +03:00
void * payload ;
2023-09-16 20:12:25 +03:00
} xmlHashEntry ;
2001-02-23 20:55:21 +03:00
/*
* The entire hash table
*/
struct _xmlHashTable {
2023-09-16 20:12:25 +03:00
xmlHashEntry * table ;
unsigned size ; /* power of two */
unsigned nbElems ;
2005-01-24 01:56:39 +03:00
xmlDictPtr dict ;
2023-09-16 20:12:25 +03:00
unsigned randomSeed ;
2001-02-23 20:55:21 +03:00
} ;
2023-09-16 20:12:25 +03:00
static int
xmlHashGrow ( xmlHashTablePtr hash , unsigned size ) ;
ATTRIBUTE_NO_SANITIZE_INTEGER
2023-09-04 17:07:23 +03:00
static unsigned
2023-09-16 20:12:25 +03:00
xmlHashValue ( unsigned seed , const xmlChar * key , const xmlChar * key2 ,
const xmlChar * key3 , size_t * lengths ) {
unsigned h1 , h2 ;
size_t i ;
2023-09-04 17:07:23 +03:00
2023-09-16 20:12:25 +03:00
HASH_INIT ( h1 , h2 , seed ) ;
2012-09-11 09:26:36 +04:00
2023-09-16 20:12:25 +03:00
for ( i = 0 ; key [ i ] ! = 0 ; i + + ) {
HASH_UPDATE ( h1 , h2 , key [ i ] ) ;
2001-04-18 17:09:01 +04:00
}
2023-09-16 20:12:25 +03:00
if ( lengths )
lengths [ 0 ] = i ;
2023-09-04 17:07:23 +03:00
HASH_UPDATE ( h1 , h2 , 0 ) ;
2023-09-16 20:12:25 +03:00
if ( key2 ! = NULL ) {
for ( i = 0 ; key2 [ i ] ! = 0 ; i + + ) {
HASH_UPDATE ( h1 , h2 , key2 [ i ] ) ;
}
if ( lengths )
lengths [ 1 ] = i ;
2001-04-18 17:09:01 +04:00
}
2023-09-16 20:12:25 +03:00
2023-09-04 17:07:23 +03:00
HASH_UPDATE ( h1 , h2 , 0 ) ;
2023-09-16 20:12:25 +03:00
if ( key3 ! = NULL ) {
for ( i = 0 ; key3 [ i ] ! = 0 ; i + + ) {
HASH_UPDATE ( h1 , h2 , key3 [ i ] ) ;
}
if ( lengths )
lengths [ 2 ] = i ;
2001-02-23 20:55:21 +03:00
}
2023-09-04 17:07:23 +03:00
HASH_FINISH ( h1 , h2 ) ;
2023-09-16 20:12:25 +03:00
return ( h2 ) ;
2001-02-23 20:55:21 +03:00
}
2023-09-16 20:12:25 +03:00
ATTRIBUTE_NO_SANITIZE_INTEGER
2023-09-04 17:07:23 +03:00
static unsigned
2023-09-16 20:12:25 +03:00
xmlHashQNameValue ( unsigned seed ,
const xmlChar * prefix , const xmlChar * name ,
const xmlChar * prefix2 , const xmlChar * name2 ,
const xmlChar * prefix3 , const xmlChar * name3 ) {
2023-09-04 17:07:23 +03:00
unsigned h1 , h2 , ch ;
2012-09-11 09:26:36 +04:00
2023-09-16 20:12:25 +03:00
HASH_INIT ( h1 , h2 , seed ) ;
2003-09-10 14:50:59 +04:00
if ( prefix ! = NULL ) {
2023-09-16 20:12:25 +03:00
while ( ( ch = * prefix + + ) ! = 0 ) {
2023-09-04 17:07:23 +03:00
HASH_UPDATE ( h1 , h2 , ch ) ;
2023-09-16 20:12:25 +03:00
}
2023-09-04 17:07:23 +03:00
HASH_UPDATE ( h1 , h2 , ' : ' ) ;
2003-09-10 14:50:59 +04:00
}
if ( name ! = NULL ) {
2023-09-16 20:12:25 +03:00
while ( ( ch = * name + + ) ! = 0 ) {
2023-09-04 17:07:23 +03:00
HASH_UPDATE ( h1 , h2 , ch ) ;
2023-09-16 20:12:25 +03:00
}
2003-09-10 14:50:59 +04:00
}
2023-09-04 17:07:23 +03:00
HASH_UPDATE ( h1 , h2 , 0 ) ;
2003-09-10 14:50:59 +04:00
if ( prefix2 ! = NULL ) {
2023-09-16 20:12:25 +03:00
while ( ( ch = * prefix2 + + ) ! = 0 ) {
2023-09-04 17:07:23 +03:00
HASH_UPDATE ( h1 , h2 , ch ) ;
2023-09-16 20:12:25 +03:00
}
2023-09-04 17:07:23 +03:00
HASH_UPDATE ( h1 , h2 , ' : ' ) ;
2003-09-10 14:50:59 +04:00
}
if ( name2 ! = NULL ) {
2023-09-16 20:12:25 +03:00
while ( ( ch = * name2 + + ) ! = 0 ) {
2023-09-04 17:07:23 +03:00
HASH_UPDATE ( h1 , h2 , ch ) ;
2023-09-16 20:12:25 +03:00
}
2003-09-10 14:50:59 +04:00
}
2023-09-04 17:07:23 +03:00
HASH_UPDATE ( h1 , h2 , 0 ) ;
2003-09-10 14:50:59 +04:00
if ( prefix3 ! = NULL ) {
2023-09-16 20:12:25 +03:00
while ( ( ch = * prefix3 + + ) ! = 0 ) {
2023-09-04 17:07:23 +03:00
HASH_UPDATE ( h1 , h2 , ch ) ;
2023-09-16 20:12:25 +03:00
}
2023-09-04 17:07:23 +03:00
HASH_UPDATE ( h1 , h2 , ' : ' ) ;
2003-09-10 14:50:59 +04:00
}
if ( name3 ! = NULL ) {
2023-09-16 20:12:25 +03:00
while ( ( ch = * name3 + + ) ! = 0 ) {
2023-09-04 17:07:23 +03:00
HASH_UPDATE ( h1 , h2 , ch ) ;
2023-09-16 20:12:25 +03:00
}
2003-09-10 14:50:59 +04:00
}
2023-09-04 17:07:23 +03:00
HASH_FINISH ( h1 , h2 ) ;
2023-09-16 20:12:25 +03:00
return ( h2 ) ;
2003-09-10 14:50:59 +04:00
}
2001-02-23 20:55:21 +03:00
/**
* xmlHashCreate :
2023-09-16 20:12:25 +03:00
* @ size : initial size of the hash table
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Create a new hash table . Set size to zero if the number of entries
* can ' t be estimated .
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Returns the newly created object , or NULL if a memory allocation failed .
2001-02-23 20:55:21 +03:00
*/
xmlHashTablePtr
xmlHashCreate ( int size ) {
2023-09-16 20:12:25 +03:00
xmlHashTablePtr hash ;
2012-09-11 09:26:36 +04:00
2023-05-06 16:28:13 +03:00
xmlInitParser ( ) ;
2023-09-16 20:12:25 +03:00
hash = xmlMalloc ( sizeof ( * hash ) ) ;
if ( hash = = NULL )
return ( NULL ) ;
hash - > dict = NULL ;
hash - > size = 0 ;
hash - > table = NULL ;
hash - > nbElems = 0 ;
hash - > randomSeed = xmlRandom ( ) ;
# ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
hash - > randomSeed = 0 ;
2012-02-04 15:07:44 +04:00
# endif
2023-09-16 20:12:25 +03:00
/*
* Unless a larger size is passed , the backing table is created
* lazily with MIN_HASH_SIZE capacity . In practice , there are many
* hash tables which are never filled .
*/
if ( size > MIN_HASH_SIZE ) {
unsigned newSize = MIN_HASH_SIZE * 2 ;
while ( ( newSize < ( unsigned ) size ) & & ( newSize < MAX_HASH_SIZE ) )
newSize * = 2 ;
if ( xmlHashGrow ( hash , newSize ) ! = 0 ) {
xmlFree ( hash ) ;
return ( NULL ) ;
2001-02-23 20:55:21 +03:00
}
}
2023-09-16 20:12:25 +03:00
return ( hash ) ;
2001-02-23 20:55:21 +03:00
}
2005-01-24 01:56:39 +03:00
/**
* xmlHashCreateDict :
* @ size : the size of the hash table
* @ dict : a dictionary to use for the hash
*
2023-09-16 20:12:25 +03:00
* Create a new hash table backed by a dictionary . This can reduce
* resource usage considerably if most keys passed to API functions
* originate from this dictionary .
2005-01-24 01:56:39 +03:00
*
2023-09-16 20:12:25 +03:00
* Returns the newly created object , or NULL if a memory allocation failed .
2005-01-24 01:56:39 +03:00
*/
xmlHashTablePtr
xmlHashCreateDict ( int size , xmlDictPtr dict ) {
2023-09-16 20:12:25 +03:00
xmlHashTablePtr hash ;
2005-01-24 01:56:39 +03:00
2023-09-16 20:12:25 +03:00
hash = xmlHashCreate ( size ) ;
if ( hash ! = NULL ) {
hash - > dict = dict ;
xmlDictReference ( dict ) ;
2005-01-24 01:56:39 +03:00
}
2023-09-16 20:12:25 +03:00
return ( hash ) ;
}
/**
* xmlHashFree :
* @ hash : hash table
* @ dealloc : deallocator function or NULL
*
* Free the hash and its contents . The payload is deallocated with
* @ dealloc if provided .
*/
void
xmlHashFree ( xmlHashTablePtr hash , xmlHashDeallocator dealloc ) {
if ( hash = = NULL )
return ;
if ( hash - > table ) {
const xmlHashEntry * end = & hash - > table [ hash - > size ] ;
const xmlHashEntry * entry ;
for ( entry = hash - > table ; entry < end ; entry + + ) {
if ( entry - > hashValue = = 0 )
continue ;
if ( ( dealloc ! = NULL ) & & ( entry - > payload ! = NULL ) )
dealloc ( entry - > payload , entry - > key ) ;
if ( hash - > dict = = NULL ) {
if ( entry - > key )
xmlFree ( entry - > key ) ;
if ( entry - > key2 )
xmlFree ( entry - > key2 ) ;
if ( entry - > key3 )
xmlFree ( entry - > key3 ) ;
}
}
xmlFree ( hash - > table ) ;
}
if ( hash - > dict )
xmlDictFree ( hash - > dict ) ;
xmlFree ( hash ) ;
}
/**
* xmlFastStrEqual :
* @ s1 : string
* @ s2 : string
*
* Compare two strings for equality , allowing NULL values .
*/
static int
xmlFastStrEqual ( const xmlChar * s1 , const xmlChar * s2 ) {
if ( s1 = = NULL )
return ( s2 = = NULL ) ;
else
return ( ( s2 ! = NULL ) & &
( strcmp ( ( const char * ) s1 , ( const char * ) s2 ) = = 0 ) ) ;
}
/**
* xmlHashFindEntry :
* @ hash : hash table , non - NULL , size > 0
* @ key : first string key , non - NULL
* @ key2 : second string key
* @ key3 : third string key
* @ hashValue : valid hash value of keys
* @ 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 xmlHashEntry *
xmlHashFindEntry ( const xmlHashTable * hash , const xmlChar * key ,
const xmlChar * key2 , const xmlChar * key3 ,
unsigned hashValue , int * pfound ) {
xmlHashEntry * entry ;
unsigned mask , pos , displ ;
int found = 0 ;
mask = hash - > size - 1 ;
pos = hashValue & mask ;
entry = & hash - > 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 ;
hashValue | = MAX_HASH_SIZE ;
do {
if ( entry - > hashValue = = hashValue ) {
if ( hash - > dict ) {
if ( ( entry - > key = = key ) & &
( entry - > key2 = = key2 ) & &
( entry - > key3 = = key3 ) ) {
found = 1 ;
break ;
}
}
if ( ( strcmp ( ( const char * ) entry - > key ,
( const char * ) key ) = = 0 ) & &
( xmlFastStrEqual ( entry - > key2 , key2 ) ) & &
( xmlFastStrEqual ( entry - > key3 , key3 ) ) ) {
found = 1 ;
break ;
}
}
displ + + ;
pos + + ;
entry + + ;
if ( ( pos & mask ) = = 0 )
entry = hash - > table ;
} while ( ( entry - > hashValue ! = 0 ) & &
( ( ( pos - entry - > hashValue ) & mask ) > = displ ) ) ;
}
* pfound = found ;
return ( entry ) ;
2005-01-24 01:56:39 +03:00
}
2001-04-18 17:09:01 +04:00
/**
* xmlHashGrow :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
* @ size : new size of the hash table
2001-04-18 17:09:01 +04:00
*
2023-09-16 20:12:25 +03:00
* Resize the hash table .
2001-04-18 17:09:01 +04:00
*
2023-09-16 20:12:25 +03:00
* Returns 0 in case of success , - 1 if a memory allocation failed .
2001-04-18 17:09:01 +04:00
*/
2001-04-20 17:03:48 +04:00
static int
2023-09-16 20:12:25 +03:00
xmlHashGrow ( xmlHashTablePtr hash , unsigned size ) {
const xmlHashEntry * oldentry , * oldend , * end ;
xmlHashEntry * table ;
unsigned oldsize , i ;
2012-09-11 09:26:36 +04:00
2023-09-16 20:12:25 +03:00
/* 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 ] ) ) ;
2001-04-18 17:09:01 +04:00
if ( table = = NULL )
return ( - 1 ) ;
2023-09-16 20:12:25 +03:00
memset ( table , 0 , size * sizeof ( table [ 0 ] ) ) ;
2012-09-11 09:26:36 +04:00
2023-09-16 20:12:25 +03:00
oldsize = hash - > size ;
if ( oldsize = = 0 )
goto done ;
oldend = & hash - > table [ oldsize ] ;
end = & table [ size ] ;
/*
* Robin Hood sorting order is maintained if we
*
* - compute hash indices with modulo
* - resize by an integer factor
* - start to copy from the beginning of a probe sequence
*/
oldentry = hash - > table ;
while ( oldentry - > hashValue ! = 0 ) {
if ( + + oldentry > = oldend )
oldentry = hash - > table ;
2002-07-02 01:52:03 +04:00
}
for ( i = 0 ; i < oldsize ; i + + ) {
2023-09-16 20:12:25 +03:00
if ( oldentry - > hashValue ! = 0 ) {
xmlHashEntry * entry = & table [ oldentry - > hashValue & ( size - 1 ) ] ;
2001-04-18 17:09:01 +04:00
2023-09-16 20:12:25 +03:00
while ( entry - > hashValue ! = 0 ) {
if ( + + entry > = end )
entry = table ;
}
* entry = * oldentry ;
}
if ( + + oldentry > = oldend )
oldentry = hash - > table ;
2001-04-18 17:09:01 +04:00
}
2023-09-16 20:12:25 +03:00
xmlFree ( hash - > table ) ;
2001-04-18 17:09:01 +04:00
2023-09-16 20:12:25 +03:00
done :
hash - > table = table ;
hash - > size = size ;
2001-04-18 17:09:01 +04:00
return ( 0 ) ;
}
2001-02-23 20:55:21 +03:00
/**
2023-09-16 20:12:25 +03:00
* xmlHashUpdateInternal :
* @ hash : hash table
* @ key : first string key
* @ key2 : second string key
* @ key3 : third string key
* @ payload : pointer to the payload
* @ dealloc : deallocator function for replaced item or NULL
* @ update : whether existing entries should be updated
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Internal function to add or update hash entries .
2001-02-23 20:55:21 +03:00
*/
2023-09-16 20:12:25 +03:00
ATTRIBUTE_NO_SANITIZE_INTEGER
static int
xmlHashUpdateInternal ( xmlHashTablePtr hash , const xmlChar * key ,
const xmlChar * key2 , const xmlChar * key3 ,
void * payload , xmlHashDeallocator dealloc , int update ) {
xmlChar * copy , * copy2 , * copy3 ;
xmlHashEntry * entry = NULL ;
size_t lengths [ 3 ] ;
unsigned hashValue ;
int found = 0 ;
if ( ( hash = = NULL ) | | ( key = = NULL ) )
return ( - 1 ) ;
2001-02-23 20:55:21 +03:00
2023-09-16 20:12:25 +03:00
/*
* Check for an existing entry
*/
hashValue = xmlHashValue ( hash - > randomSeed , key , key2 , key3 , lengths ) ;
if ( hash - > size > 0 )
entry = xmlHashFindEntry ( hash , key , key2 , key3 , hashValue , & found ) ;
if ( found ) {
if ( update ) {
if ( dealloc )
dealloc ( entry - > payload , entry - > key ) ;
entry - > payload = payload ;
}
2023-12-10 17:14:15 +03:00
return ( 0 ) ;
2001-02-23 20:55:21 +03:00
}
2023-09-16 20:12:25 +03:00
2023-09-30 18:02:46 +03:00
/*
* Grow the hash table if needed
*/
if ( hash - > nbElems + 1 > hash - > size / MAX_FILL_DENOM * MAX_FILL_NUM ) {
unsigned newSize , mask , displ , pos ;
if ( hash - > size = = 0 ) {
newSize = MIN_HASH_SIZE ;
} else {
/* This guarantees that nbElems < INT_MAX */
if ( hash - > size > = MAX_HASH_SIZE )
return ( - 1 ) ;
newSize = hash - > size * 2 ;
}
if ( xmlHashGrow ( hash , newSize ) ! = 0 )
return ( - 1 ) ;
/*
* Find new entry
*/
mask = hash - > size - 1 ;
displ = 0 ;
pos = hashValue & mask ;
entry = & hash - > table [ pos ] ;
if ( entry - > hashValue ! = 0 ) {
do {
displ + + ;
pos + + ;
entry + + ;
if ( ( pos & mask ) = = 0 )
entry = hash - > table ;
} while ( ( entry - > hashValue ! = 0 ) & &
( ( pos - entry - > hashValue ) & mask ) > = displ ) ;
}
}
2023-09-16 20:12:25 +03:00
/*
* Copy keys
*/
if ( hash - > dict ! = NULL ) {
if ( xmlDictOwns ( hash - > dict , key ) ) {
copy = ( xmlChar * ) key ;
} else {
copy = ( xmlChar * ) xmlDictLookup ( hash - > dict , key , - 1 ) ;
if ( copy = = NULL )
return ( - 1 ) ;
}
if ( ( key2 = = NULL ) | | ( xmlDictOwns ( hash - > dict , key2 ) ) ) {
copy2 = ( xmlChar * ) key2 ;
} else {
copy2 = ( xmlChar * ) xmlDictLookup ( hash - > dict , key2 , - 1 ) ;
if ( copy2 = = NULL )
return ( - 1 ) ;
}
if ( ( key3 = = NULL ) | | ( xmlDictOwns ( hash - > dict , key3 ) ) ) {
copy3 = ( xmlChar * ) key3 ;
} else {
copy3 = ( xmlChar * ) xmlDictLookup ( hash - > dict , key3 , - 1 ) ;
if ( copy3 = = NULL )
return ( - 1 ) ;
}
} else {
copy = xmlMalloc ( lengths [ 0 ] + 1 ) ;
if ( copy = = NULL )
return ( - 1 ) ;
memcpy ( copy , key , lengths [ 0 ] + 1 ) ;
if ( key2 ! = NULL ) {
copy2 = xmlMalloc ( lengths [ 1 ] + 1 ) ;
if ( copy2 = = NULL ) {
xmlFree ( copy ) ;
return ( - 1 ) ;
}
memcpy ( copy2 , key2 , lengths [ 1 ] + 1 ) ;
} else {
copy2 = NULL ;
}
if ( key3 ! = NULL ) {
copy3 = xmlMalloc ( lengths [ 2 ] + 1 ) ;
if ( copy3 = = NULL ) {
xmlFree ( copy ) ;
xmlFree ( copy2 ) ;
return ( - 1 ) ;
}
memcpy ( copy3 , key3 , lengths [ 2 ] + 1 ) ;
} else {
copy3 = NULL ;
}
}
/*
* Shift the remainder of the probe sequence to the right
*/
if ( entry - > hashValue ! = 0 ) {
const xmlHashEntry * end = & hash - > table [ hash - > size ] ;
const xmlHashEntry * cur = entry ;
do {
cur + + ;
if ( cur > = end )
cur = hash - > 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 ( & hash - > table [ 1 ] , hash - > table ,
( char * ) cur - ( char * ) hash - > table ) ;
cur = end - 1 ;
hash - > table [ 0 ] = * cur ;
}
memmove ( & entry [ 1 ] , entry , ( char * ) cur - ( char * ) entry ) ;
}
/*
* Populate entry
*/
entry - > key = copy ;
entry - > key2 = copy2 ;
entry - > key3 = copy3 ;
entry - > payload = payload ;
/* OR with MAX_HASH_SIZE to make sure that the value is non-zero */
entry - > hashValue = hashValue | MAX_HASH_SIZE ;
hash - > nbElems + + ;
2023-12-10 17:14:15 +03:00
return ( 1 ) ;
2001-02-23 20:55:21 +03:00
}
2017-11-09 18:42:47 +03:00
/**
* xmlHashDefaultDeallocator :
2023-09-16 20:12:25 +03:00
* @ entry : hash table entry
* @ key : the entry ' s string key
2017-11-09 18:42:47 +03:00
*
* Free a hash table entry with xmlFree .
*/
void
2023-09-16 20:12:25 +03:00
xmlHashDefaultDeallocator ( void * entry , const xmlChar * key ATTRIBUTE_UNUSED ) {
2017-11-09 18:42:47 +03:00
xmlFree ( entry ) ;
}
2023-12-10 17:14:15 +03:00
/**
* xmlHashAdd :
* @ hash : hash table
* @ key : string key
* @ payload : pointer to the payload
*
* Add a hash table entry . If an entry with this key already exists ,
* payload will not be updated and 0 is returned . This return value
* can ' t be distinguished from out - of - memory errors , so this function
* should be used with care .
*
2024-05-20 14:58:22 +03:00
* Available since 2.13 .0 .
*
2023-12-10 17:14:15 +03:00
* Returns 1 on success , 0 if an entry exists and - 1 in case of error .
*/
int
xmlHashAdd ( xmlHashTablePtr hash , const xmlChar * key , void * payload ) {
return ( xmlHashUpdateInternal ( hash , key , NULL , NULL , payload , NULL , 0 ) ) ;
}
/**
* xmlHashAdd2 :
* @ hash : hash table
* @ key : first string key
* @ key2 : second string key
* @ payload : pointer to the payload
*
* Add a hash table entry with two strings as key .
*
* See xmlHashAdd .
2024-05-20 14:58:22 +03:00
*
* Available since 2.13 .0 .
*
* Returns 1 on success , 0 if an entry exists and - 1 in case of error .
2023-12-10 17:14:15 +03:00
*/
int
xmlHashAdd2 ( xmlHashTablePtr hash , const xmlChar * key ,
const xmlChar * key2 , void * payload ) {
return ( xmlHashUpdateInternal ( hash , key , key2 , NULL , payload , NULL , 0 ) ) ;
}
/**
* xmlHashAdd3 :
* @ hash : hash table
* @ key : first string key
* @ key2 : second string key
* @ key3 : third string key
* @ payload : pointer to the payload
*
* Add a hash table entry with three strings as key .
*
* See xmlHashAdd .
2024-05-20 14:58:22 +03:00
*
* Available since 2.13 .0 .
*
* Returns 1 on success , 0 if an entry exists and - 1 in case of error .
2023-12-10 17:14:15 +03:00
*/
int
xmlHashAdd3 ( xmlHashTablePtr hash , const xmlChar * key ,
const xmlChar * key2 , const xmlChar * key3 ,
void * payload ) {
return ( xmlHashUpdateInternal ( hash , key , key2 , key3 , payload , NULL , 0 ) ) ;
}
2001-02-23 20:55:21 +03:00
/**
* xmlHashAddEntry :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
* @ key : string key
* @ payload : pointer to the payload
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Add a hash table entry . If an entry with this key already exists ,
* payload will not be updated and - 1 is returned . This return value
* can ' t be distinguished from out - of - memory errors , so this function
* should be used with care .
2001-02-23 20:55:21 +03:00
*
2023-12-10 17:14:15 +03:00
* NOTE : This function doesn ' t allow to distinguish malloc failures from
* existing entries . Use xmlHashAdd instead .
*
2023-09-16 20:12:25 +03:00
* Returns 0 on success and - 1 in case of error .
2001-02-23 20:55:21 +03:00
*/
int
2023-09-16 20:12:25 +03:00
xmlHashAddEntry ( xmlHashTablePtr hash , const xmlChar * key , void * payload ) {
2023-12-10 17:14:15 +03:00
int res = xmlHashUpdateInternal ( hash , key , NULL , NULL , payload , NULL , 0 ) ;
if ( res = = 0 )
res = - 1 ;
else if ( res = = 1 )
res = 0 ;
return ( res ) ;
2001-02-23 20:55:21 +03:00
}
/**
* xmlHashAddEntry2 :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
* @ key : first string key
* @ key2 : second string key
* @ payload : pointer to the payload
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Add a hash table entry with two strings as key .
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* See xmlHashAddEntry .
2023-11-04 21:04:23 +03:00
*
* Returns 0 on success and - 1 in case of error .
2001-02-23 20:55:21 +03:00
*/
int
2023-09-16 20:12:25 +03:00
xmlHashAddEntry2 ( xmlHashTablePtr hash , const xmlChar * key ,
const xmlChar * key2 , void * payload ) {
2023-12-10 17:14:15 +03:00
int res = xmlHashUpdateInternal ( hash , key , key2 , NULL , payload , NULL , 0 ) ;
if ( res = = 0 )
res = - 1 ;
else if ( res = = 1 )
res = 0 ;
return ( res ) ;
2001-02-23 20:55:21 +03:00
}
/**
2023-09-16 20:12:25 +03:00
* xmlHashAddEntry3 :
* @ hash : hash table
* @ key : first string key
* @ key2 : second string key
* @ key3 : third string key
* @ payload : pointer to the payload
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Add a hash table entry with three strings as key .
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* See xmlHashAddEntry .
2023-11-04 21:04:23 +03:00
*
* Returns 0 on success and - 1 in case of error .
2001-02-23 20:55:21 +03:00
*/
int
2023-09-16 20:12:25 +03:00
xmlHashAddEntry3 ( xmlHashTablePtr hash , const xmlChar * key ,
const xmlChar * key2 , const xmlChar * key3 ,
void * payload ) {
2023-12-10 17:14:15 +03:00
int res = xmlHashUpdateInternal ( hash , key , key2 , key3 , payload , NULL , 0 ) ;
if ( res = = 0 )
res = - 1 ;
else if ( res = = 1 )
res = 0 ;
return ( res ) ;
2001-02-23 20:55:21 +03:00
}
/**
2023-09-16 20:12:25 +03:00
* xmlHashUpdateEntry :
* @ hash : hash table
* @ key : string key
* @ payload : pointer to the payload
* @ dealloc : deallocator function for replaced item or NULL
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Add a hash table entry . If an entry with this key already exists ,
* the old payload will be freed and updated with the new value .
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Returns 0 in case of success , - 1 if a memory allocation failed .
2001-02-23 20:55:21 +03:00
*/
int
2023-09-16 20:12:25 +03:00
xmlHashUpdateEntry ( xmlHashTablePtr hash , const xmlChar * key ,
void * payload , xmlHashDeallocator dealloc ) {
2023-12-10 17:14:15 +03:00
int res = xmlHashUpdateInternal ( hash , key , NULL , NULL , payload ,
dealloc , 1 ) ;
if ( res = = 1 )
res = 0 ;
return ( res ) ;
2001-02-23 20:55:21 +03:00
}
/**
2023-09-16 20:12:25 +03:00
* xmlHashUpdateEntry2 :
* @ hash : hash table
* @ key : first string key
* @ key2 : second string key
* @ payload : pointer to the payload
* @ dealloc : deallocator function for replaced item or NULL
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Add a hash table entry with two strings as key .
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* See xmlHashUpdateEntry .
2023-11-04 21:04:23 +03:00
*
* Returns 0 on success and - 1 in case of error .
2001-02-23 20:55:21 +03:00
*/
2023-09-16 20:12:25 +03:00
int
xmlHashUpdateEntry2 ( xmlHashTablePtr hash , const xmlChar * key ,
const xmlChar * key2 , void * payload ,
xmlHashDeallocator dealloc ) {
2023-12-10 17:14:15 +03:00
int res = xmlHashUpdateInternal ( hash , key , key2 , NULL , payload ,
dealloc , 1 ) ;
if ( res = = 1 )
res = 0 ;
return ( res ) ;
2001-02-23 20:55:21 +03:00
}
/**
2023-09-16 20:12:25 +03:00
* xmlHashUpdateEntry3 :
* @ hash : hash table
* @ key : first string key
* @ key2 : second string key
* @ key3 : third string key
* @ payload : pointer to the payload
* @ dealloc : deallocator function for replaced item or NULL
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Add a hash table entry with three strings as key .
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* See xmlHashUpdateEntry .
2023-11-04 21:04:23 +03:00
*
* Returns 0 on success and - 1 in case of error .
2001-02-23 20:55:21 +03:00
*/
2023-09-16 20:12:25 +03:00
int
xmlHashUpdateEntry3 ( xmlHashTablePtr hash , const xmlChar * key ,
const xmlChar * key2 , const xmlChar * key3 ,
void * payload , xmlHashDeallocator dealloc ) {
2023-12-10 17:14:15 +03:00
int res = xmlHashUpdateInternal ( hash , key , key2 , key3 , payload ,
dealloc , 1 ) ;
if ( res = = 1 )
res = 0 ;
return ( res ) ;
2001-02-23 20:55:21 +03:00
}
2003-09-10 14:50:59 +04:00
/**
2023-09-16 20:12:25 +03:00
* xmlHashLookup :
* @ hash : hash table
* @ key : string key
2003-09-10 14:50:59 +04:00
*
2023-09-16 20:12:25 +03:00
* Find the entry specified by @ key .
2003-09-10 14:50:59 +04:00
*
2023-09-16 20:12:25 +03:00
* Returns a pointer to the payload or NULL if no entry was found .
2003-09-10 14:50:59 +04:00
*/
void *
2023-09-16 20:12:25 +03:00
xmlHashLookup ( xmlHashTablePtr hash , const xmlChar * key ) {
return ( xmlHashLookup3 ( hash , key , NULL , NULL ) ) ;
2003-09-10 14:50:59 +04:00
}
/**
2023-09-16 20:12:25 +03:00
* xmlHashLookup2 :
* @ hash : hash table
* @ key : first string key
* @ key2 : second string key
2003-09-10 14:50:59 +04:00
*
2023-09-16 20:12:25 +03:00
* Find the payload specified by the ( @ key , @ key2 ) tuple .
2003-09-10 14:50:59 +04:00
*
2023-09-16 20:12:25 +03:00
* Returns a pointer to the payload or NULL if no entry was found .
2003-09-10 14:50:59 +04:00
*/
void *
2023-09-16 20:12:25 +03:00
xmlHashLookup2 ( xmlHashTablePtr hash , const xmlChar * key ,
const xmlChar * key2 ) {
return ( xmlHashLookup3 ( hash , key , key2 , NULL ) ) ;
2003-09-10 14:50:59 +04:00
}
2001-02-23 20:55:21 +03:00
/**
2023-09-16 20:12:25 +03:00
* xmlHashQLookup :
* @ hash : hash table
* @ prefix : prefix of the string key
* @ name : local name of the string key
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Find the payload specified by the QName @ prefix : @ name or @ name .
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Returns a pointer to the payload or NULL if no entry was found .
2001-02-23 20:55:21 +03:00
*/
2023-09-16 20:12:25 +03:00
void *
xmlHashQLookup ( xmlHashTablePtr hash , const xmlChar * prefix ,
const xmlChar * name ) {
return ( xmlHashQLookup3 ( hash , prefix , name , NULL , NULL , NULL , NULL ) ) ;
2001-02-23 20:55:21 +03:00
}
/**
2023-09-16 20:12:25 +03:00
* xmlHashQLookup2 :
* @ hash : hash table
* @ prefix : first prefix
* @ name : first local name
* @ prefix2 : second prefix
* @ name2 : second local name
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Find the payload specified by the QNames tuple .
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Returns a pointer to the payload or NULL if no entry was found .
2001-02-23 20:55:21 +03:00
*/
2023-09-16 20:12:25 +03:00
void *
xmlHashQLookup2 ( xmlHashTablePtr hash , const xmlChar * prefix ,
const xmlChar * name , const xmlChar * prefix2 ,
const xmlChar * name2 ) {
return ( xmlHashQLookup3 ( hash , prefix , name , prefix2 , name2 , NULL , NULL ) ) ;
2001-02-23 20:55:21 +03:00
}
/**
2001-07-18 23:30:27 +04:00
* xmlHashLookup3 :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
* @ key : first string key
* @ key2 : second string key
* @ key3 : third string key
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Find the payload specified by the ( @ key , @ key2 , @ key3 ) tuple .
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Returns a pointer to the payload or NULL if no entry was found .
2001-02-23 20:55:21 +03:00
*/
void *
2023-09-16 20:12:25 +03:00
xmlHashLookup3 ( xmlHashTablePtr hash , const xmlChar * key ,
const xmlChar * key2 , const xmlChar * key3 ) {
const xmlHashEntry * entry ;
unsigned hashValue ;
int found ;
2001-02-23 20:55:21 +03:00
2023-09-16 20:12:25 +03:00
if ( ( hash = = NULL ) | | ( hash - > size = = 0 ) | | ( key = = NULL ) )
return ( NULL ) ;
hashValue = xmlHashValue ( hash - > randomSeed , key , key2 , key3 , NULL ) ;
entry = xmlHashFindEntry ( hash , key , key2 , key3 , hashValue , & found ) ;
if ( found )
return ( entry - > payload ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
2003-09-10 14:50:59 +04:00
/**
* xmlHashQLookup3 :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
* @ prefix : first prefix
* @ name : first local name
* @ prefix2 : second prefix
* @ name2 : second local name
* @ prefix3 : third prefix
* @ name3 : third local name
2003-09-10 14:50:59 +04:00
*
2023-09-16 20:12:25 +03:00
* Find the payload specified by the QNames tuple .
2003-09-10 14:50:59 +04:00
*
2023-09-16 20:12:25 +03:00
* Returns a pointer to the payload or NULL if no entry was found .
2003-09-10 14:50:59 +04:00
*/
2023-09-16 20:12:25 +03:00
ATTRIBUTE_NO_SANITIZE_INTEGER
2003-09-10 14:50:59 +04:00
void *
2023-09-16 20:12:25 +03:00
xmlHashQLookup3 ( xmlHashTablePtr hash ,
2003-09-10 14:50:59 +04:00
const xmlChar * prefix , const xmlChar * name ,
2023-09-16 20:12:25 +03:00
const xmlChar * prefix2 , const xmlChar * name2 ,
const xmlChar * prefix3 , const xmlChar * name3 ) {
const xmlHashEntry * entry ;
unsigned hashValue , mask , pos , displ ;
2003-09-10 14:50:59 +04:00
2023-09-16 20:12:25 +03:00
if ( ( hash = = NULL ) | | ( hash - > size = = 0 ) | | ( name = = NULL ) )
return ( NULL ) ;
hashValue = xmlHashQNameValue ( hash - > randomSeed , prefix , name , prefix2 ,
name2 , prefix3 , name3 ) ;
mask = hash - > size - 1 ;
pos = hashValue & mask ;
entry = & hash - > table [ pos ] ;
if ( entry - > hashValue ! = 0 ) {
displ = 0 ;
hashValue | = MAX_HASH_SIZE ;
do {
if ( ( hashValue = = entry - > hashValue ) & &
( xmlStrQEqual ( prefix , name , entry - > key ) ) & &
( xmlStrQEqual ( prefix2 , name2 , entry - > key2 ) ) & &
( xmlStrQEqual ( prefix3 , name3 , entry - > key3 ) ) )
return ( entry - > payload ) ;
displ + + ;
pos + + ;
entry + + ;
if ( ( pos & mask ) = = 0 )
entry = hash - > table ;
} while ( ( entry - > hashValue ! = 0 ) & &
( ( ( pos - entry - > hashValue ) & mask ) > = displ ) ) ;
2003-09-10 14:50:59 +04:00
}
2023-09-16 20:12:25 +03:00
2003-09-10 14:50:59 +04:00
return ( NULL ) ;
}
2002-06-18 11:58:35 +04:00
typedef struct {
2023-09-16 20:12:25 +03:00
xmlHashScanner scan ;
2002-06-18 11:58:35 +04:00
void * data ;
} stubData ;
2012-09-11 09:26:36 +04:00
static void
2023-09-16 20:12:25 +03:00
stubHashScannerFull ( void * payload , void * data , const xmlChar * key ,
const xmlChar * key2 ATTRIBUTE_UNUSED ,
const xmlChar * key3 ATTRIBUTE_UNUSED ) {
stubData * sdata = ( stubData * ) data ;
sdata - > scan ( payload , sdata - > data , key ) ;
2012-09-11 09:26:36 +04:00
}
2002-12-10 18:19:08 +03:00
/**
* xmlHashScan :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
* @ scan : scanner function for items in the hash
* @ data : extra data passed to @ scan
2002-12-10 18:19:08 +03:00
*
2023-09-16 20:12:25 +03:00
* Scan the hash @ table and apply @ scan to each value .
2002-12-10 18:19:08 +03:00
*/
2001-02-23 20:55:21 +03:00
void
2023-09-16 20:12:25 +03:00
xmlHashScan ( xmlHashTablePtr hash , xmlHashScanner scan , void * data ) {
stubData sdata ;
sdata . data = data ;
sdata . scan = scan ;
xmlHashScanFull ( hash , stubHashScannerFull , & sdata ) ;
2001-07-22 07:54:15 +04:00
}
/**
* xmlHashScanFull :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
* @ scan : scanner function for items in the hash
* @ data : extra data passed to @ scan
2001-07-22 07:54:15 +04:00
*
2023-09-16 20:12:25 +03:00
* Scan the hash @ table and apply @ scan to each value .
2001-07-22 07:54:15 +04:00
*/
void
2023-09-16 20:12:25 +03:00
xmlHashScanFull ( xmlHashTablePtr hash , xmlHashScannerFull scan , void * data ) {
const xmlHashEntry * entry , * end ;
2023-11-21 16:35:54 +03:00
xmlHashEntry old ;
unsigned i ;
2001-02-23 20:55:21 +03:00
2023-09-16 20:12:25 +03:00
if ( ( hash = = NULL ) | | ( hash - > size = = 0 ) | | ( scan = = NULL ) )
return ;
2023-11-21 16:35:54 +03:00
/*
* We must handle the case that a scanned entry is removed when executing
* the callback ( xmlCleanSpecialAttr and possibly other places ) .
*
* Find the start of a probe sequence to avoid scanning entries twice if
* a deletion happens .
*/
entry = hash - > table ;
2023-09-16 20:12:25 +03:00
end = & hash - > table [ hash - > size ] ;
2023-11-21 16:35:54 +03:00
while ( entry - > hashValue ! = 0 ) {
if ( + + entry > = end )
entry = hash - > table ;
}
2023-09-16 20:12:25 +03:00
2023-11-21 16:35:54 +03:00
for ( i = 0 ; i < hash - > size ; i + + ) {
if ( ( entry - > hashValue ! = 0 ) & & ( entry - > payload ! = NULL ) ) {
/*
* Make sure to rescan after a possible deletion .
*/
do {
old = * entry ;
scan ( entry - > payload , data , entry - > key , entry - > key2 , entry - > key3 ) ;
} while ( ( entry - > hashValue ! = 0 ) & &
( entry - > payload ! = NULL ) & &
( ( entry - > key ! = old . key ) | |
( entry - > key2 ! = old . key2 ) | |
( entry - > key3 ! = old . key3 ) ) ) ;
}
if ( + + entry > = end )
entry = hash - > table ;
2001-02-23 20:55:21 +03:00
}
}
/**
* xmlHashScan3 :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
* @ key : first string key or NULL
* @ key2 : second string key or NULL
* @ key3 : third string key or NULL
* @ scan : scanner function for items in the hash
* @ data : extra data passed to @ scan
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Scan the hash @ table and apply @ scan to each value matching
* ( @ key , @ key2 , @ key3 ) tuple . If one of the keys is null ,
2001-02-23 20:55:21 +03:00
* the comparison is considered to match .
*/
void
2023-09-16 20:12:25 +03:00
xmlHashScan3 ( xmlHashTablePtr hash , const xmlChar * key ,
const xmlChar * key2 , const xmlChar * key3 ,
xmlHashScanner scan , void * data ) {
stubData sdata ;
sdata . data = data ;
sdata . scan = scan ;
xmlHashScanFull3 ( hash , key , key2 , key3 , stubHashScannerFull , & sdata ) ;
2001-07-22 07:54:15 +04:00
}
/**
* xmlHashScanFull3 :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
* @ key : first string key or NULL
* @ key2 : second string key or NULL
* @ key3 : third string key or NULL
* @ scan : scanner function for items in the hash
* @ data : extra data passed to @ scan
2001-07-22 07:54:15 +04:00
*
2023-09-16 20:12:25 +03:00
* Scan the hash @ table and apply @ scan to each value matching
* ( @ key , @ key2 , @ key3 ) tuple . If one of the keys is null ,
2001-07-22 07:54:15 +04:00
* the comparison is considered to match .
*/
void
2023-09-16 20:12:25 +03:00
xmlHashScanFull3 ( xmlHashTablePtr hash , const xmlChar * key ,
const xmlChar * key2 , const xmlChar * key3 ,
xmlHashScannerFull scan , void * data ) {
const xmlHashEntry * entry , * end ;
2023-11-21 16:35:54 +03:00
xmlHashEntry old ;
unsigned i ;
2023-09-16 20:12:25 +03:00
if ( ( hash = = NULL ) | | ( hash - > size = = 0 ) | | ( scan = = NULL ) )
return ;
2023-11-21 16:35:54 +03:00
/*
* We must handle the case that a scanned entry is removed when executing
* the callback ( xmlCleanSpecialAttr and possibly other places ) .
*
* Find the start of a probe sequence to avoid scanning entries twice if
* a deletion happens .
*/
entry = hash - > table ;
2023-09-16 20:12:25 +03:00
end = & hash - > table [ hash - > size ] ;
2023-11-21 16:35:54 +03:00
while ( entry - > hashValue ! = 0 ) {
if ( + + entry > = end )
entry = hash - > table ;
}
2023-09-16 20:12:25 +03:00
2023-11-21 16:35:54 +03:00
for ( i = 0 ; i < hash - > size ; i + + ) {
if ( ( entry - > hashValue ! = 0 ) & & ( entry - > payload ! = NULL ) ) {
/*
* Make sure to rescan after a possible deletion .
*/
do {
if ( ( ( key ! = NULL ) & & ( strcmp ( ( const char * ) key ,
( const char * ) entry - > key ) ! = 0 ) ) | |
( ( key2 ! = NULL ) & & ( ! xmlFastStrEqual ( key2 , entry - > key2 ) ) ) | |
( ( key3 ! = NULL ) & & ( ! xmlFastStrEqual ( key3 , entry - > key3 ) ) ) )
break ;
old = * entry ;
scan ( entry - > payload , data , entry - > key , entry - > key2 , entry - > key3 ) ;
} while ( ( entry - > hashValue ! = 0 ) & &
( entry - > payload ! = NULL ) & &
( ( entry - > key ! = old . key ) | |
( entry - > key2 ! = old . key2 ) | |
( entry - > key3 ! = old . key3 ) ) ) ;
2023-09-16 20:12:25 +03:00
}
2023-11-21 16:35:54 +03:00
if ( + + entry > = end )
entry = hash - > table ;
2001-02-23 20:55:21 +03:00
}
}
2023-12-10 17:14:15 +03:00
/*
* xmlHashCopySafe :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
2023-12-10 17:14:15 +03:00
* @ copyFunc : copier function for items in the hash
* @ deallocFunc : deallocation function in case of errors
2001-02-23 20:55:21 +03:00
*
2023-12-10 17:14:15 +03:00
* Copy the hash table using @ copyFunc to copy payloads .
2001-02-23 20:55:21 +03:00
*
2024-05-20 14:58:22 +03:00
* Available since 2.13 .0 .
*
2023-09-16 20:12:25 +03:00
* Returns the new table or NULL if a memory allocation failed .
2001-02-23 20:55:21 +03:00
*/
xmlHashTablePtr
2023-12-10 17:14:15 +03:00
xmlHashCopySafe ( xmlHashTablePtr hash , xmlHashCopier copyFunc ,
xmlHashDeallocator deallocFunc ) {
2023-09-16 20:12:25 +03:00
const xmlHashEntry * entry , * end ;
2001-02-23 20:55:21 +03:00
xmlHashTablePtr ret ;
2023-12-10 17:14:15 +03:00
if ( ( hash = = NULL ) | | ( copyFunc = = NULL ) )
2023-09-16 20:12:25 +03:00
return ( NULL ) ;
2001-02-23 20:55:21 +03:00
2023-09-16 20:12:25 +03:00
ret = xmlHashCreate ( hash - > size ) ;
2014-07-14 13:50:27 +04:00
if ( ret = = NULL )
return ( NULL ) ;
2023-09-16 20:12:25 +03:00
if ( hash - > size = = 0 )
return ( ret ) ;
end = & hash - > table [ hash - > size ] ;
for ( entry = hash - > table ; entry < end ; entry + + ) {
2023-12-10 17:14:15 +03:00
if ( entry - > hashValue ! = 0 ) {
void * copy ;
copy = copyFunc ( entry - > payload , entry - > key ) ;
if ( copy = = NULL )
goto error ;
if ( xmlHashAdd3 ( ret , entry - > key , entry - > key2 , entry - > key3 ,
copy ) < = 0 ) {
if ( deallocFunc ! = NULL )
deallocFunc ( copy , entry - > key ) ;
goto error ;
}
}
2001-02-23 20:55:21 +03:00
}
2023-09-16 20:12:25 +03:00
2001-02-23 20:55:21 +03:00
return ( ret ) ;
2023-12-10 17:14:15 +03:00
error :
xmlHashFree ( ret , deallocFunc ) ;
return ( NULL ) ;
}
/*
* xmlHashCopy :
* @ hash : hash table
* @ copy : copier function for items in the hash
*
* DEPRECATED : Leaks memory in error case .
*
* Copy the hash table using @ copy to copy payloads .
*
* Returns the new table or NULL if a memory allocation failed .
*/
xmlHashTablePtr
xmlHashCopy ( xmlHashTablePtr hash , xmlHashCopier copy ) {
return ( xmlHashCopySafe ( hash , copy , NULL ) ) ;
2001-02-23 20:55:21 +03:00
}
/**
* xmlHashSize :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Query the number of elements in the hash table .
2001-07-18 23:30:27 +04:00
*
2001-02-23 20:55:21 +03:00
* Returns the number of elements in the hash table or
2023-09-16 20:12:25 +03:00
* - 1 in case of error .
2001-02-23 20:55:21 +03:00
*/
int
2023-09-16 20:12:25 +03:00
xmlHashSize ( xmlHashTablePtr hash ) {
if ( hash = = NULL )
return ( - 1 ) ;
return ( hash - > nbElems ) ;
2001-02-23 20:55:21 +03:00
}
/**
2001-05-19 17:24:56 +04:00
* xmlHashRemoveEntry :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
* @ key : string key
* @ dealloc : deallocator function for removed item or NULL
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Find the entry specified by the @ key and remove it from the hash table .
* Payload will be freed with @ dealloc .
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Returns 0 on success and - 1 if no entry was found .
2001-02-23 20:55:21 +03:00
*/
2023-09-16 20:12:25 +03:00
int xmlHashRemoveEntry ( xmlHashTablePtr hash , const xmlChar * key ,
xmlHashDeallocator dealloc ) {
return ( xmlHashRemoveEntry3 ( hash , key , NULL , NULL , dealloc ) ) ;
2001-02-23 20:55:21 +03:00
}
/**
2001-05-19 17:24:56 +04:00
* xmlHashRemoveEntry2 :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
* @ key : first string key
* @ key2 : second string key
* @ dealloc : deallocator function for removed item or NULL
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Remove an entry with two strings as key .
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* See xmlHashRemoveEntry .
2023-11-04 21:04:23 +03:00
*
* Returns 0 on success and - 1 in case of error .
2001-02-23 20:55:21 +03:00
*/
2002-12-10 18:19:08 +03:00
int
2023-09-16 20:12:25 +03:00
xmlHashRemoveEntry2 ( xmlHashTablePtr hash , const xmlChar * key ,
const xmlChar * key2 , xmlHashDeallocator dealloc ) {
return ( xmlHashRemoveEntry3 ( hash , key , key2 , NULL , dealloc ) ) ;
2001-02-23 20:55:21 +03:00
}
/**
2002-12-10 18:19:08 +03:00
* xmlHashRemoveEntry3 :
2023-09-16 20:12:25 +03:00
* @ hash : hash table
* @ key : first string key
* @ key2 : second string key
* @ key3 : third string key
* @ dealloc : deallocator function for removed item or NULL
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* Remove an entry with three strings as key .
2001-02-23 20:55:21 +03:00
*
2023-09-16 20:12:25 +03:00
* See xmlHashRemoveEntry .
2023-11-04 21:04:23 +03:00
*
* Returns 0 on success and - 1 in case of error .
2001-02-23 20:55:21 +03:00
*/
2023-09-16 20:12:25 +03:00
ATTRIBUTE_NO_SANITIZE_INTEGER
2002-12-10 18:19:08 +03:00
int
2023-09-16 20:12:25 +03:00
xmlHashRemoveEntry3 ( xmlHashTablePtr hash , const xmlChar * key ,
const xmlChar * key2 , const xmlChar * key3 ,
xmlHashDeallocator dealloc ) {
xmlHashEntry * entry , * cur , * next ;
unsigned hashValue , mask , pos , nextpos ;
int found ;
if ( ( hash = = NULL ) | | ( hash - > size = = 0 ) | | ( key = = NULL ) )
2001-04-18 17:09:01 +04:00
return ( - 1 ) ;
2001-02-23 20:55:21 +03:00
2023-09-16 20:12:25 +03:00
hashValue = xmlHashValue ( hash - > randomSeed , key , key2 , key3 , NULL ) ;
entry = xmlHashFindEntry ( hash , key , key2 , key3 , hashValue , & found ) ;
if ( ! found )
2001-04-18 17:09:01 +04:00
return ( - 1 ) ;
2023-09-16 20:12:25 +03:00
if ( ( dealloc ! = NULL ) & & ( entry - > payload ! = NULL ) )
dealloc ( entry - > payload , entry - > key ) ;
if ( hash - > dict = = NULL ) {
if ( entry - > key )
xmlFree ( entry - > key ) ;
if ( entry - > key2 )
xmlFree ( entry - > key2 ) ;
if ( entry - > key3 )
xmlFree ( entry - > key3 ) ;
}
/*
* Find end of probe sequence . Entries at their initial probe
* position start a new sequence .
*/
mask = hash - > size - 1 ;
pos = entry - hash - > table ;
cur = entry ;
while ( 1 ) {
nextpos = pos + 1 ;
next = cur + 1 ;
if ( ( nextpos & mask ) = = 0 )
next = hash - > table ;
if ( ( next - > hashValue = = 0 ) | |
( ( ( next - > hashValue - nextpos ) & mask ) = = 0 ) )
break ;
cur = next ;
pos = nextpos ;
}
/*
* Backward shift
*/
next = entry + 1 ;
if ( cur < entry ) {
xmlHashEntry * end = & hash - > table [ hash - > size ] ;
memmove ( entry , next , ( char * ) end - ( char * ) next ) ;
entry = hash - > table ;
end [ - 1 ] = * entry ;
next = entry + 1 ;
2001-04-18 17:09:01 +04:00
}
2023-09-16 20:12:25 +03:00
memmove ( entry , next , ( char * ) cur - ( char * ) entry ) ;
/*
* Update entry
*/
cur - > hashValue = 0 ;
hash - > nbElems - - ;
return ( 0 ) ;
2001-03-19 02:17:47 +03:00
}