diff -r 000000000000 -r e35f40988205 xml/libxml2libs/src/libxml2/libxml2_hash.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xml/libxml2libs/src/libxml2/libxml2_hash.c Thu Dec 17 09:29:21 2009 +0200 @@ -0,0 +1,1025 @@ +/* + * libxml2_hash.c: chained hash tables + * + * Reference: Your favorite introductory book on algorithms + * + * Copyright (C) 2000 Bjorn Reese and Daniel Veillard. + * + * 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 + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + * Author: breese@users.sourceforge.net + * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. + */ + +#define IN_LIBXML +#include "xmlenglibxml.h" + +#include +#include + +#define MAX_HASH_LEN 8 + +/* #define DEBUG_GROW */ + +/* + * A single entry in the hash table + */ +typedef struct _xmlHashEntry xmlHashEntry; +typedef xmlHashEntry* xmlHashEntryPtr; +struct _xmlHashEntry { + struct _xmlHashEntry *next; + xmlChar *name; + xmlChar *name2; + xmlChar *name3; + void *payload; + int valid; +}; + +/* + * The entire hash table + */ +struct _xmlHashTable { + xmlHashEntryPtr table; + int size; + int nbElems; +}; + +/* + * xmlHashComputeKey: + * Calculate the hash key + * + * OOM: never + */ +static unsigned long +xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3) { + unsigned long value = 0L; + char ch; + + if (name != NULL) { + value += 30 * (*name); + while ((ch = *name++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + if (name2 != NULL) { + while ((ch = *name2++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + if (name3 != NULL) { + while ((ch = *name3++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + return (value % table->size); +} + +static unsigned long +xmlHashComputeQKey(xmlHashTablePtr table, + const xmlChar *prefix, const xmlChar *name, + const xmlChar *prefix2, const xmlChar *name2, + const xmlChar *prefix3, const xmlChar *name3) { + unsigned long value = 0L; + char ch; + + if (prefix != NULL) + value += 30 * (*prefix); + else + value += 30 * (*name); + + if (prefix != NULL) { + while ((ch = *prefix++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); + } + if (name != NULL) { + while ((ch = *name++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + if (prefix2 != NULL) { + while ((ch = *prefix2++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); + } + if (name2 != NULL) { + while ((ch = *name2++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + if (prefix3 != NULL) { + while ((ch = *prefix3++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); + } + if (name3 != NULL) { + while ((ch = *name3++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + return (value % table->size); +} + +/** + * xmlHashCreate: + * @param size the size of the hash table + * + * Create a new xmlHashTablePtr. + * + * Returns the newly created object, or NULL if an error occured. + * + * OOM: possible --> returns NULL, OOM flag is set + */ +XMLPUBFUNEXPORT xmlHashTablePtr +xmlHashCreate(int size) { + xmlHashTablePtr table; + + if (size <= 0) + size = 256; + + table = (xmlHashTablePtr) xmlMalloc(sizeof(xmlHashTable)); + if (table) { + table->size = size; + table->nbElems = 0; + table->table = (xmlHashEntryPtr)xmlMalloc(size * sizeof(xmlHashEntry)); // may set OOM flag + if (table->table) { + memset(table->table, 0, size * sizeof(xmlHashEntry)); + return(table); + } + xmlFree(table); + } + return(NULL); +} + +/** + * xmlHashGrow: + * @param table the hash table + * @param size the new size of the hash table + * + * resize the hash table + * + * Returns 0 in case of success, -1 in case of failure + * + * OOM: possible --> sets OOM flag when returns -1 + */ +static int +xmlHashGrow(xmlHashTablePtr table, int size) { + unsigned long key; + int oldsize, i; + xmlHashEntryPtr iter, next; + struct _xmlHashEntry *oldtable; +#ifdef DEBUG_GROW + unsigned long nbElem = 0; +#endif + + if (table == NULL) + return(-1); + if (size < 8) + return(-1); + if (size > 8 * 2048) + return(-1); + + oldsize = table->size; + oldtable = table->table; + if (oldtable == NULL) + return(-1); + + table->table = (xmlHashEntryPtr)xmlMalloc(size * sizeof(xmlHashEntry)); // may set OOM flag + if (table->table == NULL) { + table->table = oldtable; + return(-1); + } + memset(table->table, 0, size * sizeof(xmlHashEntry)); + table->size = size; + + /* If the two loops are merged, there would be situations where + a new entry needs to allocated and data copied into it from + the main table. So instead, we run through the array twice, first + copying all the elements in the main array (where we can't get + conflicts) and then the rest, so we only free (and don't allocate) + */ + for (i = 0; i < oldsize; i++) { + + if (oldtable[i].valid == 0) + continue; + key = xmlHashComputeKey( + table, + oldtable[i].name, + oldtable[i].name2, + oldtable[i].name3); + memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry)); + table->table[key].next = NULL; + } + + for (i = 0; i < oldsize; i++) { + iter = oldtable[i].next; + while (iter) { + next = iter->next; + + /* + * put back the entry in the new table + */ + + key = xmlHashComputeKey( + table, + iter->name, + iter->name2, + iter->name3); + if (table->table[key].valid == 0) { + memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry)); + table->table[key].next = NULL; + xmlFree(iter); + } else { + iter->next = table->table[key].next; + table->table[key].next = iter; + } + +#ifdef DEBUG_GROW + nbElem++; +#endif + iter = next; + } + } + + xmlFree(oldtable); + +#ifdef DEBUG_GROW + xmlGenericError(xmlGenericErrorContext, + "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem); +#endif + return(0); +} + +/** + * xmlHashFree: + * @param table the hash table + * @param f the deallocator function for items in the hash + * + * Free the hash table and its contents. The userdata is + * deallocated with f if provided. + * + * OOM: never // same as argument 'f' has when f!=NULL + */ +XMLPUBFUNEXPORT void +xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) { + int i; + xmlHashEntryPtr iter; + xmlHashEntryPtr next; + int inside_table = 0; + int nbElems; + + if (table == NULL) + return; + if (table->table) { + nbElems = table->nbElems; + for(i = 0; (i < table->size) && (nbElems > 0); i++) { + iter = &(table->table[i]); + if (iter->valid == 0) + continue; + inside_table = 1; + while (iter) { + next = iter->next; + if ((f != NULL) && (iter->payload != NULL)) + f(iter->payload, iter->name); + if (iter->name) + xmlFree(iter->name); + if (iter->name2) + xmlFree(iter->name2); + if (iter->name3) + xmlFree(iter->name3); + iter->payload = NULL; + if (!inside_table) + xmlFree(iter); + nbElems--; + inside_table = 0; + iter = next; + } + inside_table = 0; + } + xmlFree(table->table); + } + xmlFree(table); +} + +/** + * xmlHashAddEntry: + * @param table the hash table + * @param name the name of the userdata + * @param userdata a pointer to the userdata + * + * Add the userdata to the hash table. This can later be retrieved + * by using the name. Duplicate names generate errors. + * + * Returns 0 the addition succeeded and -1 in case of error. + * + * OOM: iif returns -1 and flag is set + */ +XMLPUBFUNEXPORT int +xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) { + return(xmlHashAddEntry3(table, name, NULL, NULL, userdata)); +} + +/** + * xmlHashAddEntry2: + * @param table the hash table + * @param name the name of the userdata + * @param name2 a second name of the userdata + * @param userdata a pointer to the userdata + * + * Add the userdata to the hash table. This can later be retrieved + * by using the (name, name2) tuple. Duplicate tuples generate errors. + * + * Returns 0 the addition succeeded and -1 in case of error. + */ +XMLPUBFUNEXPORT int +xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, void *userdata) { + return(xmlHashAddEntry3(table, name, name2, NULL, userdata)); +} + +/** + * xmlHashUpdateEntry: + * @param table the hash table + * @param name the name of the userdata + * @param userdata a pointer to the userdata + * @param f the deallocator function for replaced item (if any) + * + * Add the userdata to the hash table. This can later be retrieved + * by using the name. Existing entry for this name will be removed + * and freed with f if found. + * + * Returns 0 the addition succeeded and -1 in case of error. + */ +XMLPUBFUNEXPORT int +xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name, + void *userdata, xmlHashDeallocator f) { + return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f)); +} + +/** + * xmlHashUpdateEntry2: + * @param table the hash table + * @param name the name of the userdata + * @param name2 a second name of the userdata + * @param userdata a pointer to the userdata + * @param f the deallocator function for replaced item (if any) + * + * Add the userdata to the hash table. This can later be retrieved + * by using the (name, name2) tuple. Existing entry for this tuple will + * be removed and freed with f if found. + * + * Returns 0 the addition succeeded and -1 in case of error. + */ +XMLPUBFUNEXPORT int +xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, void *userdata, + xmlHashDeallocator f) { + return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f)); +} + +/** + * xmlHashLookup: + * @param table the hash table + * @param name the name of the userdata + * + * Find the userdata specified by the name. + * + * Returns the pointer to the userdata + */ +XMLPUBFUNEXPORT void * +xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) { + return(xmlHashLookup3(table, name, NULL, NULL)); +} + +/** + * xmlHashLookup2: + * @param table the hash table + * @param name the name of the userdata + * @param name2 a second name of the userdata + * + * Find the userdata specified by the (name, name2) tuple. + * + * Returns the pointer to the userdata + * + * OOM: never + */ +XMLPUBFUNEXPORT void* +xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2) { + return(xmlHashLookup3(table, name, name2, NULL)); +} + +#ifndef XMLENGINE_EXCLUDE_UNUSED +/** + * xmlHashQLookup: + * @param table the hash table + * @param prefix the prefix of the userdata + * @param name the name of the userdata + * + * Find the userdata specified by the QName prefix:name/name. + * + * Returns the pointer to the userdata + * + * OOM: never + */ +void* +xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix, + const xmlChar *name) { + return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL)); +} +#endif /* ifndef XMLENGINE_EXCLUDE_UNUSED */ + +/** + * xmlHashQLookup2: + * @param table the hash table + * @param prefix the prefix of the userdata + * @param name the name of the userdata + * @param prefix2 the second prefix of the userdata + * @param name2 a second name of the userdata + * + * Find the userdata specified by the QNames tuple + * + * Returns the pointer to the userdata + */ +XMLPUBFUNEXPORT void * +xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix, + const xmlChar *name, const xmlChar *prefix2, + const xmlChar *name2) { + return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL)); +} + +/** + * xmlHashAddEntry3: + * @param table the hash table + * @param name the name of the userdata + * @param name2 a second name of the userdata + * @param name3 a third name of the userdata + * @param userdata a pointer to the userdata + * + * Add the userdata to the hash table. This can later be retrieved + * by using the tuple (name, name2, name3). Duplicate entries generate + * errors. + * + * Returns 0 the addition succeeded and -1 in case of error. + * + * OOM: iif returns -1 and flag is set + */ +XMLPUBFUNEXPORT int +xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3, + void *userdata) { + LOAD_GS_DIRECT + unsigned long key, len = 0; + xmlHashEntryPtr entry; + xmlHashEntryPtr insert; + int res; + + if ((table == NULL) || name == NULL) + return(-1); + + /* + * Check for duplicate and insertion location. + */ + key = xmlHashComputeKey(table, name, name2, name3); + if (table->table[key].valid == 0) { + insert = NULL; + } else { + for (insert = &(table->table[key]); insert->next != NULL; + insert = insert->next) { + if ((xmlStrEqual(insert->name, name)) && + (xmlStrEqual(insert->name2, name2)) && + (xmlStrEqual(insert->name3, name3))) + return(-1); + len++; + } + if ((xmlStrEqual(insert->name, name)) && + (xmlStrEqual(insert->name2, name2)) && + (xmlStrEqual(insert->name3, name3))) + return(-1); + } + + if (insert == NULL) { + entry = &(table->table[key]); + } else { + entry = (xmlHashEntryPtr) xmlMalloc(sizeof(xmlHashEntry)); // may set OOM flag + if (entry == NULL) + return(-1); + } + // DONE: Check OOM // DONE: Try to avoid xmlStrdup(NULL) + + + entry->name = xmlStrdup(name); // name is never NULL here + entry->name2 = name2 ? xmlStrdup(name2): (xmlChar*) name2 /* it's NULL here */; + entry->name3 = name3 ? xmlStrdup(name3): (xmlChar*) name3 /* it's NULL here */; + if(OOM_FLAG){ + if(entry->name) xmlFree(entry->name); + if(entry->name2) xmlFree(entry->name2); + if(entry->name3) xmlFree(entry->name3); + if(insert) xmlFree(entry); + return -1; + } + entry->payload = userdata; + entry->next = NULL; + entry->valid = 1; + + if (insert != NULL) + insert->next = entry; + + table->nbElems++; + + res = 0; + if (len > MAX_HASH_LEN){ + res = xmlHashGrow(table, MAX_HASH_LEN * table->size); + } + + return(res); +} + +/** + * xmlHashUpdateEntry3: + * @param table the hash table + * @param name the name of the userdata + * @param name2 a second name of the userdata + * @param name3 a third name of the userdata + * @param userdata a pointer to the userdata + * @param f the deallocator function for replaced item (if any) + * + * Add the userdata to the hash table. This can later be retrieved + * by using the tuple (name, name2, name3). Existing entry for this tuple + * will be removed and freed with f if found. + * + * Returns 0 the addition succeeded and -1 in case of error. + */ +XMLPUBFUNEXPORT int +xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3, + void *userdata, xmlHashDeallocator f) { + LOAD_GS_DIRECT + unsigned long key; + xmlHashEntryPtr entry; + xmlHashEntryPtr insert; + + if ((table == NULL) || name == NULL) + return(-1); + + /* + * Check for duplicate and insertion location. + */ + key = xmlHashComputeKey(table, name, name2, name3); + if (table->table[key].valid == 0) { + insert = NULL; + } else { + for (insert = &(table->table[key]); insert->next != NULL; + insert = insert->next) { + if ((xmlStrEqual(insert->name, name)) && + (xmlStrEqual(insert->name2, name2)) && + (xmlStrEqual(insert->name3, name3))) { + if (f) + f(insert->payload, insert->name); + insert->payload = userdata; + return(0); + } + } + if ((xmlStrEqual(insert->name, name)) && + (xmlStrEqual(insert->name2, name2)) && + (xmlStrEqual(insert->name3, name3))) { + if (f) + f(insert->payload, insert->name); + insert->payload = userdata; + return(0); + } + } + + if (!insert) { + entry = &(table->table[key]); + } else { + entry = (xmlHashEntryPtr)xmlMalloc(sizeof(xmlHashEntry)); + if (entry == NULL) + return(-1); + } + // DONE: Check OOM + entry->name = xmlStrdup(name); // name is never NULL here + entry->name2 = name2 ? xmlStrdup(name2): NULL; + entry->name3 = name3 ? xmlStrdup(name3): NULL; + if(OOM_FLAG){ + if(entry->name) xmlFree(entry->name); + if(entry->name2) xmlFree(entry->name2); + if(entry->name3) xmlFree(entry->name3); + if(insert) xmlFree(entry); + return -1; + } + entry->payload = userdata; + entry->next = NULL; + entry->valid = 1; + table->nbElems++; + + + if (insert) { + insert->next = entry; + } + return(0); +} + +/** + * xmlHashLookup3: + * @param table the hash table + * @param name the name of the userdata + * @param name2 a second name of the userdata + * @param name3 a third name of the userdata + * + * Find the userdata specified by the (name, name2, name3) tuple. + * + * Returns the a pointer to the userdata + * + * OOM: never + */ +XMLPUBFUNEXPORT void * +xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3) +{ + unsigned long key; + xmlHashEntryPtr entry; + + if (table == NULL) + return(NULL); + if (name == NULL) + return(NULL); + key = xmlHashComputeKey(table, name, name2, name3); + if (table->table[key].valid == 0) + return(NULL); + for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { + if ((xmlStrEqual(entry->name, name)) && + (xmlStrEqual(entry->name2, name2)) && + (xmlStrEqual(entry->name3, name3))) + return(entry->payload); + } + return(NULL); +} + +/** + * xmlHashQLookup3: + * @param table the hash table + * @param prefix the prefix of the userdata + * @param name the name of the userdata + * @param prefix2 the second prefix of the userdata + * @param name2 a second name of the userdata + * @param prefix3 the third prefix of the userdata + * @param name3 a third name of the userdata + * + * Find the userdata specified by the (name, name2, name3) tuple. + * + * Returns the a pointer to the userdata + */ +XMLPUBFUNEXPORT void * +xmlHashQLookup3(xmlHashTablePtr table, + const xmlChar *prefix, const xmlChar *name, + const xmlChar *prefix2, const xmlChar *name2, + const xmlChar *prefix3, const xmlChar *name3) { + unsigned long key; + xmlHashEntryPtr entry; + + if (table == NULL) + return(NULL); + if (name == NULL) + return(NULL); + key = xmlHashComputeQKey(table, prefix, name, prefix2, + name2, prefix3, name3); + if (table->table[key].valid == 0) + return(NULL); + for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { + if ((xmlStrQEqual(prefix, name, entry->name)) && + (xmlStrQEqual(prefix2, name2, entry->name2)) && + (xmlStrQEqual(prefix3, name3, entry->name3))) + return(entry->payload); + } + return(NULL); +} + +typedef struct { + xmlHashScanner hashscanner; + void *data; +} stubData; + +static void +stubHashScannerFull (void *payload, void *data, const xmlChar *name, + const xmlChar *name2 ATTRIBUTE_UNUSED, + const xmlChar *name3 ATTRIBUTE_UNUSED) { + stubData *stubdata = (stubData *) data; + stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name); +} + +/** + * xmlHashScan: + * @param table the hash table + * @param f the scanner function for items in the hash + * @param data extra data passed to f + * + * Scan the hash table and applied f to each value. + */ +XMLPUBFUNEXPORT void +xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) { + stubData stubdata; + stubdata.data = data; + stubdata.hashscanner = f; + xmlHashScanFull (table, stubHashScannerFull, &stubdata); +} + +/** + * xmlHashScanFull: + * @param table the hash table + * @param f the scanner function for items in the hash + * @param data extra data passed to f + * + * Scan the hash table and applied f to each value. + */ +XMLPUBFUNEXPORT void +xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) { + int i; + xmlHashEntryPtr iter; + xmlHashEntryPtr next; + + if (table == NULL) + return; + if (f == NULL) + return; + + if (table->table) { + for(i = 0; i < table->size; i++) { + if (table->table[i].valid == 0) + continue; + iter = &(table->table[i]); + while (iter) { + next = iter->next; + if ((f != NULL) && (iter->payload != NULL)) + f(iter->payload, data, iter->name, + iter->name2, iter->name3); + iter = next; + } + } + } +} + +/** + * xmlHashScan3: + * @param table the hash table + * @param name the name of the userdata or NULL + * @param name2 a second name of the userdata or NULL + * @param name3 a third name of the userdata or NULL + * @param f the scanner function for items in the hash + * @param data extra data passed to f + * + * Scan the hash table and applied f to each value matching + * (name, name2, name3) tuple. If one of the names is null, + * the comparison is considered to match. + */ +XMLPUBFUNEXPORT void +xmlHashScan3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3, + xmlHashScanner f, void *data) { + xmlHashScanFull3 (table, name, name2, name3, + (xmlHashScannerFull) f, data); +} + +/** + * xmlHashScanFull3: + * @param table the hash table + * @param name the name of the userdata or NULL + * @param name2 a second name of the userdata or NULL + * @param name3 a third name of the userdata or NULL + * @param f the scanner function for items in the hash + * @param data extra data passed to f + * + * Scan the hash table and applied f to each value matching + * (name, name2, name3) tuple. If one of the names is null, + * the comparison is considered to match. + */ +XMLPUBFUNEXPORT void +xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3, + xmlHashScannerFull f, void *data) { + int i; + xmlHashEntryPtr iter; + xmlHashEntryPtr next; + + if (table == NULL) + return; + if (f == NULL) + return; + + if (table->table) { + for(i = 0; i < table->size; i++) { + if (table->table[i].valid == 0) + continue; + iter = &(table->table[i]); + while (iter) { + next = iter->next; + if (((name == NULL) || (xmlStrEqual(name, iter->name))) && + ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) && + ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) && + (iter->payload != NULL)) { + f(iter->payload, data, iter->name, + iter->name2, iter->name3); + } + iter = next; + } + } + } +} + +/** + * xmlHashCopy: + * @param table the hash table + * @param f the copier function for items in the hash + * + * Scan the hash table and applied f to each value. + * + * Returns the new table or NULL in case of error. + * + * OOM: possible --> returns NULL, OOM flag is set + */ +XMLPUBFUNEXPORT xmlHashTablePtr +xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) +{ + LOAD_GS_DIRECT + int i; + xmlHashEntryPtr iter; + xmlHashEntryPtr next; + xmlHashTablePtr ret; + //int res; + void* pCopy; + + if (table == NULL) + return(NULL); + if (f == NULL) + return(NULL); + + ret = xmlHashCreate(table->size); // may set OOM flag + if(!ret) + return NULL; // OOM happened, the flag is set already + + if (table->table) { + for(i = 0; i < table->size; i++) + { + if (table->table[i].valid == 0) + continue; + iter = &(table->table[i]); + while (iter) + { + next = iter->next; + pCopy = f(iter->payload, iter->name); + if(OOM_FLAG) + goto oom; + //res = + xmlHashAddEntry3( + ret, + iter->name, + iter->name2, + iter->name3, + pCopy); + if(OOM_FLAG) + goto oom; + iter = next; + } + } + } + ret->nbElems = table->nbElems; + return(ret); +oom: + // OOM during copying entry in f() + xmlHashFree(ret, NULL); + return NULL; +} + +#ifndef XMLENGINE_EXCLUDE_UNUSED +/** + * xmlHashSize: + * @param table the hash table + * + * Query the number of elements installed in the hash table. + * + * Returns the number of elements in the hash table or + * -1 in case of error + */ +int +xmlHashSize(xmlHashTablePtr table) +{ + if (table == NULL) + return(-1); + return(table->nbElems); +} +#endif /* ifndef XMLENGINE_EXCLUDE_UNUSED */ + +/** + * xmlHashRemoveEntry: + * @param table the hash table + * @param name the name of the userdata + * @param f the deallocator function for removed item (if any) + * + * Find the userdata specified by the name and remove + * it from the hash table. Existing userdata for this tuple will be removed + * and freed with f. + * + * Returns 0 if the removal succeeded and -1 in case of error or not found. + * + * OOM: never / same as argument function 'f' has, if f!=NULL* + */ +XMLPUBFUNEXPORT int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name, + xmlHashDeallocator f) +{ + return(xmlHashRemoveEntry3(table, name, NULL, NULL, f)); +} + +/** + * xmlHashRemoveEntry2: + * @param table the hash table + * @param name the name of the userdata + * @param name2 a second name of the userdata + * @param f the deallocator function for removed item (if any) + * + * Find the userdata specified by the (name, name2) tuple and remove + * it from the hash table. Existing userdata for this tuple will be removed + * and freed with f. + * + * Returns 0 if the removal succeeded and -1 in case of error or not found. + */ +XMLPUBFUNEXPORT int +xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, xmlHashDeallocator f) { + return(xmlHashRemoveEntry3(table, name, name2, NULL, f)); +} + +/** + * xmlHashRemoveEntry3: + * @param table the hash table + * @param name the name of the userdata + * @param name2 a second name of the userdata + * @param name3 a third name of the userdata + * @param f the deallocator function for removed item (if any) + * + * Find the userdata specified by the (name, name2, name3) tuple and remove + * it from the hash table. Existing userdata for this tuple will be removed + * and freed with f. + * + * Returns 0 if the removal succeeded and -1 in case of error or not found. + * + * OOM: never / same as argument function 'f' has, if f!=NULL + */ +XMLPUBFUNEXPORT int +xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) +{ + unsigned long key; + xmlHashEntryPtr entry; + xmlHashEntryPtr prev = NULL; + + if (table == NULL || name == NULL) + return(-1); + + key = xmlHashComputeKey(table, name, name2, name3); + if (table->table[key].valid == 0) { + return(-1); + } else { + for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { + if (xmlStrEqual(entry->name, name) && + xmlStrEqual(entry->name2, name2) && + xmlStrEqual(entry->name3, name3)) { + if ((f != NULL) && (entry->payload != NULL)) + f(entry->payload, entry->name); + entry->payload = NULL; + if(entry->name) + xmlFree(entry->name); + if(entry->name2) + xmlFree(entry->name2); + if(entry->name3) + xmlFree(entry->name3); + if(prev) { + prev->next = entry->next; + xmlFree(entry); + } else { + if (entry->next == NULL) { + entry->valid = 0; + } else { + entry = entry->next; + memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry)); + xmlFree(entry); + } + } + table->nbElems--; + return(0); + } + prev = entry; + } + return(-1); + } +}