| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089 | 
							- /*
 
-  * 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
 
-  */
 
- #define IN_LIBXML
 
- #include "libxml.h"
 
- #include <string.h>
 
- #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;
 
- };
 
- /*
 
-  * xmlHashComputeKey:
 
-  * Calculate the hash key
 
-  */
 
- 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:
 
-  * @size: the size of the hash table
 
-  *
 
-  * Create a new xmlHashTablePtr.
 
-  *
 
-  * Returns the newly created object, or NULL if an error occured.
 
-  */
 
- 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));
 
-   	    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 occured.
 
-  */
 
- 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);
 
- }
 
- /**
 
-  * 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) {
 
-     xmlHashScanFull3 (table, name, name2, name3,
 
- 		      (xmlHashScannerFull) f, data);
 
- }
 
- /**
 
-  * 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 (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"
 
 
  |