Home | History | Annotate | Download | only in src
      1 /*
      2  * hash.c: chained hash tables
      3  *
      4  * Reference: Your favorite introductory book on algorithms
      5  *
      6  * Copyright (C) 2000 Bjorn Reese and Daniel Veillard.
      7  *
      8  * Permission to use, copy, modify, and distribute this software for any
      9  * purpose with or without fee is hereby granted, provided that the above
     10  * copyright notice and this permission notice appear in all copies.
     11  *
     12  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     13  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     14  * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
     15  * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
     16  *
     17  * Author: breese (at) users.sourceforge.net
     18  */
     19 
     20 #define IN_LIBXML
     21 #include "libxml.h"
     22 
     23 #include <string.h>
     24 #include <libxml/parser.h>
     25 #include <libxml/hash.h>
     26 #include <libxml/xmlmemory.h>
     27 #include <libxml/xmlerror.h>
     28 #include <libxml/globals.h>
     29 
     30 #define MAX_HASH_LEN 8
     31 
     32 /* #define DEBUG_GROW */
     33 
     34 /*
     35  * A single entry in the hash table
     36  */
     37 typedef struct _xmlHashEntry xmlHashEntry;
     38 typedef xmlHashEntry *xmlHashEntryPtr;
     39 struct _xmlHashEntry {
     40     struct _xmlHashEntry *next;
     41     xmlChar *name;
     42     xmlChar *name2;
     43     xmlChar *name3;
     44     void *payload;
     45     int valid;
     46 };
     47 
     48 /*
     49  * The entire hash table
     50  */
     51 struct _xmlHashTable {
     52     struct _xmlHashEntry *table;
     53     int size;
     54     int nbElems;
     55     xmlDictPtr dict;
     56 };
     57 
     58 /*
     59  * xmlHashComputeKey:
     60  * Calculate the hash key
     61  */
     62 static unsigned long
     63 xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
     64 	          const xmlChar *name2, const xmlChar *name3) {
     65     unsigned long value = 0L;
     66     char ch;
     67 
     68     if (name != NULL) {
     69 	value += 30 * (*name);
     70 	while ((ch = *name++) != 0) {
     71 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
     72 	}
     73     }
     74     if (name2 != NULL) {
     75 	while ((ch = *name2++) != 0) {
     76 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
     77 	}
     78     }
     79     if (name3 != NULL) {
     80 	while ((ch = *name3++) != 0) {
     81 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
     82 	}
     83     }
     84     return (value % table->size);
     85 }
     86 
     87 static unsigned long
     88 xmlHashComputeQKey(xmlHashTablePtr table,
     89 		   const xmlChar *prefix, const xmlChar *name,
     90 		   const xmlChar *prefix2, const xmlChar *name2,
     91 		   const xmlChar *prefix3, const xmlChar *name3) {
     92     unsigned long value = 0L;
     93     char ch;
     94 
     95     if (prefix != NULL)
     96 	value += 30 * (*prefix);
     97     else
     98 	value += 30 * (*name);
     99 
    100     if (prefix != NULL) {
    101 	while ((ch = *prefix++) != 0) {
    102 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
    103 	}
    104 	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
    105     }
    106     if (name != NULL) {
    107 	while ((ch = *name++) != 0) {
    108 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
    109 	}
    110     }
    111     if (prefix2 != NULL) {
    112 	while ((ch = *prefix2++) != 0) {
    113 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
    114 	}
    115 	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
    116     }
    117     if (name2 != NULL) {
    118 	while ((ch = *name2++) != 0) {
    119 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
    120 	}
    121     }
    122     if (prefix3 != NULL) {
    123 	while ((ch = *prefix3++) != 0) {
    124 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
    125 	}
    126 	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
    127     }
    128     if (name3 != NULL) {
    129 	while ((ch = *name3++) != 0) {
    130 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
    131 	}
    132     }
    133     return (value % table->size);
    134 }
    135 
    136 /**
    137  * xmlHashCreate:
    138  * @size: the size of the hash table
    139  *
    140  * Create a new xmlHashTablePtr.
    141  *
    142  * Returns the newly created object, or NULL if an error occured.
    143  */
    144 xmlHashTablePtr
    145 xmlHashCreate(int size) {
    146     xmlHashTablePtr table;
    147 
    148     if (size <= 0)
    149         size = 256;
    150 
    151     table = xmlMalloc(sizeof(xmlHashTable));
    152     if (table) {
    153         table->dict = NULL;
    154         table->size = size;
    155 	table->nbElems = 0;
    156         table->table = xmlMalloc(size * sizeof(xmlHashEntry));
    157         if (table->table) {
    158   	    memset(table->table, 0, size * sizeof(xmlHashEntry));
    159   	    return(table);
    160         }
    161         xmlFree(table);
    162     }
    163     return(NULL);
    164 }
    165 
    166 /**
    167  * xmlHashCreateDict:
    168  * @size: the size of the hash table
    169  * @dict: a dictionary to use for the hash
    170  *
    171  * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
    172  *
    173  * Returns the newly created object, or NULL if an error occured.
    174  */
    175 xmlHashTablePtr
    176 xmlHashCreateDict(int size, xmlDictPtr dict) {
    177     xmlHashTablePtr table;
    178 
    179     table = xmlHashCreate(size);
    180     if (table != NULL) {
    181         table->dict = dict;
    182 	xmlDictReference(dict);
    183     }
    184     return(table);
    185 }
    186 
    187 /**
    188  * xmlHashGrow:
    189  * @table: the hash table
    190  * @size: the new size of the hash table
    191  *
    192  * resize the hash table
    193  *
    194  * Returns 0 in case of success, -1 in case of failure
    195  */
    196 static int
    197 xmlHashGrow(xmlHashTablePtr table, int size) {
    198     unsigned long key;
    199     int oldsize, i;
    200     xmlHashEntryPtr iter, next;
    201     struct _xmlHashEntry *oldtable;
    202 #ifdef DEBUG_GROW
    203     unsigned long nbElem = 0;
    204 #endif
    205 
    206     if (table == NULL)
    207 	return(-1);
    208     if (size < 8)
    209         return(-1);
    210     if (size > 8 * 2048)
    211 	return(-1);
    212 
    213     oldsize = table->size;
    214     oldtable = table->table;
    215     if (oldtable == NULL)
    216         return(-1);
    217 
    218     table->table = xmlMalloc(size * sizeof(xmlHashEntry));
    219     if (table->table == NULL) {
    220 	table->table = oldtable;
    221 	return(-1);
    222     }
    223     memset(table->table, 0, size * sizeof(xmlHashEntry));
    224     table->size = size;
    225 
    226     /*	If the two loops are merged, there would be situations where
    227 	a new entry needs to allocated and data copied into it from
    228 	the main table. So instead, we run through the array twice, first
    229 	copying all the elements in the main array (where we can't get
    230 	conflicts) and then the rest, so we only free (and don't allocate)
    231     */
    232     for (i = 0; i < oldsize; i++) {
    233 	if (oldtable[i].valid == 0)
    234 	    continue;
    235 	key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
    236 				oldtable[i].name3);
    237 	memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
    238 	table->table[key].next = NULL;
    239     }
    240 
    241     for (i = 0; i < oldsize; i++) {
    242 	iter = oldtable[i].next;
    243 	while (iter) {
    244 	    next = iter->next;
    245 
    246 	    /*
    247 	     * put back the entry in the new table
    248 	     */
    249 
    250 	    key = xmlHashComputeKey(table, iter->name, iter->name2,
    251 		                    iter->name3);
    252 	    if (table->table[key].valid == 0) {
    253 		memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
    254 		table->table[key].next = NULL;
    255 		xmlFree(iter);
    256 	    } else {
    257 	    	iter->next = table->table[key].next;
    258 	    	table->table[key].next = iter;
    259 	    }
    260 
    261 #ifdef DEBUG_GROW
    262 	    nbElem++;
    263 #endif
    264 
    265 	    iter = next;
    266 	}
    267     }
    268 
    269     xmlFree(oldtable);
    270 
    271 #ifdef DEBUG_GROW
    272     xmlGenericError(xmlGenericErrorContext,
    273 	    "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
    274 #endif
    275 
    276     return(0);
    277 }
    278 
    279 /**
    280  * xmlHashFree:
    281  * @table: the hash table
    282  * @f:  the deallocator function for items in the hash
    283  *
    284  * Free the hash @table and its contents. The userdata is
    285  * deallocated with @f if provided.
    286  */
    287 void
    288 xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
    289     int i;
    290     xmlHashEntryPtr iter;
    291     xmlHashEntryPtr next;
    292     int inside_table = 0;
    293     int nbElems;
    294 
    295     if (table == NULL)
    296 	return;
    297     if (table->table) {
    298 	nbElems = table->nbElems;
    299 	for(i = 0; (i < table->size) && (nbElems > 0); i++) {
    300 	    iter = &(table->table[i]);
    301 	    if (iter->valid == 0)
    302 		continue;
    303 	    inside_table = 1;
    304 	    while (iter) {
    305 		next = iter->next;
    306 		if ((f != NULL) && (iter->payload != NULL))
    307 		    f(iter->payload, iter->name);
    308 		if (table->dict == NULL) {
    309 		    if (iter->name)
    310 			xmlFree(iter->name);
    311 		    if (iter->name2)
    312 			xmlFree(iter->name2);
    313 		    if (iter->name3)
    314 			xmlFree(iter->name3);
    315 		}
    316 		iter->payload = NULL;
    317 		if (!inside_table)
    318 		    xmlFree(iter);
    319 		nbElems--;
    320 		inside_table = 0;
    321 		iter = next;
    322 	    }
    323 	}
    324 	xmlFree(table->table);
    325     }
    326     if (table->dict)
    327         xmlDictFree(table->dict);
    328     xmlFree(table);
    329 }
    330 
    331 /**
    332  * xmlHashAddEntry:
    333  * @table: the hash table
    334  * @name: the name of the userdata
    335  * @userdata: a pointer to the userdata
    336  *
    337  * Add the @userdata to the hash @table. This can later be retrieved
    338  * by using the @name. Duplicate names generate errors.
    339  *
    340  * Returns 0 the addition succeeded and -1 in case of error.
    341  */
    342 int
    343 xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
    344     return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
    345 }
    346 
    347 /**
    348  * xmlHashAddEntry2:
    349  * @table: the hash table
    350  * @name: the name of the userdata
    351  * @name2: a second name of the userdata
    352  * @userdata: a pointer to the userdata
    353  *
    354  * Add the @userdata to the hash @table. This can later be retrieved
    355  * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
    356  *
    357  * Returns 0 the addition succeeded and -1 in case of error.
    358  */
    359 int
    360 xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
    361 	        const xmlChar *name2, void *userdata) {
    362     return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
    363 }
    364 
    365 /**
    366  * xmlHashUpdateEntry:
    367  * @table: the hash table
    368  * @name: the name of the userdata
    369  * @userdata: a pointer to the userdata
    370  * @f: the deallocator function for replaced item (if any)
    371  *
    372  * Add the @userdata to the hash @table. This can later be retrieved
    373  * by using the @name. Existing entry for this @name will be removed
    374  * and freed with @f if found.
    375  *
    376  * Returns 0 the addition succeeded and -1 in case of error.
    377  */
    378 int
    379 xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
    380 	           void *userdata, xmlHashDeallocator f) {
    381     return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
    382 }
    383 
    384 /**
    385  * xmlHashUpdateEntry2:
    386  * @table: the hash table
    387  * @name: the name of the userdata
    388  * @name2: a second name of the userdata
    389  * @userdata: a pointer to the userdata
    390  * @f: the deallocator function for replaced item (if any)
    391  *
    392  * Add the @userdata to the hash @table. This can later be retrieved
    393  * by using the (@name, @name2) tuple. Existing entry for this tuple will
    394  * be removed and freed with @f if found.
    395  *
    396  * Returns 0 the addition succeeded and -1 in case of error.
    397  */
    398 int
    399 xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
    400 	           const xmlChar *name2, void *userdata,
    401 		   xmlHashDeallocator f) {
    402     return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
    403 }
    404 
    405 /**
    406  * xmlHashLookup:
    407  * @table: the hash table
    408  * @name: the name of the userdata
    409  *
    410  * Find the userdata specified by the @name.
    411  *
    412  * Returns the pointer to the userdata
    413  */
    414 void *
    415 xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
    416     return(xmlHashLookup3(table, name, NULL, NULL));
    417 }
    418 
    419 /**
    420  * xmlHashLookup2:
    421  * @table: the hash table
    422  * @name: the name of the userdata
    423  * @name2: a second name of the userdata
    424  *
    425  * Find the userdata specified by the (@name, @name2) tuple.
    426  *
    427  * Returns the pointer to the userdata
    428  */
    429 void *
    430 xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
    431 	      const xmlChar *name2) {
    432     return(xmlHashLookup3(table, name, name2, NULL));
    433 }
    434 
    435 /**
    436  * xmlHashQLookup:
    437  * @table: the hash table
    438  * @prefix: the prefix of the userdata
    439  * @name: the name of the userdata
    440  *
    441  * Find the userdata specified by the QName @prefix:@name/@name.
    442  *
    443  * Returns the pointer to the userdata
    444  */
    445 void *
    446 xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
    447                const xmlChar *name) {
    448     return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
    449 }
    450 
    451 /**
    452  * xmlHashQLookup2:
    453  * @table: the hash table
    454  * @prefix: the prefix of the userdata
    455  * @name: the name of the userdata
    456  * @prefix2: the second prefix of the userdata
    457  * @name2: a second name of the userdata
    458  *
    459  * Find the userdata specified by the QNames tuple
    460  *
    461  * Returns the pointer to the userdata
    462  */
    463 void *
    464 xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix,
    465                 const xmlChar *name, const xmlChar *prefix2,
    466 	        const xmlChar *name2) {
    467     return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
    468 }
    469 
    470 /**
    471  * xmlHashAddEntry3:
    472  * @table: the hash table
    473  * @name: the name of the userdata
    474  * @name2: a second name of the userdata
    475  * @name3: a third name of the userdata
    476  * @userdata: a pointer to the userdata
    477  *
    478  * Add the @userdata to the hash @table. This can later be retrieved
    479  * by using the tuple (@name, @name2, @name3). Duplicate entries generate
    480  * errors.
    481  *
    482  * Returns 0 the addition succeeded and -1 in case of error.
    483  */
    484 int
    485 xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
    486 	         const xmlChar *name2, const xmlChar *name3,
    487 		 void *userdata) {
    488     unsigned long key, len = 0;
    489     xmlHashEntryPtr entry;
    490     xmlHashEntryPtr insert;
    491 
    492     if ((table == NULL) || (name == NULL))
    493 	return(-1);
    494 
    495     /*
    496      * If using a dict internalize if needed
    497      */
    498     if (table->dict) {
    499         if (!xmlDictOwns(table->dict, name)) {
    500 	    name = xmlDictLookup(table->dict, name, -1);
    501 	    if (name == NULL)
    502 	        return(-1);
    503 	}
    504         if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
    505 	    name2 = xmlDictLookup(table->dict, name2, -1);
    506 	    if (name2 == NULL)
    507 	        return(-1);
    508 	}
    509         if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
    510 	    name3 = xmlDictLookup(table->dict, name3, -1);
    511 	    if (name3 == NULL)
    512 	        return(-1);
    513 	}
    514     }
    515 
    516     /*
    517      * Check for duplicate and insertion location.
    518      */
    519     key = xmlHashComputeKey(table, name, name2, name3);
    520     if (table->table[key].valid == 0) {
    521 	insert = NULL;
    522     } else {
    523         if (table->dict) {
    524 	    for (insert = &(table->table[key]); insert->next != NULL;
    525 		 insert = insert->next) {
    526 		if ((insert->name == name) &&
    527 		    (insert->name2 == name2) &&
    528 		    (insert->name3 == name3))
    529 		    return(-1);
    530 		len++;
    531 	    }
    532 	    if ((insert->name == name) &&
    533 		(insert->name2 == name2) &&
    534 		(insert->name3 == name3))
    535 		return(-1);
    536 	} else {
    537 	    for (insert = &(table->table[key]); insert->next != NULL;
    538 		 insert = insert->next) {
    539 		if ((xmlStrEqual(insert->name, name)) &&
    540 		    (xmlStrEqual(insert->name2, name2)) &&
    541 		    (xmlStrEqual(insert->name3, name3)))
    542 		    return(-1);
    543 		len++;
    544 	    }
    545 	    if ((xmlStrEqual(insert->name, name)) &&
    546 		(xmlStrEqual(insert->name2, name2)) &&
    547 		(xmlStrEqual(insert->name3, name3)))
    548 		return(-1);
    549 	}
    550     }
    551 
    552     if (insert == NULL) {
    553 	entry = &(table->table[key]);
    554     } else {
    555 	entry = xmlMalloc(sizeof(xmlHashEntry));
    556 	if (entry == NULL)
    557 	     return(-1);
    558     }
    559 
    560     if (table->dict != NULL) {
    561         entry->name = (xmlChar *) name;
    562         entry->name2 = (xmlChar *) name2;
    563         entry->name3 = (xmlChar *) name3;
    564     } else {
    565 	entry->name = xmlStrdup(name);
    566 	entry->name2 = xmlStrdup(name2);
    567 	entry->name3 = xmlStrdup(name3);
    568     }
    569     entry->payload = userdata;
    570     entry->next = NULL;
    571     entry->valid = 1;
    572 
    573 
    574     if (insert != NULL)
    575 	insert->next = entry;
    576 
    577     table->nbElems++;
    578 
    579     if (len > MAX_HASH_LEN)
    580 	xmlHashGrow(table, MAX_HASH_LEN * table->size);
    581 
    582     return(0);
    583 }
    584 
    585 /**
    586  * xmlHashUpdateEntry3:
    587  * @table: the hash table
    588  * @name: the name of the userdata
    589  * @name2: a second name of the userdata
    590  * @name3: a third name of the userdata
    591  * @userdata: a pointer to the userdata
    592  * @f: the deallocator function for replaced item (if any)
    593  *
    594  * Add the @userdata to the hash @table. This can later be retrieved
    595  * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
    596  * will be removed and freed with @f if found.
    597  *
    598  * Returns 0 the addition succeeded and -1 in case of error.
    599  */
    600 int
    601 xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
    602 	           const xmlChar *name2, const xmlChar *name3,
    603 		   void *userdata, xmlHashDeallocator f) {
    604     unsigned long key;
    605     xmlHashEntryPtr entry;
    606     xmlHashEntryPtr insert;
    607 
    608     if ((table == NULL) || name == NULL)
    609 	return(-1);
    610 
    611     /*
    612      * If using a dict internalize if needed
    613      */
    614     if (table->dict) {
    615         if (!xmlDictOwns(table->dict, name)) {
    616 	    name = xmlDictLookup(table->dict, name, -1);
    617 	    if (name == NULL)
    618 	        return(-1);
    619 	}
    620         if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
    621 	    name2 = xmlDictLookup(table->dict, name2, -1);
    622 	    if (name2 == NULL)
    623 	        return(-1);
    624 	}
    625         if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
    626 	    name3 = xmlDictLookup(table->dict, name3, -1);
    627 	    if (name3 == NULL)
    628 	        return(-1);
    629 	}
    630     }
    631 
    632     /*
    633      * Check for duplicate and insertion location.
    634      */
    635     key = xmlHashComputeKey(table, name, name2, name3);
    636     if (table->table[key].valid == 0) {
    637 	insert = NULL;
    638     } else {
    639         if (table ->dict) {
    640 	    for (insert = &(table->table[key]); insert->next != NULL;
    641 		 insert = insert->next) {
    642 		if ((insert->name == name) &&
    643 		    (insert->name2 == name2) &&
    644 		    (insert->name3 == name3)) {
    645 		    if (f)
    646 			f(insert->payload, insert->name);
    647 		    insert->payload = userdata;
    648 		    return(0);
    649 		}
    650 	    }
    651 	    if ((insert->name == name) &&
    652 		(insert->name2 == name2) &&
    653 		(insert->name3 == name3)) {
    654 		if (f)
    655 		    f(insert->payload, insert->name);
    656 		insert->payload = userdata;
    657 		return(0);
    658 	    }
    659 	} else {
    660 	    for (insert = &(table->table[key]); insert->next != NULL;
    661 		 insert = insert->next) {
    662 		if ((xmlStrEqual(insert->name, name)) &&
    663 		    (xmlStrEqual(insert->name2, name2)) &&
    664 		    (xmlStrEqual(insert->name3, name3))) {
    665 		    if (f)
    666 			f(insert->payload, insert->name);
    667 		    insert->payload = userdata;
    668 		    return(0);
    669 		}
    670 	    }
    671 	    if ((xmlStrEqual(insert->name, name)) &&
    672 		(xmlStrEqual(insert->name2, name2)) &&
    673 		(xmlStrEqual(insert->name3, name3))) {
    674 		if (f)
    675 		    f(insert->payload, insert->name);
    676 		insert->payload = userdata;
    677 		return(0);
    678 	    }
    679 	}
    680     }
    681 
    682     if (insert == NULL) {
    683 	entry =  &(table->table[key]);
    684     } else {
    685 	entry = xmlMalloc(sizeof(xmlHashEntry));
    686 	if (entry == NULL)
    687 	     return(-1);
    688     }
    689 
    690     if (table->dict != NULL) {
    691         entry->name = (xmlChar *) name;
    692         entry->name2 = (xmlChar *) name2;
    693         entry->name3 = (xmlChar *) name3;
    694     } else {
    695 	entry->name = xmlStrdup(name);
    696 	entry->name2 = xmlStrdup(name2);
    697 	entry->name3 = xmlStrdup(name3);
    698     }
    699     entry->payload = userdata;
    700     entry->next = NULL;
    701     entry->valid = 1;
    702     table->nbElems++;
    703 
    704 
    705     if (insert != NULL) {
    706 	insert->next = entry;
    707     }
    708     return(0);
    709 }
    710 
    711 /**
    712  * xmlHashLookup3:
    713  * @table: the hash table
    714  * @name: the name of the userdata
    715  * @name2: a second name of the userdata
    716  * @name3: a third name of the userdata
    717  *
    718  * Find the userdata specified by the (@name, @name2, @name3) tuple.
    719  *
    720  * Returns the a pointer to the userdata
    721  */
    722 void *
    723 xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
    724 	       const xmlChar *name2, const xmlChar *name3) {
    725     unsigned long key;
    726     xmlHashEntryPtr entry;
    727 
    728     if (table == NULL)
    729 	return(NULL);
    730     if (name == NULL)
    731 	return(NULL);
    732     key = xmlHashComputeKey(table, name, name2, name3);
    733     if (table->table[key].valid == 0)
    734 	return(NULL);
    735     if (table->dict) {
    736 	for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
    737 	    if ((entry->name == name) &&
    738 		(entry->name2 == name2) &&
    739 		(entry->name3 == name3))
    740 		return(entry->payload);
    741 	}
    742     }
    743     for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
    744 	if ((xmlStrEqual(entry->name, name)) &&
    745 	    (xmlStrEqual(entry->name2, name2)) &&
    746 	    (xmlStrEqual(entry->name3, name3)))
    747 	    return(entry->payload);
    748     }
    749     return(NULL);
    750 }
    751 
    752 /**
    753  * xmlHashQLookup3:
    754  * @table: the hash table
    755  * @prefix: the prefix of the userdata
    756  * @name: the name of the userdata
    757  * @prefix2: the second prefix of the userdata
    758  * @name2: a second name of the userdata
    759  * @prefix3: the third prefix of the userdata
    760  * @name3: a third name of the userdata
    761  *
    762  * Find the userdata specified by the (@name, @name2, @name3) tuple.
    763  *
    764  * Returns the a pointer to the userdata
    765  */
    766 void *
    767 xmlHashQLookup3(xmlHashTablePtr table,
    768                 const xmlChar *prefix, const xmlChar *name,
    769 		const xmlChar *prefix2, const xmlChar *name2,
    770 		const xmlChar *prefix3, const xmlChar *name3) {
    771     unsigned long key;
    772     xmlHashEntryPtr entry;
    773 
    774     if (table == NULL)
    775 	return(NULL);
    776     if (name == NULL)
    777 	return(NULL);
    778     key = xmlHashComputeQKey(table, prefix, name, prefix2,
    779                              name2, prefix3, name3);
    780     if (table->table[key].valid == 0)
    781 	return(NULL);
    782     for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
    783 	if ((xmlStrQEqual(prefix, name, entry->name)) &&
    784 	    (xmlStrQEqual(prefix2, name2, entry->name2)) &&
    785 	    (xmlStrQEqual(prefix3, name3, entry->name3)))
    786 	    return(entry->payload);
    787     }
    788     return(NULL);
    789 }
    790 
    791 typedef struct {
    792     xmlHashScanner hashscanner;
    793     void *data;
    794 } stubData;
    795 
    796 static void
    797 stubHashScannerFull (void *payload, void *data, const xmlChar *name,
    798                      const xmlChar *name2 ATTRIBUTE_UNUSED,
    799 		     const xmlChar *name3 ATTRIBUTE_UNUSED) {
    800     stubData *stubdata = (stubData *) data;
    801     stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
    802 }
    803 
    804 /**
    805  * xmlHashScan:
    806  * @table: the hash table
    807  * @f:  the scanner function for items in the hash
    808  * @data:  extra data passed to f
    809  *
    810  * Scan the hash @table and applied @f to each value.
    811  */
    812 void
    813 xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
    814     stubData stubdata;
    815     stubdata.data = data;
    816     stubdata.hashscanner = f;
    817     xmlHashScanFull (table, stubHashScannerFull, &stubdata);
    818 }
    819 
    820 /**
    821  * xmlHashScanFull:
    822  * @table: the hash table
    823  * @f:  the scanner function for items in the hash
    824  * @data:  extra data passed to f
    825  *
    826  * Scan the hash @table and applied @f to each value.
    827  */
    828 void
    829 xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
    830     int i, nb;
    831     xmlHashEntryPtr iter;
    832     xmlHashEntryPtr next;
    833 
    834     if (table == NULL)
    835 	return;
    836     if (f == NULL)
    837 	return;
    838 
    839     if (table->table) {
    840 	for(i = 0; i < table->size; i++) {
    841 	    if (table->table[i].valid == 0)
    842 		continue;
    843 	    iter = &(table->table[i]);
    844 	    while (iter) {
    845 		next = iter->next;
    846                 nb = table->nbElems;
    847 		if ((f != NULL) && (iter->payload != NULL))
    848 		    f(iter->payload, data, iter->name,
    849 		      iter->name2, iter->name3);
    850                 if (nb != table->nbElems) {
    851                     /* table was modified by the callback, be careful */
    852                     if (iter == &(table->table[i])) {
    853                         if (table->table[i].valid == 0)
    854                             iter = NULL;
    855                         if (table->table[i].next != next)
    856 			    iter = &(table->table[i]);
    857                     } else
    858 		        iter = next;
    859                 } else
    860 		    iter = next;
    861 	    }
    862 	}
    863     }
    864 }
    865 
    866 /**
    867  * xmlHashScan3:
    868  * @table: the hash table
    869  * @name: the name of the userdata or NULL
    870  * @name2: a second name of the userdata or NULL
    871  * @name3: a third name of the userdata or NULL
    872  * @f:  the scanner function for items in the hash
    873  * @data:  extra data passed to f
    874  *
    875  * Scan the hash @table and applied @f to each value matching
    876  * (@name, @name2, @name3) tuple. If one of the names is null,
    877  * the comparison is considered to match.
    878  */
    879 void
    880 xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
    881 	     const xmlChar *name2, const xmlChar *name3,
    882 	     xmlHashScanner f, void *data) {
    883     xmlHashScanFull3 (table, name, name2, name3,
    884 		      (xmlHashScannerFull) f, data);
    885 }
    886 
    887 /**
    888  * xmlHashScanFull3:
    889  * @table: the hash table
    890  * @name: the name of the userdata or NULL
    891  * @name2: a second name of the userdata or NULL
    892  * @name3: a third name of the userdata or NULL
    893  * @f:  the scanner function for items in the hash
    894  * @data:  extra data passed to f
    895  *
    896  * Scan the hash @table and applied @f to each value matching
    897  * (@name, @name2, @name3) tuple. If one of the names is null,
    898  * the comparison is considered to match.
    899  */
    900 void
    901 xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
    902 		 const xmlChar *name2, const xmlChar *name3,
    903 		 xmlHashScannerFull f, void *data) {
    904     int i;
    905     xmlHashEntryPtr iter;
    906     xmlHashEntryPtr next;
    907 
    908     if (table == NULL)
    909 	return;
    910     if (f == NULL)
    911 	return;
    912 
    913     if (table->table) {
    914 	for(i = 0; i < table->size; i++) {
    915 	    if (table->table[i].valid == 0)
    916 		continue;
    917 	    iter = &(table->table[i]);
    918 	    while (iter) {
    919 		next = iter->next;
    920 		if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
    921 		    ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
    922 		    ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
    923 		    (iter->payload != NULL)) {
    924 		    f(iter->payload, data, iter->name,
    925 		      iter->name2, iter->name3);
    926 		}
    927 		iter = next;
    928 	    }
    929 	}
    930     }
    931 }
    932 
    933 /**
    934  * xmlHashCopy:
    935  * @table: the hash table
    936  * @f:  the copier function for items in the hash
    937  *
    938  * Scan the hash @table and applied @f to each value.
    939  *
    940  * Returns the new table or NULL in case of error.
    941  */
    942 xmlHashTablePtr
    943 xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
    944     int i;
    945     xmlHashEntryPtr iter;
    946     xmlHashEntryPtr next;
    947     xmlHashTablePtr ret;
    948 
    949     if (table == NULL)
    950 	return(NULL);
    951     if (f == NULL)
    952 	return(NULL);
    953 
    954     ret = xmlHashCreate(table->size);
    955     if (table->table) {
    956 	for(i = 0; i < table->size; i++) {
    957 	    if (table->table[i].valid == 0)
    958 		continue;
    959 	    iter = &(table->table[i]);
    960 	    while (iter) {
    961 		next = iter->next;
    962 		xmlHashAddEntry3(ret, iter->name, iter->name2,
    963 			         iter->name3, f(iter->payload, iter->name));
    964 		iter = next;
    965 	    }
    966 	}
    967     }
    968     ret->nbElems = table->nbElems;
    969     return(ret);
    970 }
    971 
    972 /**
    973  * xmlHashSize:
    974  * @table: the hash table
    975  *
    976  * Query the number of elements installed in the hash @table.
    977  *
    978  * Returns the number of elements in the hash table or
    979  * -1 in case of error
    980  */
    981 int
    982 xmlHashSize(xmlHashTablePtr table) {
    983     if (table == NULL)
    984 	return(-1);
    985     return(table->nbElems);
    986 }
    987 
    988 /**
    989  * xmlHashRemoveEntry:
    990  * @table: the hash table
    991  * @name: the name of the userdata
    992  * @f: the deallocator function for removed item (if any)
    993  *
    994  * Find the userdata specified by the @name and remove
    995  * it from the hash @table. Existing userdata for this tuple will be removed
    996  * and freed with @f.
    997  *
    998  * Returns 0 if the removal succeeded and -1 in case of error or not found.
    999  */
   1000 int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
   1001 		       xmlHashDeallocator f) {
   1002     return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
   1003 }
   1004 
   1005 /**
   1006  * xmlHashRemoveEntry2:
   1007  * @table: the hash table
   1008  * @name: the name of the userdata
   1009  * @name2: a second name of the userdata
   1010  * @f: the deallocator function for removed item (if any)
   1011  *
   1012  * Find the userdata specified by the (@name, @name2) tuple and remove
   1013  * it from the hash @table. Existing userdata for this tuple will be removed
   1014  * and freed with @f.
   1015  *
   1016  * Returns 0 if the removal succeeded and -1 in case of error or not found.
   1017  */
   1018 int
   1019 xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
   1020 			const xmlChar *name2, xmlHashDeallocator f) {
   1021     return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
   1022 }
   1023 
   1024 /**
   1025  * xmlHashRemoveEntry3:
   1026  * @table: the hash table
   1027  * @name: the name of the userdata
   1028  * @name2: a second name of the userdata
   1029  * @name3: a third name of the userdata
   1030  * @f: the deallocator function for removed item (if any)
   1031  *
   1032  * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
   1033  * it from the hash @table. Existing userdata for this tuple will be removed
   1034  * and freed with @f.
   1035  *
   1036  * Returns 0 if the removal succeeded and -1 in case of error or not found.
   1037  */
   1038 int
   1039 xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
   1040     const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
   1041     unsigned long key;
   1042     xmlHashEntryPtr entry;
   1043     xmlHashEntryPtr prev = NULL;
   1044 
   1045     if (table == NULL || name == NULL)
   1046         return(-1);
   1047 
   1048     key = xmlHashComputeKey(table, name, name2, name3);
   1049     if (table->table[key].valid == 0) {
   1050         return(-1);
   1051     } else {
   1052         for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
   1053             if (xmlStrEqual(entry->name, name) &&
   1054                     xmlStrEqual(entry->name2, name2) &&
   1055                     xmlStrEqual(entry->name3, name3)) {
   1056                 if ((f != NULL) && (entry->payload != NULL))
   1057                     f(entry->payload, entry->name);
   1058                 entry->payload = NULL;
   1059 		if (table->dict == NULL) {
   1060 		    if(entry->name)
   1061 			xmlFree(entry->name);
   1062 		    if(entry->name2)
   1063 			xmlFree(entry->name2);
   1064 		    if(entry->name3)
   1065 			xmlFree(entry->name3);
   1066 		}
   1067                 if(prev) {
   1068                     prev->next = entry->next;
   1069 		    xmlFree(entry);
   1070 		} else {
   1071 		    if (entry->next == NULL) {
   1072 			entry->valid = 0;
   1073 		    } else {
   1074 			entry = entry->next;
   1075 			memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
   1076 			xmlFree(entry);
   1077 		    }
   1078 		}
   1079                 table->nbElems--;
   1080                 return(0);
   1081             }
   1082             prev = entry;
   1083         }
   1084         return(-1);
   1085     }
   1086 }
   1087 
   1088 #define bottom_hash
   1089 #include "elfgcchack.h"
   1090