1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147 |
- /*
- * hash.c: chained hash tables
- *
- * Reference: Your favorite introductory book on algorithms
- *
- * Copyright (C) 2000,2012 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
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
- * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
- *
- * Author: breese@users.sourceforge.net
- */
- #define IN_LIBXML
- #include "libxml.h"
- #include <string.h>
- #ifdef HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #ifdef HAVE_TIME_H
- #include <time.h>
- #endif
- /*
- * Following http://www.ocert.org/advisories/ocert-2011-003.html
- * it seems that having hash randomization might be a good idea
- * when using XML with untrusted data
- */
- #if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME) && \
- !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
- #define HASH_RANDOMIZATION
- #endif
- #include <libxml/parser.h>
- #include <libxml/hash.h>
- #include <libxml/xmlmemory.h>
- #include <libxml/xmlerror.h>
- #include <libxml/globals.h>
- #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 {
- struct _xmlHashEntry *table;
- int size;
- int nbElems;
- xmlDictPtr dict;
- #ifdef HASH_RANDOMIZATION
- int random_seed;
- #endif
- };
- /*
- * xmlHashComputeKey:
- * Calculate the hash key
- */
- #ifdef __clang__
- ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
- #endif
- static unsigned long
- xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
- const xmlChar *name2, const xmlChar *name3) {
- unsigned long value = 0L;
- unsigned long ch;
- #ifdef HASH_RANDOMIZATION
- value = table->random_seed;
- #endif
- if (name != NULL) {
- value += 30 * (*name);
- while ((ch = *name++) != 0) {
- value = value ^ ((value << 5) + (value >> 3) + ch);
- }
- }
- value = value ^ ((value << 5) + (value >> 3));
- if (name2 != NULL) {
- while ((ch = *name2++) != 0) {
- value = value ^ ((value << 5) + (value >> 3) + ch);
- }
- }
- value = value ^ ((value << 5) + (value >> 3));
- if (name3 != NULL) {
- while ((ch = *name3++) != 0) {
- value = value ^ ((value << 5) + (value >> 3) + ch);
- }
- }
- return (value % table->size);
- }
- #ifdef __clang__
- ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
- #endif
- 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;
- unsigned long ch;
- #ifdef HASH_RANDOMIZATION
- value = table->random_seed;
- #endif
- if (prefix != NULL)
- value += 30 * (*prefix);
- else
- value += 30 * (*name);
- if (prefix != NULL) {
- while ((ch = *prefix++) != 0) {
- value = value ^ ((value << 5) + (value >> 3) + ch);
- }
- value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
- }
- if (name != NULL) {
- while ((ch = *name++) != 0) {
- value = value ^ ((value << 5) + (value >> 3) + ch);
- }
- }
- value = value ^ ((value << 5) + (value >> 3));
- if (prefix2 != NULL) {
- while ((ch = *prefix2++) != 0) {
- value = value ^ ((value << 5) + (value >> 3) + ch);
- }
- value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
- }
- if (name2 != NULL) {
- while ((ch = *name2++) != 0) {
- value = value ^ ((value << 5) + (value >> 3) + ch);
- }
- }
- value = value ^ ((value << 5) + (value >> 3));
- if (prefix3 != NULL) {
- while ((ch = *prefix3++) != 0) {
- value = value ^ ((value << 5) + (value >> 3) + ch);
- }
- value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
- }
- if (name3 != NULL) {
- while ((ch = *name3++) != 0) {
- value = value ^ ((value << 5) + (value >> 3) + ch);
- }
- }
- return (value % table->size);
- }
- /**
- * xmlHashCreate:
- * @size: the size of the hash table
- *
- * Create a new xmlHashTablePtr.
- *
- * Returns the newly created object, or NULL if an error occurred.
- */
- xmlHashTablePtr
- xmlHashCreate(int size) {
- xmlHashTablePtr table;
- if (size <= 0)
- size = 256;
- table = xmlMalloc(sizeof(xmlHashTable));
- if (table) {
- table->dict = NULL;
- table->size = size;
- table->nbElems = 0;
- table->table = xmlMalloc(size * sizeof(xmlHashEntry));
- if (table->table) {
- memset(table->table, 0, size * sizeof(xmlHashEntry));
- #ifdef HASH_RANDOMIZATION
- table->random_seed = __xmlRandom();
- #endif
- return(table);
- }
- xmlFree(table);
- }
- return(NULL);
- }
- /**
- * xmlHashCreateDict:
- * @size: the size of the hash table
- * @dict: a dictionary to use for the hash
- *
- * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
- *
- * Returns the newly created object, or NULL if an error occurred.
- */
- xmlHashTablePtr
- xmlHashCreateDict(int size, xmlDictPtr dict) {
- xmlHashTablePtr table;
- table = xmlHashCreate(size);
- if (table != NULL) {
- table->dict = dict;
- xmlDictReference(dict);
- }
- return(table);
- }
- /**
- * xmlHashGrow:
- * @table: the hash table
- * @size: the new size of the hash table
- *
- * resize the hash table
- *
- * Returns 0 in case of success, -1 in case of failure
- */
- 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 = xmlMalloc(size * sizeof(xmlHashEntry));
- 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:
- * @table: the hash table
- * @f: the deallocator function for items in the hash
- *
- * Free the hash @table and its contents. The userdata is
- * deallocated with @f if provided.
- */
- 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 (table->dict == NULL) {
- 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;
- }
- }
- xmlFree(table->table);
- }
- if (table->dict)
- xmlDictFree(table->dict);
- xmlFree(table);
- }
- /**
- * xmlHashDefaultDeallocator:
- * @entry: the hash table entry
- * @name: the entry's name
- *
- * Free a hash table entry with xmlFree.
- */
- void
- xmlHashDefaultDeallocator(void *entry, const xmlChar *name ATTRIBUTE_UNUSED) {
- xmlFree(entry);
- }
- /**
- * xmlHashAddEntry:
- * @table: the hash table
- * @name: the name of the userdata
- * @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.
- */
- int
- xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
- return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
- }
- /**
- * xmlHashAddEntry2:
- * @table: the hash table
- * @name: the name of the userdata
- * @name2: a second name of the userdata
- * @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.
- */
- int
- xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
- const xmlChar *name2, void *userdata) {
- return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
- }
- /**
- * xmlHashUpdateEntry:
- * @table: the hash table
- * @name: the name of the userdata
- * @userdata: a pointer to the userdata
- * @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.
- */
- int
- xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
- void *userdata, xmlHashDeallocator f) {
- return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
- }
- /**
- * xmlHashUpdateEntry2:
- * @table: the hash table
- * @name: the name of the userdata
- * @name2: a second name of the userdata
- * @userdata: a pointer to the userdata
- * @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.
- */
- int
- xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
- const xmlChar *name2, void *userdata,
- xmlHashDeallocator f) {
- return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
- }
- /**
- * xmlHashLookup:
- * @table: the hash table
- * @name: the name of the userdata
- *
- * Find the userdata specified by the @name.
- *
- * Returns the pointer to the userdata
- */
- void *
- xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
- return(xmlHashLookup3(table, name, NULL, NULL));
- }
- /**
- * xmlHashLookup2:
- * @table: the hash table
- * @name: the name of the userdata
- * @name2: a second name of the userdata
- *
- * Find the userdata specified by the (@name, @name2) tuple.
- *
- * Returns the pointer to the userdata
- */
- void *
- xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
- const xmlChar *name2) {
- return(xmlHashLookup3(table, name, name2, NULL));
- }
- /**
- * xmlHashQLookup:
- * @table: the hash table
- * @prefix: the prefix of the userdata
- * @name: the name of the userdata
- *
- * Find the userdata specified by the QName @prefix:@name/@name.
- *
- * Returns the pointer to the userdata
- */
- void *
- xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
- const xmlChar *name) {
- return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
- }
- /**
- * xmlHashQLookup2:
- * @table: the hash table
- * @prefix: the prefix of the userdata
- * @name: the name of the userdata
- * @prefix2: the second prefix of the userdata
- * @name2: a second name of the userdata
- *
- * Find the userdata specified by the QNames tuple
- *
- * Returns the pointer to the userdata
- */
- 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:
- * @table: the hash table
- * @name: the name of the userdata
- * @name2: a second name of the userdata
- * @name3: a third name of the userdata
- * @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.
- */
- int
- xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
- const xmlChar *name2, const xmlChar *name3,
- void *userdata) {
- unsigned long key, len = 0;
- xmlHashEntryPtr entry;
- xmlHashEntryPtr insert;
- if ((table == NULL) || (name == NULL))
- return(-1);
- /*
- * If using a dict internalize if needed
- */
- if (table->dict) {
- if (!xmlDictOwns(table->dict, name)) {
- name = xmlDictLookup(table->dict, name, -1);
- if (name == NULL)
- return(-1);
- }
- if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
- name2 = xmlDictLookup(table->dict, name2, -1);
- if (name2 == NULL)
- return(-1);
- }
- if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
- name3 = xmlDictLookup(table->dict, name3, -1);
- if (name3 == NULL)
- return(-1);
- }
- }
- /*
- * Check for duplicate and insertion location.
- */
- key = xmlHashComputeKey(table, name, name2, name3);
- if (table->table[key].valid == 0) {
- insert = NULL;
- } else {
- if (table->dict) {
- for (insert = &(table->table[key]); insert->next != NULL;
- insert = insert->next) {
- if ((insert->name == name) &&
- (insert->name2 == name2) &&
- (insert->name3 == name3))
- return(-1);
- len++;
- }
- if ((insert->name == name) &&
- (insert->name2 == name2) &&
- (insert->name3 == name3))
- return(-1);
- } 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 = xmlMalloc(sizeof(xmlHashEntry));
- if (entry == NULL)
- return(-1);
- }
- if (table->dict != NULL) {
- entry->name = (xmlChar *) name;
- entry->name2 = (xmlChar *) name2;
- entry->name3 = (xmlChar *) name3;
- } else {
- entry->name = xmlStrdup(name);
- entry->name2 = xmlStrdup(name2);
- entry->name3 = xmlStrdup(name3);
- }
- entry->payload = userdata;
- entry->next = NULL;
- entry->valid = 1;
- if (insert != NULL)
- insert->next = entry;
- table->nbElems++;
- if (len > MAX_HASH_LEN)
- xmlHashGrow(table, MAX_HASH_LEN * table->size);
- return(0);
- }
- /**
- * xmlHashUpdateEntry3:
- * @table: the hash table
- * @name: the name of the userdata
- * @name2: a second name of the userdata
- * @name3: a third name of the userdata
- * @userdata: a pointer to the userdata
- * @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.
- */
- int
- xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
- const xmlChar *name2, const xmlChar *name3,
- void *userdata, xmlHashDeallocator f) {
- unsigned long key;
- xmlHashEntryPtr entry;
- xmlHashEntryPtr insert;
- if ((table == NULL) || name == NULL)
- return(-1);
- /*
- * If using a dict internalize if needed
- */
- if (table->dict) {
- if (!xmlDictOwns(table->dict, name)) {
- name = xmlDictLookup(table->dict, name, -1);
- if (name == NULL)
- return(-1);
- }
- if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
- name2 = xmlDictLookup(table->dict, name2, -1);
- if (name2 == NULL)
- return(-1);
- }
- if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
- name3 = xmlDictLookup(table->dict, name3, -1);
- if (name3 == NULL)
- return(-1);
- }
- }
- /*
- * Check for duplicate and insertion location.
- */
- key = xmlHashComputeKey(table, name, name2, name3);
- if (table->table[key].valid == 0) {
- insert = NULL;
- } else {
- if (table ->dict) {
- for (insert = &(table->table[key]); insert->next != NULL;
- insert = insert->next) {
- if ((insert->name == name) &&
- (insert->name2 == name2) &&
- (insert->name3 == name3)) {
- if (f)
- f(insert->payload, insert->name);
- insert->payload = userdata;
- return(0);
- }
- }
- if ((insert->name == name) &&
- (insert->name2 == name2) &&
- (insert->name3 == name3)) {
- if (f)
- f(insert->payload, insert->name);
- insert->payload = userdata;
- return(0);
- }
- } 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 == NULL) {
- entry = &(table->table[key]);
- } else {
- entry = xmlMalloc(sizeof(xmlHashEntry));
- if (entry == NULL)
- return(-1);
- }
- if (table->dict != NULL) {
- entry->name = (xmlChar *) name;
- entry->name2 = (xmlChar *) name2;
- entry->name3 = (xmlChar *) name3;
- } else {
- entry->name = xmlStrdup(name);
- entry->name2 = xmlStrdup(name2);
- entry->name3 = xmlStrdup(name3);
- }
- entry->payload = userdata;
- entry->next = NULL;
- entry->valid = 1;
- table->nbElems++;
- if (insert != NULL) {
- insert->next = entry;
- }
- return(0);
- }
- /**
- * xmlHashLookup3:
- * @table: the hash table
- * @name: the name of the userdata
- * @name2: a second name of the userdata
- * @name3: a third name of the userdata
- *
- * Find the userdata specified by the (@name, @name2, @name3) tuple.
- *
- * Returns the a pointer to the userdata
- */
- 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);
- if (table->dict) {
- for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
- if ((entry->name == name) &&
- (entry->name2 == name2) &&
- (entry->name3 == name3))
- return(entry->payload);
- }
- }
- 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:
- * @table: the hash table
- * @prefix: the prefix of the userdata
- * @name: the name of the userdata
- * @prefix2: the second prefix of the userdata
- * @name2: a second name of the userdata
- * @prefix3: the third prefix of the userdata
- * @name3: a third name of the userdata
- *
- * Find the userdata specified by the (@name, @name2, @name3) tuple.
- *
- * Returns the a pointer to the userdata
- */
- 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:
- * @table: the hash table
- * @f: the scanner function for items in the hash
- * @data: extra data passed to f
- *
- * Scan the hash @table and applied @f to each value.
- */
- void
- xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
- stubData stubdata;
- stubdata.data = data;
- stubdata.hashscanner = f;
- xmlHashScanFull (table, stubHashScannerFull, &stubdata);
- }
- /**
- * xmlHashScanFull:
- * @table: the hash table
- * @f: the scanner function for items in the hash
- * @data: extra data passed to f
- *
- * Scan the hash @table and applied @f to each value.
- */
- void
- xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
- int i, nb;
- 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;
- nb = table->nbElems;
- if ((f != NULL) && (iter->payload != NULL))
- f(iter->payload, data, iter->name,
- iter->name2, iter->name3);
- if (nb != table->nbElems) {
- /* table was modified by the callback, be careful */
- if (iter == &(table->table[i])) {
- if (table->table[i].valid == 0)
- iter = NULL;
- if (table->table[i].next != next)
- iter = &(table->table[i]);
- } else
- iter = next;
- } else
- iter = next;
- }
- }
- }
- }
- /**
- * xmlHashScan3:
- * @table: the hash table
- * @name: the name of the userdata or NULL
- * @name2: a second name of the userdata or NULL
- * @name3: a third name of the userdata or NULL
- * @f: the scanner function for items in the hash
- * @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.
- */
- void
- xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
- const xmlChar *name2, const xmlChar *name3,
- xmlHashScanner f, void *data) {
- stubData stubdata;
- stubdata.data = data;
- stubdata.hashscanner = f;
- xmlHashScanFull3(table, name, name2, name3, stubHashScannerFull,
- &stubdata);
- }
- /**
- * xmlHashScanFull3:
- * @table: the hash table
- * @name: the name of the userdata or NULL
- * @name2: a second name of the userdata or NULL
- * @name3: a third name of the userdata or NULL
- * @f: the scanner function for items in the hash
- * @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.
- */
- 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:
- * @table: the hash table
- * @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.
- */
- xmlHashTablePtr
- xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
- int i;
- xmlHashEntryPtr iter;
- xmlHashEntryPtr next;
- xmlHashTablePtr ret;
- if (table == NULL)
- return(NULL);
- if (f == NULL)
- return(NULL);
- ret = xmlHashCreate(table->size);
- if (ret == NULL)
- return(NULL);
- 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;
- xmlHashAddEntry3(ret, iter->name, iter->name2,
- iter->name3, f(iter->payload, iter->name));
- iter = next;
- }
- }
- }
- ret->nbElems = table->nbElems;
- return(ret);
- }
- /**
- * xmlHashSize:
- * @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);
- }
- /**
- * xmlHashRemoveEntry:
- * @table: the hash table
- * @name: the name of the userdata
- * @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.
- */
- int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
- xmlHashDeallocator f) {
- return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
- }
- /**
- * xmlHashRemoveEntry2:
- * @table: the hash table
- * @name: the name of the userdata
- * @name2: a second name of the userdata
- * @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.
- */
- int
- xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
- const xmlChar *name2, xmlHashDeallocator f) {
- return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
- }
- /**
- * xmlHashRemoveEntry3:
- * @table: the hash table
- * @name: the name of the userdata
- * @name2: a second name of the userdata
- * @name3: a third name of the userdata
- * @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.
- */
- 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 (table->dict == 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);
- }
- }
- #define bottom_hash
- #include "elfgcchack.h"
|