| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #define IN_LIBXML |
| | #include "libxml.h" |
| |
|
| | #include <string.h> |
| | #include <limits.h> |
| |
|
| | #include <libxml/parser.h> |
| | #include <libxml/hash.h> |
| | #include <libxml/dict.h> |
| | #include <libxml/xmlmemory.h> |
| | #include <libxml/xmlstring.h> |
| |
|
| | #include "private/dict.h" |
| |
|
| | #ifndef SIZE_MAX |
| | #define SIZE_MAX ((size_t) -1) |
| | #endif |
| |
|
| | #define MAX_FILL_NUM 7 |
| | #define MAX_FILL_DENOM 8 |
| | #define MIN_HASH_SIZE 8 |
| | #define MAX_HASH_SIZE (1u << 31) |
| |
|
| | |
| | |
| | |
| | typedef struct { |
| | unsigned hashValue; |
| | |
| | xmlChar *key; |
| | xmlChar *key2; |
| | xmlChar *key3; |
| | void *payload; |
| | } xmlHashEntry; |
| |
|
| | |
| | |
| | |
| | struct _xmlHashTable { |
| | xmlHashEntry *table; |
| | unsigned size; |
| | unsigned nbElems; |
| | xmlDictPtr dict; |
| | unsigned randomSeed; |
| | }; |
| |
|
| | static int |
| | xmlHashGrow(xmlHashTablePtr hash, unsigned size); |
| |
|
| | ATTRIBUTE_NO_SANITIZE_INTEGER |
| | static unsigned |
| | xmlHashValue(unsigned seed, const xmlChar *key, const xmlChar *key2, |
| | const xmlChar *key3, size_t *lengths) { |
| | unsigned h1, h2; |
| | size_t i; |
| |
|
| | HASH_INIT(h1, h2, seed); |
| |
|
| | for (i = 0; key[i] != 0; i++) { |
| | HASH_UPDATE(h1, h2, key[i]); |
| | } |
| | if (lengths) |
| | lengths[0] = i; |
| |
|
| | HASH_UPDATE(h1, h2, 0); |
| |
|
| | if (key2 != NULL) { |
| | for (i = 0; key2[i] != 0; i++) { |
| | HASH_UPDATE(h1, h2, key2[i]); |
| | } |
| | if (lengths) |
| | lengths[1] = i; |
| | } |
| |
|
| | HASH_UPDATE(h1, h2, 0); |
| |
|
| | if (key3 != NULL) { |
| | for (i = 0; key3[i] != 0; i++) { |
| | HASH_UPDATE(h1, h2, key3[i]); |
| | } |
| | if (lengths) |
| | lengths[2] = i; |
| | } |
| |
|
| | HASH_FINISH(h1, h2); |
| |
|
| | return(h2); |
| | } |
| |
|
| | ATTRIBUTE_NO_SANITIZE_INTEGER |
| | static unsigned |
| | xmlHashQNameValue(unsigned seed, |
| | const xmlChar *prefix, const xmlChar *name, |
| | const xmlChar *prefix2, const xmlChar *name2, |
| | const xmlChar *prefix3, const xmlChar *name3) { |
| | unsigned h1, h2, ch; |
| |
|
| | HASH_INIT(h1, h2, seed); |
| |
|
| | if (prefix != NULL) { |
| | while ((ch = *prefix++) != 0) { |
| | HASH_UPDATE(h1, h2, ch); |
| | } |
| | HASH_UPDATE(h1, h2, ':'); |
| | } |
| | if (name != NULL) { |
| | while ((ch = *name++) != 0) { |
| | HASH_UPDATE(h1, h2, ch); |
| | } |
| | } |
| | HASH_UPDATE(h1, h2, 0); |
| | if (prefix2 != NULL) { |
| | while ((ch = *prefix2++) != 0) { |
| | HASH_UPDATE(h1, h2, ch); |
| | } |
| | HASH_UPDATE(h1, h2, ':'); |
| | } |
| | if (name2 != NULL) { |
| | while ((ch = *name2++) != 0) { |
| | HASH_UPDATE(h1, h2, ch); |
| | } |
| | } |
| | HASH_UPDATE(h1, h2, 0); |
| | if (prefix3 != NULL) { |
| | while ((ch = *prefix3++) != 0) { |
| | HASH_UPDATE(h1, h2, ch); |
| | } |
| | HASH_UPDATE(h1, h2, ':'); |
| | } |
| | if (name3 != NULL) { |
| | while ((ch = *name3++) != 0) { |
| | HASH_UPDATE(h1, h2, ch); |
| | } |
| | } |
| |
|
| | HASH_FINISH(h1, h2); |
| |
|
| | return(h2); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | xmlHashTable * |
| | xmlHashCreate(int size) { |
| | xmlHashTablePtr hash; |
| |
|
| | xmlInitParser(); |
| |
|
| | 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; |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | 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); |
| | } |
| | } |
| |
|
| | return(hash); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | xmlHashTable * |
| | xmlHashCreateDict(int size, xmlDict *dict) { |
| | xmlHashTablePtr hash; |
| |
|
| | hash = xmlHashCreate(size); |
| | if (hash != NULL) { |
| | hash->dict = dict; |
| | xmlDictReference(dict); |
| | } |
| | return(hash); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void |
| | xmlHashFree(xmlHashTable *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); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | 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)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | 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) { |
| | |
| | |
| | |
| | |
| | |
| | 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); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static int |
| | xmlHashGrow(xmlHashTablePtr hash, unsigned size) { |
| | const xmlHashEntry *oldentry, *oldend, *end; |
| | xmlHashEntry *table; |
| | unsigned oldsize, i; |
| |
|
| | |
| | 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 = hash->size; |
| | if (oldsize == 0) |
| | goto done; |
| |
|
| | oldend = &hash->table[oldsize]; |
| | end = &table[size]; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | oldentry = hash->table; |
| | while (oldentry->hashValue != 0) { |
| | if (++oldentry >= oldend) |
| | oldentry = hash->table; |
| | } |
| |
|
| | for (i = 0; i < oldsize; i++) { |
| | if (oldentry->hashValue != 0) { |
| | xmlHashEntry *entry = &table[oldentry->hashValue & (size - 1)]; |
| |
|
| | while (entry->hashValue != 0) { |
| | if (++entry >= end) |
| | entry = table; |
| | } |
| | *entry = *oldentry; |
| | } |
| |
|
| | if (++oldentry >= oldend) |
| | oldentry = hash->table; |
| | } |
| |
|
| | xmlFree(hash->table); |
| |
|
| | done: |
| | hash->table = table; |
| | hash->size = size; |
| |
|
| | return(0); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | ATTRIBUTE_NO_SANITIZE_INTEGER |
| | static int |
| | xmlHashUpdateInternal(xmlHashTable *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] = {0, 0, 0}; |
| | unsigned hashValue, newSize; |
| |
|
| | if ((hash == NULL) || (key == NULL)) |
| | return(-1); |
| |
|
| | hashValue = xmlHashValue(hash->randomSeed, key, key2, key3, lengths); |
| |
|
| | |
| | |
| | |
| | if (hash->size == 0) { |
| | newSize = MIN_HASH_SIZE; |
| | } else { |
| | int found = 0; |
| |
|
| | entry = xmlHashFindEntry(hash, key, key2, key3, hashValue, &found); |
| |
|
| | if (found) { |
| | if (update) { |
| | if (dealloc) |
| | dealloc(entry->payload, entry->key); |
| | entry->payload = payload; |
| | } |
| |
|
| | return(0); |
| | } |
| |
|
| | if (hash->nbElems + 1 > hash->size / MAX_FILL_DENOM * MAX_FILL_NUM) { |
| | |
| | if (hash->size >= MAX_HASH_SIZE) |
| | return(-1); |
| | newSize = hash->size * 2; |
| | } else { |
| | newSize = 0; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | if (newSize > 0) { |
| | unsigned mask, displ, pos; |
| |
|
| | if (xmlHashGrow(hash, newSize) != 0) |
| | return(-1); |
| |
|
| | |
| | |
| | |
| | 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); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | 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; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | 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) { |
| | |
| | |
| | |
| | |
| | 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); |
| | } |
| |
|
| | |
| | |
| | |
| | entry->key = copy; |
| | entry->key2 = copy2; |
| | entry->key3 = copy3; |
| | entry->payload = payload; |
| | |
| | entry->hashValue = hashValue | MAX_HASH_SIZE; |
| |
|
| | hash->nbElems++; |
| |
|
| | return(1); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | void |
| | xmlHashDefaultDeallocator(void *entry, const xmlChar *key ATTRIBUTE_UNUSED) { |
| | xmlFree(entry); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int |
| | xmlHashAdd(xmlHashTable *hash, const xmlChar *key, void *payload) { |
| | return(xmlHashUpdateInternal(hash, key, NULL, NULL, payload, NULL, 0)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int |
| | xmlHashAdd2(xmlHashTable *hash, const xmlChar *key, |
| | const xmlChar *key2, void *payload) { |
| | return(xmlHashUpdateInternal(hash, key, key2, NULL, payload, NULL, 0)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int |
| | xmlHashAdd3(xmlHashTable *hash, const xmlChar *key, |
| | const xmlChar *key2, const xmlChar *key3, |
| | void *payload) { |
| | return(xmlHashUpdateInternal(hash, key, key2, key3, payload, NULL, 0)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int |
| | xmlHashAddEntry(xmlHashTable *hash, const xmlChar *key, void *payload) { |
| | int res = xmlHashUpdateInternal(hash, key, NULL, NULL, payload, NULL, 0); |
| |
|
| | if (res == 0) |
| | res = -1; |
| | else if (res == 1) |
| | res = 0; |
| |
|
| | return(res); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int |
| | xmlHashAddEntry2(xmlHashTable *hash, const xmlChar *key, |
| | const xmlChar *key2, void *payload) { |
| | int res = xmlHashUpdateInternal(hash, key, key2, NULL, payload, NULL, 0); |
| |
|
| | if (res == 0) |
| | res = -1; |
| | else if (res == 1) |
| | res = 0; |
| |
|
| | return(res); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int |
| | xmlHashAddEntry3(xmlHashTable *hash, const xmlChar *key, |
| | const xmlChar *key2, const xmlChar *key3, |
| | void *payload) { |
| | int res = xmlHashUpdateInternal(hash, key, key2, key3, payload, NULL, 0); |
| |
|
| | if (res == 0) |
| | res = -1; |
| | else if (res == 1) |
| | res = 0; |
| |
|
| | return(res); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int |
| | xmlHashUpdateEntry(xmlHashTable *hash, const xmlChar *key, |
| | void *payload, xmlHashDeallocator dealloc) { |
| | int res = xmlHashUpdateInternal(hash, key, NULL, NULL, payload, |
| | dealloc, 1); |
| |
|
| | if (res == 1) |
| | res = 0; |
| |
|
| | return(res); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int |
| | xmlHashUpdateEntry2(xmlHashTable *hash, const xmlChar *key, |
| | const xmlChar *key2, void *payload, |
| | xmlHashDeallocator dealloc) { |
| | int res = xmlHashUpdateInternal(hash, key, key2, NULL, payload, |
| | dealloc, 1); |
| |
|
| | if (res == 1) |
| | res = 0; |
| |
|
| | return(res); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int |
| | xmlHashUpdateEntry3(xmlHashTable *hash, const xmlChar *key, |
| | const xmlChar *key2, const xmlChar *key3, |
| | void *payload, xmlHashDeallocator dealloc) { |
| | int res = xmlHashUpdateInternal(hash, key, key2, key3, payload, |
| | dealloc, 1); |
| |
|
| | if (res == 1) |
| | res = 0; |
| |
|
| | return(res); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void * |
| | xmlHashLookup(xmlHashTable *hash, const xmlChar *key) { |
| | return(xmlHashLookup3(hash, key, NULL, NULL)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void * |
| | xmlHashLookup2(xmlHashTable *hash, const xmlChar *key, |
| | const xmlChar *key2) { |
| | return(xmlHashLookup3(hash, key, key2, NULL)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void * |
| | xmlHashQLookup(xmlHashTable *hash, const xmlChar *prefix, |
| | const xmlChar *name) { |
| | return(xmlHashQLookup3(hash, prefix, name, NULL, NULL, NULL, NULL)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void * |
| | xmlHashQLookup2(xmlHashTable *hash, const xmlChar *prefix, |
| | const xmlChar *name, const xmlChar *prefix2, |
| | const xmlChar *name2) { |
| | return(xmlHashQLookup3(hash, prefix, name, prefix2, name2, NULL, NULL)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void * |
| | xmlHashLookup3(xmlHashTable *hash, const xmlChar *key, |
| | const xmlChar *key2, const xmlChar *key3) { |
| | const xmlHashEntry *entry; |
| | unsigned hashValue; |
| | int found; |
| |
|
| | 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); |
| | return(NULL); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | ATTRIBUTE_NO_SANITIZE_INTEGER |
| | void * |
| | xmlHashQLookup3(xmlHashTable *hash, |
| | const xmlChar *prefix, const xmlChar *name, |
| | const xmlChar *prefix2, const xmlChar *name2, |
| | const xmlChar *prefix3, const xmlChar *name3) { |
| | const xmlHashEntry *entry; |
| | unsigned hashValue, mask, pos, displ; |
| |
|
| | 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)); |
| | } |
| |
|
| | return(NULL); |
| | } |
| |
|
| | typedef struct { |
| | xmlHashScanner scan; |
| | void *data; |
| | } stubData; |
| |
|
| | static void |
| | 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); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void |
| | xmlHashScan(xmlHashTable *hash, xmlHashScanner scan, void *data) { |
| | stubData sdata; |
| | sdata.data = data; |
| | sdata.scan = scan; |
| | xmlHashScanFull(hash, stubHashScannerFull, &sdata); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void |
| | xmlHashScanFull(xmlHashTable *hash, xmlHashScannerFull scan, void *data) { |
| | const xmlHashEntry *entry, *end; |
| | xmlHashEntry old; |
| | unsigned i; |
| |
|
| | if ((hash == NULL) || (hash->size == 0) || (scan == NULL)) |
| | return; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | entry = hash->table; |
| | end = &hash->table[hash->size]; |
| | while (entry->hashValue != 0) { |
| | if (++entry >= end) |
| | entry = hash->table; |
| | } |
| |
|
| | for (i = 0; i < hash->size; i++) { |
| | if ((entry->hashValue != 0) && (entry->payload != NULL)) { |
| | |
| | |
| | |
| | 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; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void |
| | xmlHashScan3(xmlHashTable *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); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void |
| | xmlHashScanFull3(xmlHashTable *hash, const xmlChar *key, |
| | const xmlChar *key2, const xmlChar *key3, |
| | xmlHashScannerFull scan, void *data) { |
| | const xmlHashEntry *entry, *end; |
| | xmlHashEntry old; |
| | unsigned i; |
| |
|
| | if ((hash == NULL) || (hash->size == 0) || (scan == NULL)) |
| | return; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | entry = hash->table; |
| | end = &hash->table[hash->size]; |
| | while (entry->hashValue != 0) { |
| | if (++entry >= end) |
| | entry = hash->table; |
| | } |
| |
|
| | for (i = 0; i < hash->size; i++) { |
| | if ((entry->hashValue != 0) && (entry->payload != NULL)) { |
| | |
| | |
| | |
| | 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))); |
| | } |
| | if (++entry >= end) |
| | entry = hash->table; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | xmlHashTable * |
| | xmlHashCopySafe(xmlHashTable *hash, xmlHashCopier copyFunc, |
| | xmlHashDeallocator deallocFunc) { |
| | const xmlHashEntry *entry, *end; |
| | xmlHashTablePtr ret; |
| |
|
| | if ((hash == NULL) || (copyFunc == NULL)) |
| | return(NULL); |
| |
|
| | ret = xmlHashCreate(hash->size); |
| | if (ret == NULL) |
| | return(NULL); |
| |
|
| | if (hash->size == 0) |
| | return(ret); |
| |
|
| | end = &hash->table[hash->size]; |
| |
|
| | for (entry = hash->table; entry < end; entry++) { |
| | 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; |
| | } |
| | } |
| | } |
| |
|
| | return(ret); |
| |
|
| | error: |
| | xmlHashFree(ret, deallocFunc); |
| | return(NULL); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | xmlHashTable * |
| | xmlHashCopy(xmlHashTable *hash, xmlHashCopier copy) { |
| | return(xmlHashCopySafe(hash, copy, NULL)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int |
| | xmlHashSize(xmlHashTable *hash) { |
| | if (hash == NULL) |
| | return(-1); |
| | return(hash->nbElems); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int xmlHashRemoveEntry(xmlHashTable *hash, const xmlChar *key, |
| | xmlHashDeallocator dealloc) { |
| | return(xmlHashRemoveEntry3(hash, key, NULL, NULL, dealloc)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int |
| | xmlHashRemoveEntry2(xmlHashTable *hash, const xmlChar *key, |
| | const xmlChar *key2, xmlHashDeallocator dealloc) { |
| | return(xmlHashRemoveEntry3(hash, key, key2, NULL, dealloc)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | ATTRIBUTE_NO_SANITIZE_INTEGER |
| | int |
| | xmlHashRemoveEntry3(xmlHashTable *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)) |
| | return(-1); |
| |
|
| | hashValue = xmlHashValue(hash->randomSeed, key, key2, key3, NULL); |
| | entry = xmlHashFindEntry(hash, key, key2, key3, hashValue, &found); |
| | if (!found) |
| | return(-1); |
| |
|
| | 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); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | 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; |
| | } |
| |
|
| | |
| | |
| | |
| | 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; |
| | } |
| |
|
| | memmove(entry, next, (char *) cur - (char *) entry); |
| |
|
| | |
| | |
| | |
| | cur->hashValue = 0; |
| |
|
| | hash->nbElems--; |
| |
|
| | return(0); |
| | } |
| |
|
| |
|