Home | History | Annotate | Download | only in libxml2
      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 	    inside_table = 0;
    324 	}
    325 	xmlFree(table->table);
    326     }
    327     if (table->dict)
    328         xmlDictFree(table->dict);
    329     xmlFree(table);
    330 }
    331 
    332 /**
    333  * xmlHashAddEntry:
    334  * @table: the hash table
    335  * @name: the name of the userdata
    336  * @userdata: a pointer to the userdata
    337  *
    338  * Add the @userdata to the hash @table. This can later be retrieved
    339  * by using the @name. Duplicate names generate errors.
    340  *
    341  * Returns 0 the addition succeeded and -1 in case of error.
    342  */
    343 int
    344 xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
    345     return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
    346 }
    347 
    348 /**
    349  * xmlHashAddEntry2:
    350  * @table: the hash table
    351  * @name: the name of the userdata
    352  * @name2: a second name of the userdata
    353  * @userdata: a pointer to the userdata
    354  *
    355  * Add the @userdata to the hash @table. This can later be retrieved
    356  * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
    357  *
    358  * Returns 0 the addition succeeded and -1 in case of error.
    359  */
    360 int
    361 xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
    362 	        const xmlChar *name2, void *userdata) {
    363     return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
    364 }
    365 
    366 /**
    367  * xmlHashUpdateEntry:
    368  * @table: the hash table
    369  * @name: the name of the userdata
    370  * @userdata: a pointer to the userdata
    371  * @f: the deallocator function for replaced item (if any)
    372  *
    373  * Add the @userdata to the hash @table. This can later be retrieved
    374  * by using the @name. Existing entry for this @name will be removed
    375  * and freed with @f if found.
    376  *
    377  * Returns 0 the addition succeeded and -1 in case of error.
    378  */
    379 int
    380 xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
    381 	           void *userdata, xmlHashDeallocator f) {
    382     return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
    383 }
    384 
    385 /**
    386  * xmlHashUpdateEntry2:
    387  * @table: the hash table
    388  * @name: the name of the userdata
    389  * @name2: a second name of the userdata
    390  * @userdata: a pointer to the userdata
    391  * @f: the deallocator function for replaced item (if any)
    392  *
    393  * Add the @userdata to the hash @table. This can later be retrieved
    394  * by using the (@name, @name2) tuple. Existing entry for this tuple will
    395  * be removed and freed with @f if found.
    396  *
    397  * Returns 0 the addition succeeded and -1 in case of error.
    398  */
    399 int
    400 xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
    401 	           const xmlChar *name2, void *userdata,
    402 		   xmlHashDeallocator f) {
    403     return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
    404 }
    405 
    406 /**
    407  * xmlHashLookup:
    408  * @table: the hash table
    409  * @name: the name of the userdata
    410  *
    411  * Find the userdata specified by the @name.
    412  *
    413  * Returns the pointer to the userdata
    414  */
    415 void *
    416 xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
    417     return(xmlHashLookup3(table, name, NULL, NULL));
    418 }
    419 
    420 /**
    421  * xmlHashLookup2:
    422  * @table: the hash table
    423  * @name: the name of the userdata
    424  * @name2: a second name of the userdata
    425  *
    426  * Find the userdata specified by the (@name, @name2) tuple.
    427  *
    428  * Returns the pointer to the userdata
    429  */
    430 void *
    431 xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
    432 	      const xmlChar *name2) {
    433     return(xmlHashLookup3(table, name, name2, NULL));
    434 }
    435 
    436 /**
    437  * xmlHashQLookup:
    438  * @table: the hash table
    439  * @prefix: the prefix of the userdata
    440  * @name: the name of the userdata
    441  *
    442  * Find the userdata specified by the QName @prefix:@name/@name.
    443  *
    444  * Returns the pointer to the userdata
    445  */
    446 void *
    447 xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
    448                const xmlChar *name) {
    449     return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
    450 }
    451 
    452 /**
    453  * xmlHashQLookup2:
    454  * @table: the hash table
    455  * @prefix: the prefix of the userdata
    456  * @name: the name of the userdata
    457  * @prefix2: the second prefix of the userdata
    458  * @name2: a second name of the userdata
    459  *
    460  * Find the userdata specified by the QNames tuple
    461  *
    462  * Returns the pointer to the userdata
    463  */
    464 void *
    465 xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix,
    466                 const xmlChar *name, const xmlChar *prefix2,
    467 	        const xmlChar *name2) {
    468     return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
    469 }
    470 
    471 /**
    472  * xmlHashAddEntry3:
    473  * @table: the hash table
    474  * @name: the name of the userdata
    475  * @name2: a second name of the userdata
    476  * @name3: a third name of the userdata
    477  * @userdata: a pointer to the userdata
    478  *
    479  * Add the @userdata to the hash @table. This can later be retrieved
    480  * by using the tuple (@name, @name2, @name3). Duplicate entries generate
    481  * errors.
    482  *
    483  * Returns 0 the addition succeeded and -1 in case of error.
    484  */
    485 int
    486 xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
    487 	         const xmlChar *name2, const xmlChar *name3,
    488 		 void *userdata) {
    489     unsigned long key, len = 0;
    490     xmlHashEntryPtr entry;
    491     xmlHashEntryPtr insert;
    492 
    493     if ((table == NULL) || (name == NULL))
    494 	return(-1);
    495 
    496     /*
    497      * If using a dict internalize if needed
    498      */
    499     if (table->dict) {
    500         if (!xmlDictOwns(table->dict, name)) {
    501 	    name = xmlDictLookup(table->dict, name, -1);
    502 	    if (name == NULL)
    503 	        return(-1);
    504 	}
    505         if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
    506 	    name2 = xmlDictLookup(table->dict, name2, -1);
    507 	    if (name2 == NULL)
    508 	        return(-1);
    509 	}
    510         if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
    511 	    name3 = xmlDictLookup(table->dict, name3, -1);
    512 	    if (name3 == NULL)
    513 	        return(-1);
    514 	}
    515     }
    516 
    517     /*
    518      * Check for duplicate and insertion location.
    519      */
    520     key = xmlHashComputeKey(table, name, name2, name3);
    521     if (table->table[key].valid == 0) {
    522 	insert = NULL;
    523     } else {
    524         if (table->dict) {
    525 	    for (insert = &(table->table[key]); insert->next != NULL;
    526 		 insert = insert->next) {
    527 		if ((insert->name == name) &&
    528 		    (insert->name2 == name2) &&
    529 		    (insert->name3 == name3))
    530 		    return(-1);
    531 		len++;
    532 	    }
    533 	    if ((insert->name == name) &&
    534 		(insert->name2 == name2) &&
    535 		(insert->name3 == name3))
    536 		return(-1);
    537 	} else {
    538 	    for (insert = &(table->table[key]); insert->next != NULL;
    539 		 insert = insert->next) {
    540 		if ((xmlStrEqual(insert->name, name)) &&
    541 		    (xmlStrEqual(insert->name2, name2)) &&
    542 		    (xmlStrEqual(insert->name3, name3)))
    543 		    return(-1);
    544 		len++;
    545 	    }
    546 	    if ((xmlStrEqual(insert->name, name)) &&
    547 		(xmlStrEqual(insert->name2, name2)) &&
    548 		(xmlStrEqual(insert->name3, name3)))
    549 		return(-1);
    550 	}
    551     }
    552 
    553     if (insert == NULL) {
    554 	entry = &(table->table[key]);
    555     } else {
    556 	entry = xmlMalloc(sizeof(xmlHashEntry));
    557 	if (entry == NULL)
    558 	     return(-1);
    559     }
    560 
    561     if (table->dict != NULL) {
    562         entry->name = (xmlChar *) name;
    563         entry->name2 = (xmlChar *) name2;
    564         entry->name3 = (xmlChar *) name3;
    565     } else {
    566 	entry->name = xmlStrdup(name);
    567 	entry->name2 = xmlStrdup(name2);
    568 	entry->name3 = xmlStrdup(name3);
    569     }
    570     entry->payload = userdata;
    571     entry->next = NULL;
    572     entry->valid = 1;
    573 
    574 
    575     if (insert != NULL)
    576 	insert->next = entry;
    577 
    578     table->nbElems++;
    579 
    580     if (len > MAX_HASH_LEN)
    581 	xmlHashGrow(table, MAX_HASH_LEN * table->size);
    582 
    583     return(0);
    584 }
    585 
    586 /**
    587  * xmlHashUpdateEntry3:
    588  * @table: the hash table
    589  * @name: the name of the userdata
    590  * @name2: a second name of the userdata
    591  * @name3: a third name of the userdata
    592  * @userdata: a pointer to the userdata
    593  * @f: the deallocator function for replaced item (if any)
    594  *
    595  * Add the @userdata to the hash @table. This can later be retrieved
    596  * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
    597  * will be removed and freed with @f if found.
    598  *
    599  * Returns 0 the addition succeeded and -1 in case of error.
    600  */
    601 int
    602 xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
    603 	           const xmlChar *name2, const xmlChar *name3,
    604 		   void *userdata, xmlHashDeallocator f) {
    605     unsigned long key;
    606     xmlHashEntryPtr entry;
    607     xmlHashEntryPtr insert;
    608 
    609     if ((table == NULL) || name == NULL)
    610 	return(-1);
    611 
    612     /*
    613      * If using a dict internalize if needed
    614      */
    615     if (table->dict) {
    616         if (!xmlDictOwns(table->dict, name)) {
    617 	    name = xmlDictLookup(table->dict, name, -1);
    618 	    if (name == NULL)
    619 	        return(-1);
    620 	}
    621         if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
    622 	    name2 = xmlDictLookup(table->dict, name2, -1);
    623 	    if (name2 == NULL)
    624 	        return(-1);
    625 	}
    626         if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
    627 	    name3 = xmlDictLookup(table->dict, name3, -1);
    628 	    if (name3 == NULL)
    629 	        return(-1);
    630 	}
    631     }
    632 
    633     /*
    634      * Check for duplicate and insertion location.
    635      */
    636     key = xmlHashComputeKey(table, name, name2, name3);
    637     if (table->table[key].valid == 0) {
    638 	insert = NULL;
    639     } else {
    640         if (table ->dict) {
    641 	    for (insert = &(table->table[key]); insert->next != NULL;
    642 		 insert = insert->next) {
    643 		if ((insert->name == name) &&
    644 		    (insert->name2 == name2) &&
    645 		    (insert->name3 == name3)) {
    646 		    if (f)
    647 			f(insert->payload, insert->name);
    648 		    insert->payload = userdata;
    649 		    return(0);
    650 		}
    651 	    }
    652 	    if ((insert->name == name) &&
    653 		(insert->name2 == name2) &&
    654 		(insert->name3 == name3)) {
    655 		if (f)
    656 		    f(insert->payload, insert->name);
    657 		insert->payload = userdata;
    658 		return(0);
    659 	    }
    660 	} else {
    661 	    for (insert = &(table->table[key]); insert->next != NULL;
    662 		 insert = insert->next) {
    663 		if ((xmlStrEqual(insert->name, name)) &&
    664 		    (xmlStrEqual(insert->name2, name2)) &&
    665 		    (xmlStrEqual(insert->name3, name3))) {
    666 		    if (f)
    667 			f(insert->payload, insert->name);
    668 		    insert->payload = userdata;
    669 		    return(0);
    670 		}
    671 	    }
    672 	    if ((xmlStrEqual(insert->name, name)) &&
    673 		(xmlStrEqual(insert->name2, name2)) &&
    674 		(xmlStrEqual(insert->name3, name3))) {
    675 		if (f)
    676 		    f(insert->payload, insert->name);
    677 		insert->payload = userdata;
    678 		return(0);
    679 	    }
    680 	}
    681     }
    682 
    683     if (insert == NULL) {
    684 	entry =  &(table->table[key]);
    685     } else {
    686 	entry = xmlMalloc(sizeof(xmlHashEntry));
    687 	if (entry == NULL)
    688 	     return(-1);
    689     }
    690 
    691     if (table->dict != NULL) {
    692         entry->name = (xmlChar *) name;
    693         entry->name2 = (xmlChar *) name2;
    694         entry->name3 = (xmlChar *) name3;
    695     } else {
    696 	entry->name = xmlStrdup(name);
    697 	entry->name2 = xmlStrdup(name2);
    698 	entry->name3 = xmlStrdup(name3);
    699     }
    700     entry->payload = userdata;
    701     entry->next = NULL;
    702     entry->valid = 1;
    703     table->nbElems++;
    704 
    705 
    706     if (insert != NULL) {
    707 	insert->next = entry;
    708     }
    709     return(0);
    710 }
    711 
    712 /**
    713  * xmlHashLookup3:
    714  * @table: the hash table
    715  * @name: the name of the userdata
    716  * @name2: a second name of the userdata
    717  * @name3: a third name of the userdata
    718  *
    719  * Find the userdata specified by the (@name, @name2, @name3) tuple.
    720  *
    721  * Returns the a pointer to the userdata
    722  */
    723 void *
    724 xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
    725 	       const xmlChar *name2, const xmlChar *name3) {
    726     unsigned long key;
    727     xmlHashEntryPtr entry;
    728 
    729     if (table == NULL)
    730 	return(NULL);
    731     if (name == NULL)
    732 	return(NULL);
    733     key = xmlHashComputeKey(table, name, name2, name3);
    734     if (table->table[key].valid == 0)
    735 	return(NULL);
    736     if (table->dict) {
    737 	for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
    738 	    if ((entry->name == name) &&
    739 		(entry->name2 == name2) &&
    740 		(entry->name3 == name3))
    741 		return(entry->payload);
    742 	}
    743     }
    744     for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
    745 	if ((xmlStrEqual(entry->name, name)) &&
    746 	    (xmlStrEqual(entry->name2, name2)) &&
    747 	    (xmlStrEqual(entry->name3, name3)))
    748 	    return(entry->payload);
    749     }
    750     return(NULL);
    751 }
    752 
    753 /**
    754  * xmlHashQLookup3:
    755  * @table: the hash table
    756  * @prefix: the prefix of the userdata
    757  * @name: the name of the userdata
    758  * @prefix2: the second prefix of the userdata
    759  * @name2: a second name of the userdata
    760  * @prefix3: the third prefix of the userdata
    761  * @name3: a third name of the userdata
    762  *
    763  * Find the userdata specified by the (@name, @name2, @name3) tuple.
    764  *
    765  * Returns the a pointer to the userdata
    766  */
    767 void *
    768 xmlHashQLookup3(xmlHashTablePtr table,
    769                 const xmlChar *prefix, const xmlChar *name,
    770 		const xmlChar *prefix2, const xmlChar *name2,
    771 		const xmlChar *prefix3, const xmlChar *name3) {
    772     unsigned long key;
    773     xmlHashEntryPtr entry;
    774 
    775     if (table == NULL)
    776 	return(NULL);
    777     if (name == NULL)
    778 	return(NULL);
    779     key = xmlHashComputeQKey(table, prefix, name, prefix2,
    780                              name2, prefix3, name3);
    781     if (table->table[key].valid == 0)
    782 	return(NULL);
    783     for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
    784 	if ((xmlStrQEqual(prefix, name, entry->name)) &&
    785 	    (xmlStrQEqual(prefix2, name2, entry->name2)) &&
    786 	    (xmlStrQEqual(prefix3, name3, entry->name3)))
    787 	    return(entry->payload);
    788     }
    789     return(NULL);
    790 }
    791 
    792 typedef struct {
    793     xmlHashScanner hashscanner;
    794     void *data;
    795 } stubData;
    796 
    797 static void
    798 stubHashScannerFull (void *payload, void *data, const xmlChar *name,
    799                      const xmlChar *name2 ATTRIBUTE_UNUSED,
    800 		     const xmlChar *name3 ATTRIBUTE_UNUSED) {
    801     stubData *stubdata = (stubData *) data;
    802     stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
    803 }
    804 
    805 /**
    806  * xmlHashScan:
    807  * @table: the hash table
    808  * @f:  the scanner function for items in the hash
    809  * @data:  extra data passed to f
    810  *
    811  * Scan the hash @table and applied @f to each value.
    812  */
    813 void
    814 xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
    815     stubData stubdata;
    816     stubdata.data = data;
    817     stubdata.hashscanner = f;
    818     xmlHashScanFull (table, stubHashScannerFull, &stubdata);
    819 }
    820 
    821 /**
    822  * xmlHashScanFull:
    823  * @table: the hash table
    824  * @f:  the scanner function for items in the hash
    825  * @data:  extra data passed to f
    826  *
    827  * Scan the hash @table and applied @f to each value.
    828  */
    829 void
    830 xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
    831     int i, nb;
    832     xmlHashEntryPtr iter;
    833     xmlHashEntryPtr next;
    834 
    835     if (table == NULL)
    836 	return;
    837     if (f == NULL)
    838 	return;
    839 
    840     if (table->table) {
    841 	for(i = 0; i < table->size; i++) {
    842 	    if (table->table[i].valid == 0)
    843 		continue;
    844 	    iter = &(table->table[i]);
    845 	    while (iter) {
    846 		next = iter->next;
    847                 nb = table->nbElems;
    848 		if ((f != NULL) && (iter->payload != NULL))
    849 		    f(iter->payload, data, iter->name,
    850 		      iter->name2, iter->name3);
    851                 if (nb != table->nbElems) {
    852                     /* table was modified by the callback, be careful */
    853                     if (iter == &(table->table[i])) {
    854                         if (table->table[i].valid == 0)
    855                             iter = NULL;
    856                         if (table->table[i].next != next)
    857 			    iter = &(table->table[i]);
    858                     } else
    859 		        iter = next;
    860                 } else
    861 		    iter = next;
    862 	    }
    863 	}
    864     }
    865 }
    866 
    867 /**
    868  * xmlHashScan3:
    869  * @table: the hash table
    870  * @name: the name of the userdata or NULL
    871  * @name2: a second name of the userdata or NULL
    872  * @name3: a third name of the userdata or NULL
    873  * @f:  the scanner function for items in the hash
    874  * @data:  extra data passed to f
    875  *
    876  * Scan the hash @table and applied @f to each value matching
    877  * (@name, @name2, @name3) tuple. If one of the names is null,
    878  * the comparison is considered to match.
    879  */
    880 void
    881 xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
    882 	     const xmlChar *name2, const xmlChar *name3,
    883 	     xmlHashScanner f, void *data) {
    884     xmlHashScanFull3 (table, name, name2, name3,
    885 		      (xmlHashScannerFull) f, data);
    886 }
    887 
    888 /**
    889  * xmlHashScanFull3:
    890  * @table: the hash table
    891  * @name: the name of the userdata or NULL
    892  * @name2: a second name of the userdata or NULL
    893  * @name3: a third name of the userdata or NULL
    894  * @f:  the scanner function for items in the hash
    895  * @data:  extra data passed to f
    896  *
    897  * Scan the hash @table and applied @f to each value matching
    898  * (@name, @name2, @name3) tuple. If one of the names is null,
    899  * the comparison is considered to match.
    900  */
    901 void
    902 xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
    903 		 const xmlChar *name2, const xmlChar *name3,
    904 		 xmlHashScannerFull f, void *data) {
    905     int i;
    906     xmlHashEntryPtr iter;
    907     xmlHashEntryPtr next;
    908 
    909     if (table == NULL)
    910 	return;
    911     if (f == NULL)
    912 	return;
    913 
    914     if (table->table) {
    915 	for(i = 0; i < table->size; i++) {
    916 	    if (table->table[i].valid == 0)
    917 		continue;
    918 	    iter = &(table->table[i]);
    919 	    while (iter) {
    920 		next = iter->next;
    921 		if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
    922 		    ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
    923 		    ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
    924 		    (iter->payload != NULL)) {
    925 		    f(iter->payload, data, iter->name,
    926 		      iter->name2, iter->name3);
    927 		}
    928 		iter = next;
    929 	    }
    930 	}
    931     }
    932 }
    933 
    934 /**
    935  * xmlHashCopy:
    936  * @table: the hash table
    937  * @f:  the copier function for items in the hash
    938  *
    939  * Scan the hash @table and applied @f to each value.
    940  *
    941  * Returns the new table or NULL in case of error.
    942  */
    943 xmlHashTablePtr
    944 xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
    945     int i;
    946     xmlHashEntryPtr iter;
    947     xmlHashEntryPtr next;
    948     xmlHashTablePtr ret;
    949 
    950     if (table == NULL)
    951 	return(NULL);
    952     if (f == NULL)
    953 	return(NULL);
    954 
    955     ret = xmlHashCreate(table->size);
    956     if (table->table) {
    957 	for(i = 0; i < table->size; i++) {
    958 	    if (table->table[i].valid == 0)
    959 		continue;
    960 	    iter = &(table->table[i]);
    961 	    while (iter) {
    962 		next = iter->next;
    963 		xmlHashAddEntry3(ret, iter->name, iter->name2,
    964 			         iter->name3, f(iter->payload, iter->name));
    965 		iter = next;
    966 	    }
    967 	}
    968     }
    969     ret->nbElems = table->nbElems;
    970     return(ret);
    971 }
    972 
    973 /**
    974  * xmlHashSize:
    975  * @table: the hash table
    976  *
    977  * Query the number of elements installed in the hash @table.
    978  *
    979  * Returns the number of elements in the hash table or
    980  * -1 in case of error
    981  */
    982 int
    983 xmlHashSize(xmlHashTablePtr table) {
    984     if (table == NULL)
    985 	return(-1);
    986     return(table->nbElems);
    987 }
    988 
    989 /**
    990  * xmlHashRemoveEntry:
    991  * @table: the hash table
    992  * @name: the name of the userdata
    993  * @f: the deallocator function for removed item (if any)
    994  *
    995  * Find the userdata specified by the @name and remove
    996  * it from the hash @table. Existing userdata for this tuple will be removed
    997  * and freed with @f.
    998  *
    999  * Returns 0 if the removal succeeded and -1 in case of error or not found.
   1000  */
   1001 int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
   1002 		       xmlHashDeallocator f) {
   1003     return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
   1004 }
   1005 
   1006 /**
   1007  * xmlHashRemoveEntry2:
   1008  * @table: the hash table
   1009  * @name: the name of the userdata
   1010  * @name2: a second name of the userdata
   1011  * @f: the deallocator function for removed item (if any)
   1012  *
   1013  * Find the userdata specified by the (@name, @name2) tuple and remove
   1014  * it from the hash @table. Existing userdata for this tuple will be removed
   1015  * and freed with @f.
   1016  *
   1017  * Returns 0 if the removal succeeded and -1 in case of error or not found.
   1018  */
   1019 int
   1020 xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
   1021 			const xmlChar *name2, xmlHashDeallocator f) {
   1022     return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
   1023 }
   1024 
   1025 /**
   1026  * xmlHashRemoveEntry3:
   1027  * @table: the hash table
   1028  * @name: the name of the userdata
   1029  * @name2: a second name of the userdata
   1030  * @name3: a third name of the userdata
   1031  * @f: the deallocator function for removed item (if any)
   1032  *
   1033  * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
   1034  * it from the hash @table. Existing userdata for this tuple will be removed
   1035  * and freed with @f.
   1036  *
   1037  * Returns 0 if the removal succeeded and -1 in case of error or not found.
   1038  */
   1039 int
   1040 xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
   1041     const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
   1042     unsigned long key;
   1043     xmlHashEntryPtr entry;
   1044     xmlHashEntryPtr prev = NULL;
   1045 
   1046     if (table == NULL || name == NULL)
   1047         return(-1);
   1048 
   1049     key = xmlHashComputeKey(table, name, name2, name3);
   1050     if (table->table[key].valid == 0) {
   1051         return(-1);
   1052     } else {
   1053         for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
   1054             if (xmlStrEqual(entry->name, name) &&
   1055                     xmlStrEqual(entry->name2, name2) &&
   1056                     xmlStrEqual(entry->name3, name3)) {
   1057                 if ((f != NULL) && (entry->payload != NULL))
   1058                     f(entry->payload, entry->name);
   1059                 entry->payload = NULL;
   1060 		if (table->dict == NULL) {
   1061 		    if(entry->name)
   1062 			xmlFree(entry->name);
   1063 		    if(entry->name2)
   1064 			xmlFree(entry->name2);
   1065 		    if(entry->name3)
   1066 			xmlFree(entry->name3);
   1067 		}
   1068                 if(prev) {
   1069                     prev->next = entry->next;
   1070 		    xmlFree(entry);
   1071 		} else {
   1072 		    if (entry->next == NULL) {
   1073 			entry->valid = 0;
   1074 		    } else {
   1075 			entry = entry->next;
   1076 			memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
   1077 			xmlFree(entry);
   1078 		    }
   1079 		}
   1080                 table->nbElems--;
   1081                 return(0);
   1082             }
   1083             prev = entry;
   1084         }
   1085         return(-1);
   1086     }
   1087 }
   1088 
   1089 #define bottom_hash
   1090 #include "elfgcchack.h"
   1091