You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-11-03 17:13:17 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			1091 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1091 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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;
 | 
						|
	    }
 | 
						|
	    inside_table = 0;
 | 
						|
	}
 | 
						|
	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"
 |