Blame hash.c

Packit 423ecb
/*
Packit 423ecb
 * hash.c: chained hash tables
Packit 423ecb
 *
Packit 423ecb
 * Reference: Your favorite introductory book on algorithms
Packit 423ecb
 *
Packit 423ecb
 * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard.
Packit 423ecb
 *
Packit 423ecb
 * Permission to use, copy, modify, and distribute this software for any
Packit 423ecb
 * purpose with or without fee is hereby granted, provided that the above
Packit 423ecb
 * copyright notice and this permission notice appear in all copies.
Packit 423ecb
 *
Packit 423ecb
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
Packit 423ecb
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
Packit 423ecb
 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
Packit 423ecb
 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
Packit 423ecb
 *
Packit 423ecb
 * Author: breese@users.sourceforge.net
Packit 423ecb
 */
Packit 423ecb
Packit 423ecb
#define IN_LIBXML
Packit 423ecb
#include "libxml.h"
Packit 423ecb
Packit 423ecb
#include <string.h>
Packit 423ecb
#ifdef HAVE_STDLIB_H
Packit 423ecb
#include <stdlib.h>
Packit 423ecb
#endif
Packit 423ecb
#ifdef HAVE_TIME_H
Packit 423ecb
#include <time.h>
Packit 423ecb
#endif
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * Following http://www.ocert.org/advisories/ocert-2011-003.html
Packit 423ecb
 * it seems that having hash randomization might be a good idea
Packit 423ecb
 * when using XML with untrusted data
Packit 423ecb
 */
Packit 423ecb
#if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME)
Packit 423ecb
#define HASH_RANDOMIZATION
Packit 423ecb
#endif
Packit 423ecb
Packit 423ecb
#include <libxml/parser.h>
Packit 423ecb
#include <libxml/hash.h>
Packit 423ecb
#include <libxml/xmlmemory.h>
Packit 423ecb
#include <libxml/xmlerror.h>
Packit 423ecb
#include <libxml/globals.h>
Packit 423ecb
Packit 423ecb
#define MAX_HASH_LEN 8
Packit 423ecb
Packit 423ecb
/* #define DEBUG_GROW */
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * A single entry in the hash table
Packit 423ecb
 */
Packit 423ecb
typedef struct _xmlHashEntry xmlHashEntry;
Packit 423ecb
typedef xmlHashEntry *xmlHashEntryPtr;
Packit 423ecb
struct _xmlHashEntry {
Packit 423ecb
    struct _xmlHashEntry *next;
Packit 423ecb
    xmlChar *name;
Packit 423ecb
    xmlChar *name2;
Packit 423ecb
    xmlChar *name3;
Packit 423ecb
    void *payload;
Packit 423ecb
    int valid;
Packit 423ecb
};
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * The entire hash table
Packit 423ecb
 */
Packit 423ecb
struct _xmlHashTable {
Packit 423ecb
    struct _xmlHashEntry *table;
Packit 423ecb
    int size;
Packit 423ecb
    int nbElems;
Packit 423ecb
    xmlDictPtr dict;
Packit 423ecb
#ifdef HASH_RANDOMIZATION
Packit 423ecb
    int random_seed;
Packit 423ecb
#endif
Packit 423ecb
};
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * xmlHashComputeKey:
Packit 423ecb
 * Calculate the hash key
Packit 423ecb
 */
Packit 423ecb
static unsigned long
Packit 423ecb
xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
Packit 423ecb
	          const xmlChar *name2, const xmlChar *name3) {
Packit 423ecb
    unsigned long value = 0L;
Packit 423ecb
    char ch;
Packit 423ecb
Packit 423ecb
#ifdef HASH_RANDOMIZATION
Packit 423ecb
    value = table->random_seed;
Packit 423ecb
#endif
Packit 423ecb
    if (name != NULL) {
Packit 423ecb
	value += 30 * (*name);
Packit 423ecb
	while ((ch = *name++) != 0) {
Packit 423ecb
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    value = value ^ ((value << 5) + (value >> 3));
Packit 423ecb
    if (name2 != NULL) {
Packit 423ecb
	while ((ch = *name2++) != 0) {
Packit 423ecb
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    value = value ^ ((value << 5) + (value >> 3));
Packit 423ecb
    if (name3 != NULL) {
Packit 423ecb
	while ((ch = *name3++) != 0) {
Packit 423ecb
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    return (value % table->size);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
static unsigned long
Packit 423ecb
xmlHashComputeQKey(xmlHashTablePtr table,
Packit 423ecb
		   const xmlChar *prefix, const xmlChar *name,
Packit 423ecb
		   const xmlChar *prefix2, const xmlChar *name2,
Packit 423ecb
		   const xmlChar *prefix3, const xmlChar *name3) {
Packit 423ecb
    unsigned long value = 0L;
Packit 423ecb
    char ch;
Packit 423ecb
Packit 423ecb
#ifdef HASH_RANDOMIZATION
Packit 423ecb
    value = table->random_seed;
Packit 423ecb
#endif
Packit 423ecb
    if (prefix != NULL)
Packit 423ecb
	value += 30 * (*prefix);
Packit 423ecb
    else
Packit 423ecb
	value += 30 * (*name);
Packit 423ecb
Packit 423ecb
    if (prefix != NULL) {
Packit 423ecb
	while ((ch = *prefix++) != 0) {
Packit 423ecb
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Packit 423ecb
	}
Packit 423ecb
	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
Packit 423ecb
    }
Packit 423ecb
    if (name != NULL) {
Packit 423ecb
	while ((ch = *name++) != 0) {
Packit 423ecb
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    value = value ^ ((value << 5) + (value >> 3));
Packit 423ecb
    if (prefix2 != NULL) {
Packit 423ecb
	while ((ch = *prefix2++) != 0) {
Packit 423ecb
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Packit 423ecb
	}
Packit 423ecb
	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
Packit 423ecb
    }
Packit 423ecb
    if (name2 != NULL) {
Packit 423ecb
	while ((ch = *name2++) != 0) {
Packit 423ecb
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    value = value ^ ((value << 5) + (value >> 3));
Packit 423ecb
    if (prefix3 != NULL) {
Packit 423ecb
	while ((ch = *prefix3++) != 0) {
Packit 423ecb
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Packit 423ecb
	}
Packit 423ecb
	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
Packit 423ecb
    }
Packit 423ecb
    if (name3 != NULL) {
Packit 423ecb
	while ((ch = *name3++) != 0) {
Packit 423ecb
	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    return (value % table->size);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashCreate:
Packit 423ecb
 * @size: the size of the hash table
Packit 423ecb
 *
Packit 423ecb
 * Create a new xmlHashTablePtr.
Packit 423ecb
 *
Packit 423ecb
 * Returns the newly created object, or NULL if an error occurred.
Packit 423ecb
 */
Packit 423ecb
xmlHashTablePtr
Packit 423ecb
xmlHashCreate(int size) {
Packit 423ecb
    xmlHashTablePtr table;
Packit 423ecb
Packit 423ecb
    if (size <= 0)
Packit 423ecb
        size = 256;
Packit 423ecb
Packit 423ecb
    table = xmlMalloc(sizeof(xmlHashTable));
Packit 423ecb
    if (table) {
Packit 423ecb
        table->dict = NULL;
Packit 423ecb
        table->size = size;
Packit 423ecb
	table->nbElems = 0;
Packit 423ecb
        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
Packit 423ecb
        if (table->table) {
Packit 423ecb
	    memset(table->table, 0, size * sizeof(xmlHashEntry));
Packit 423ecb
#ifdef HASH_RANDOMIZATION
Packit 423ecb
            table->random_seed = __xmlRandom();
Packit 423ecb
#endif
Packit 423ecb
	    return(table);
Packit 423ecb
        }
Packit 423ecb
        xmlFree(table);
Packit 423ecb
    }
Packit 423ecb
    return(NULL);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashCreateDict:
Packit 423ecb
 * @size: the size of the hash table
Packit 423ecb
 * @dict: a dictionary to use for the hash
Packit 423ecb
 *
Packit 423ecb
 * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
Packit 423ecb
 *
Packit 423ecb
 * Returns the newly created object, or NULL if an error occurred.
Packit 423ecb
 */
Packit 423ecb
xmlHashTablePtr
Packit 423ecb
xmlHashCreateDict(int size, xmlDictPtr dict) {
Packit 423ecb
    xmlHashTablePtr table;
Packit 423ecb
Packit 423ecb
    table = xmlHashCreate(size);
Packit 423ecb
    if (table != NULL) {
Packit 423ecb
        table->dict = dict;
Packit 423ecb
	xmlDictReference(dict);
Packit 423ecb
    }
Packit 423ecb
    return(table);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashGrow:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @size: the new size of the hash table
Packit 423ecb
 *
Packit 423ecb
 * resize the hash table
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 in case of success, -1 in case of failure
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlHashGrow(xmlHashTablePtr table, int size) {
Packit 423ecb
    unsigned long key;
Packit 423ecb
    int oldsize, i;
Packit 423ecb
    xmlHashEntryPtr iter, next;
Packit 423ecb
    struct _xmlHashEntry *oldtable;
Packit 423ecb
#ifdef DEBUG_GROW
Packit 423ecb
    unsigned long nbElem = 0;
Packit 423ecb
#endif
Packit 423ecb
Packit 423ecb
    if (table == NULL)
Packit 423ecb
	return(-1);
Packit 423ecb
    if (size < 8)
Packit 423ecb
        return(-1);
Packit 423ecb
    if (size > 8 * 2048)
Packit 423ecb
	return(-1);
Packit 423ecb
Packit 423ecb
    oldsize = table->size;
Packit 423ecb
    oldtable = table->table;
Packit 423ecb
    if (oldtable == NULL)
Packit 423ecb
        return(-1);
Packit 423ecb
Packit 423ecb
    table->table = xmlMalloc(size * sizeof(xmlHashEntry));
Packit 423ecb
    if (table->table == NULL) {
Packit 423ecb
	table->table = oldtable;
Packit 423ecb
	return(-1);
Packit 423ecb
    }
Packit 423ecb
    memset(table->table, 0, size * sizeof(xmlHashEntry));
Packit 423ecb
    table->size = size;
Packit 423ecb
Packit 423ecb
    /*	If the two loops are merged, there would be situations where
Packit 423ecb
	a new entry needs to allocated and data copied into it from
Packit 423ecb
	the main table. So instead, we run through the array twice, first
Packit 423ecb
	copying all the elements in the main array (where we can't get
Packit 423ecb
	conflicts) and then the rest, so we only free (and don't allocate)
Packit 423ecb
    */
Packit 423ecb
    for (i = 0; i < oldsize; i++) {
Packit 423ecb
	if (oldtable[i].valid == 0)
Packit 423ecb
	    continue;
Packit 423ecb
	key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
Packit 423ecb
				oldtable[i].name3);
Packit 423ecb
	memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
Packit 423ecb
	table->table[key].next = NULL;
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    for (i = 0; i < oldsize; i++) {
Packit 423ecb
	iter = oldtable[i].next;
Packit 423ecb
	while (iter) {
Packit 423ecb
	    next = iter->next;
Packit 423ecb
Packit 423ecb
	    /*
Packit 423ecb
	     * put back the entry in the new table
Packit 423ecb
	     */
Packit 423ecb
Packit 423ecb
	    key = xmlHashComputeKey(table, iter->name, iter->name2,
Packit 423ecb
		                    iter->name3);
Packit 423ecb
	    if (table->table[key].valid == 0) {
Packit 423ecb
		memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
Packit 423ecb
		table->table[key].next = NULL;
Packit 423ecb
		xmlFree(iter);
Packit 423ecb
	    } else {
Packit 423ecb
		iter->next = table->table[key].next;
Packit 423ecb
		table->table[key].next = iter;
Packit 423ecb
	    }
Packit 423ecb
Packit 423ecb
#ifdef DEBUG_GROW
Packit 423ecb
	    nbElem++;
Packit 423ecb
#endif
Packit 423ecb
Packit 423ecb
	    iter = next;
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    xmlFree(oldtable);
Packit 423ecb
Packit 423ecb
#ifdef DEBUG_GROW
Packit 423ecb
    xmlGenericError(xmlGenericErrorContext,
Packit 423ecb
	    "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
Packit 423ecb
#endif
Packit 423ecb
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashFree:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @f:  the deallocator function for items in the hash
Packit 423ecb
 *
Packit 423ecb
 * Free the hash @table and its contents. The userdata is
Packit 423ecb
 * deallocated with @f if provided.
Packit 423ecb
 */
Packit 423ecb
void
Packit 423ecb
xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
Packit 423ecb
    int i;
Packit 423ecb
    xmlHashEntryPtr iter;
Packit 423ecb
    xmlHashEntryPtr next;
Packit 423ecb
    int inside_table = 0;
Packit 423ecb
    int nbElems;
Packit 423ecb
Packit 423ecb
    if (table == NULL)
Packit 423ecb
	return;
Packit 423ecb
    if (table->table) {
Packit 423ecb
	nbElems = table->nbElems;
Packit 423ecb
	for(i = 0; (i < table->size) && (nbElems > 0); i++) {
Packit 423ecb
	    iter = &(table->table[i]);
Packit 423ecb
	    if (iter->valid == 0)
Packit 423ecb
		continue;
Packit 423ecb
	    inside_table = 1;
Packit 423ecb
	    while (iter) {
Packit 423ecb
		next = iter->next;
Packit 423ecb
		if ((f != NULL) && (iter->payload != NULL))
Packit 423ecb
		    f(iter->payload, iter->name);
Packit 423ecb
		if (table->dict == NULL) {
Packit 423ecb
		    if (iter->name)
Packit 423ecb
			xmlFree(iter->name);
Packit 423ecb
		    if (iter->name2)
Packit 423ecb
			xmlFree(iter->name2);
Packit 423ecb
		    if (iter->name3)
Packit 423ecb
			xmlFree(iter->name3);
Packit 423ecb
		}
Packit 423ecb
		iter->payload = NULL;
Packit 423ecb
		if (!inside_table)
Packit 423ecb
		    xmlFree(iter);
Packit 423ecb
		nbElems--;
Packit 423ecb
		inside_table = 0;
Packit 423ecb
		iter = next;
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
	xmlFree(table->table);
Packit 423ecb
    }
Packit 423ecb
    if (table->dict)
Packit 423ecb
        xmlDictFree(table->dict);
Packit 423ecb
    xmlFree(table);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashAddEntry:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @userdata: a pointer to the userdata
Packit 423ecb
 *
Packit 423ecb
 * Add the @userdata to the hash @table. This can later be retrieved
Packit 423ecb
 * by using the @name. Duplicate names generate errors.
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 the addition succeeded and -1 in case of error.
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
Packit 423ecb
    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashAddEntry2:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @name2: a second name of the userdata
Packit 423ecb
 * @userdata: a pointer to the userdata
Packit 423ecb
 *
Packit 423ecb
 * Add the @userdata to the hash @table. This can later be retrieved
Packit 423ecb
 * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 the addition succeeded and -1 in case of error.
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
Packit 423ecb
	        const xmlChar *name2, void *userdata) {
Packit 423ecb
    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashUpdateEntry:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @userdata: a pointer to the userdata
Packit 423ecb
 * @f: the deallocator function for replaced item (if any)
Packit 423ecb
 *
Packit 423ecb
 * Add the @userdata to the hash @table. This can later be retrieved
Packit 423ecb
 * by using the @name. Existing entry for this @name will be removed
Packit 423ecb
 * and freed with @f if found.
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 the addition succeeded and -1 in case of error.
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
Packit 423ecb
	           void *userdata, xmlHashDeallocator f) {
Packit 423ecb
    return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashUpdateEntry2:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @name2: a second name of the userdata
Packit 423ecb
 * @userdata: a pointer to the userdata
Packit 423ecb
 * @f: the deallocator function for replaced item (if any)
Packit 423ecb
 *
Packit 423ecb
 * Add the @userdata to the hash @table. This can later be retrieved
Packit 423ecb
 * by using the (@name, @name2) tuple. Existing entry for this tuple will
Packit 423ecb
 * be removed and freed with @f if found.
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 the addition succeeded and -1 in case of error.
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
Packit 423ecb
	           const xmlChar *name2, void *userdata,
Packit 423ecb
		   xmlHashDeallocator f) {
Packit 423ecb
    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashLookup:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 *
Packit 423ecb
 * Find the userdata specified by the @name.
Packit 423ecb
 *
Packit 423ecb
 * Returns the pointer to the userdata
Packit 423ecb
 */
Packit 423ecb
void *
Packit 423ecb
xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
Packit 423ecb
    return(xmlHashLookup3(table, name, NULL, NULL));
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashLookup2:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @name2: a second name of the userdata
Packit 423ecb
 *
Packit 423ecb
 * Find the userdata specified by the (@name, @name2) tuple.
Packit 423ecb
 *
Packit 423ecb
 * Returns the pointer to the userdata
Packit 423ecb
 */
Packit 423ecb
void *
Packit 423ecb
xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
Packit 423ecb
	      const xmlChar *name2) {
Packit 423ecb
    return(xmlHashLookup3(table, name, name2, NULL));
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashQLookup:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @prefix: the prefix of the userdata
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 *
Packit 423ecb
 * Find the userdata specified by the QName @prefix:@name/@name.
Packit 423ecb
 *
Packit 423ecb
 * Returns the pointer to the userdata
Packit 423ecb
 */
Packit 423ecb
void *
Packit 423ecb
xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
Packit 423ecb
               const xmlChar *name) {
Packit 423ecb
    return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashQLookup2:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @prefix: the prefix of the userdata
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @prefix2: the second prefix of the userdata
Packit 423ecb
 * @name2: a second name of the userdata
Packit 423ecb
 *
Packit 423ecb
 * Find the userdata specified by the QNames tuple
Packit 423ecb
 *
Packit 423ecb
 * Returns the pointer to the userdata
Packit 423ecb
 */
Packit 423ecb
void *
Packit 423ecb
xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix,
Packit 423ecb
                const xmlChar *name, const xmlChar *prefix2,
Packit 423ecb
	        const xmlChar *name2) {
Packit 423ecb
    return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashAddEntry3:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @name2: a second name of the userdata
Packit 423ecb
 * @name3: a third name of the userdata
Packit 423ecb
 * @userdata: a pointer to the userdata
Packit 423ecb
 *
Packit 423ecb
 * Add the @userdata to the hash @table. This can later be retrieved
Packit 423ecb
 * by using the tuple (@name, @name2, @name3). Duplicate entries generate
Packit 423ecb
 * errors.
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 the addition succeeded and -1 in case of error.
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
Packit 423ecb
	         const xmlChar *name2, const xmlChar *name3,
Packit 423ecb
		 void *userdata) {
Packit 423ecb
    unsigned long key, len = 0;
Packit 423ecb
    xmlHashEntryPtr entry;
Packit 423ecb
    xmlHashEntryPtr insert;
Packit 423ecb
Packit 423ecb
    if ((table == NULL) || (name == NULL))
Packit 423ecb
	return(-1);
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * If using a dict internalize if needed
Packit 423ecb
     */
Packit 423ecb
    if (table->dict) {
Packit 423ecb
        if (!xmlDictOwns(table->dict, name)) {
Packit 423ecb
	    name = xmlDictLookup(table->dict, name, -1);
Packit 423ecb
	    if (name == NULL)
Packit 423ecb
	        return(-1);
Packit 423ecb
	}
Packit 423ecb
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
Packit 423ecb
	    name2 = xmlDictLookup(table->dict, name2, -1);
Packit 423ecb
	    if (name2 == NULL)
Packit 423ecb
	        return(-1);
Packit 423ecb
	}
Packit 423ecb
        if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
Packit 423ecb
	    name3 = xmlDictLookup(table->dict, name3, -1);
Packit 423ecb
	    if (name3 == NULL)
Packit 423ecb
	        return(-1);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * Check for duplicate and insertion location.
Packit 423ecb
     */
Packit 423ecb
    key = xmlHashComputeKey(table, name, name2, name3);
Packit 423ecb
    if (table->table[key].valid == 0) {
Packit 423ecb
	insert = NULL;
Packit 423ecb
    } else {
Packit 423ecb
        if (table->dict) {
Packit 423ecb
	    for (insert = &(table->table[key]); insert->next != NULL;
Packit 423ecb
		 insert = insert->next) {
Packit 423ecb
		if ((insert->name == name) &&
Packit 423ecb
		    (insert->name2 == name2) &&
Packit 423ecb
		    (insert->name3 == name3))
Packit 423ecb
		    return(-1);
Packit 423ecb
		len++;
Packit 423ecb
	    }
Packit 423ecb
	    if ((insert->name == name) &&
Packit 423ecb
		(insert->name2 == name2) &&
Packit 423ecb
		(insert->name3 == name3))
Packit 423ecb
		return(-1);
Packit 423ecb
	} else {
Packit 423ecb
	    for (insert = &(table->table[key]); insert->next != NULL;
Packit 423ecb
		 insert = insert->next) {
Packit 423ecb
		if ((xmlStrEqual(insert->name, name)) &&
Packit 423ecb
		    (xmlStrEqual(insert->name2, name2)) &&
Packit 423ecb
		    (xmlStrEqual(insert->name3, name3)))
Packit 423ecb
		    return(-1);
Packit 423ecb
		len++;
Packit 423ecb
	    }
Packit 423ecb
	    if ((xmlStrEqual(insert->name, name)) &&
Packit 423ecb
		(xmlStrEqual(insert->name2, name2)) &&
Packit 423ecb
		(xmlStrEqual(insert->name3, name3)))
Packit 423ecb
		return(-1);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (insert == NULL) {
Packit 423ecb
	entry = &(table->table[key]);
Packit 423ecb
    } else {
Packit 423ecb
	entry = xmlMalloc(sizeof(xmlHashEntry));
Packit 423ecb
	if (entry == NULL)
Packit 423ecb
	     return(-1);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (table->dict != NULL) {
Packit 423ecb
        entry->name = (xmlChar *) name;
Packit 423ecb
        entry->name2 = (xmlChar *) name2;
Packit 423ecb
        entry->name3 = (xmlChar *) name3;
Packit 423ecb
    } else {
Packit 423ecb
	entry->name = xmlStrdup(name);
Packit 423ecb
	entry->name2 = xmlStrdup(name2);
Packit 423ecb
	entry->name3 = xmlStrdup(name3);
Packit 423ecb
    }
Packit 423ecb
    entry->payload = userdata;
Packit 423ecb
    entry->next = NULL;
Packit 423ecb
    entry->valid = 1;
Packit 423ecb
Packit 423ecb
Packit 423ecb
    if (insert != NULL)
Packit 423ecb
	insert->next = entry;
Packit 423ecb
Packit 423ecb
    table->nbElems++;
Packit 423ecb
Packit 423ecb
    if (len > MAX_HASH_LEN)
Packit 423ecb
	xmlHashGrow(table, MAX_HASH_LEN * table->size);
Packit 423ecb
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashUpdateEntry3:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @name2: a second name of the userdata
Packit 423ecb
 * @name3: a third name of the userdata
Packit 423ecb
 * @userdata: a pointer to the userdata
Packit 423ecb
 * @f: the deallocator function for replaced item (if any)
Packit 423ecb
 *
Packit 423ecb
 * Add the @userdata to the hash @table. This can later be retrieved
Packit 423ecb
 * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
Packit 423ecb
 * will be removed and freed with @f if found.
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 the addition succeeded and -1 in case of error.
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
Packit 423ecb
	           const xmlChar *name2, const xmlChar *name3,
Packit 423ecb
		   void *userdata, xmlHashDeallocator f) {
Packit 423ecb
    unsigned long key;
Packit 423ecb
    xmlHashEntryPtr entry;
Packit 423ecb
    xmlHashEntryPtr insert;
Packit 423ecb
Packit 423ecb
    if ((table == NULL) || name == NULL)
Packit 423ecb
	return(-1);
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * If using a dict internalize if needed
Packit 423ecb
     */
Packit 423ecb
    if (table->dict) {
Packit 423ecb
        if (!xmlDictOwns(table->dict, name)) {
Packit 423ecb
	    name = xmlDictLookup(table->dict, name, -1);
Packit 423ecb
	    if (name == NULL)
Packit 423ecb
	        return(-1);
Packit 423ecb
	}
Packit 423ecb
        if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
Packit 423ecb
	    name2 = xmlDictLookup(table->dict, name2, -1);
Packit 423ecb
	    if (name2 == NULL)
Packit 423ecb
	        return(-1);
Packit 423ecb
	}
Packit 423ecb
        if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
Packit 423ecb
	    name3 = xmlDictLookup(table->dict, name3, -1);
Packit 423ecb
	    if (name3 == NULL)
Packit 423ecb
	        return(-1);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * Check for duplicate and insertion location.
Packit 423ecb
     */
Packit 423ecb
    key = xmlHashComputeKey(table, name, name2, name3);
Packit 423ecb
    if (table->table[key].valid == 0) {
Packit 423ecb
	insert = NULL;
Packit 423ecb
    } else {
Packit 423ecb
        if (table ->dict) {
Packit 423ecb
	    for (insert = &(table->table[key]); insert->next != NULL;
Packit 423ecb
		 insert = insert->next) {
Packit 423ecb
		if ((insert->name == name) &&
Packit 423ecb
		    (insert->name2 == name2) &&
Packit 423ecb
		    (insert->name3 == name3)) {
Packit 423ecb
		    if (f)
Packit 423ecb
			f(insert->payload, insert->name);
Packit 423ecb
		    insert->payload = userdata;
Packit 423ecb
		    return(0);
Packit 423ecb
		}
Packit 423ecb
	    }
Packit 423ecb
	    if ((insert->name == name) &&
Packit 423ecb
		(insert->name2 == name2) &&
Packit 423ecb
		(insert->name3 == name3)) {
Packit 423ecb
		if (f)
Packit 423ecb
		    f(insert->payload, insert->name);
Packit 423ecb
		insert->payload = userdata;
Packit 423ecb
		return(0);
Packit 423ecb
	    }
Packit 423ecb
	} else {
Packit 423ecb
	    for (insert = &(table->table[key]); insert->next != NULL;
Packit 423ecb
		 insert = insert->next) {
Packit 423ecb
		if ((xmlStrEqual(insert->name, name)) &&
Packit 423ecb
		    (xmlStrEqual(insert->name2, name2)) &&
Packit 423ecb
		    (xmlStrEqual(insert->name3, name3))) {
Packit 423ecb
		    if (f)
Packit 423ecb
			f(insert->payload, insert->name);
Packit 423ecb
		    insert->payload = userdata;
Packit 423ecb
		    return(0);
Packit 423ecb
		}
Packit 423ecb
	    }
Packit 423ecb
	    if ((xmlStrEqual(insert->name, name)) &&
Packit 423ecb
		(xmlStrEqual(insert->name2, name2)) &&
Packit 423ecb
		(xmlStrEqual(insert->name3, name3))) {
Packit 423ecb
		if (f)
Packit 423ecb
		    f(insert->payload, insert->name);
Packit 423ecb
		insert->payload = userdata;
Packit 423ecb
		return(0);
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (insert == NULL) {
Packit 423ecb
	entry =  &(table->table[key]);
Packit 423ecb
    } else {
Packit 423ecb
	entry = xmlMalloc(sizeof(xmlHashEntry));
Packit 423ecb
	if (entry == NULL)
Packit 423ecb
	     return(-1);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (table->dict != NULL) {
Packit 423ecb
        entry->name = (xmlChar *) name;
Packit 423ecb
        entry->name2 = (xmlChar *) name2;
Packit 423ecb
        entry->name3 = (xmlChar *) name3;
Packit 423ecb
    } else {
Packit 423ecb
	entry->name = xmlStrdup(name);
Packit 423ecb
	entry->name2 = xmlStrdup(name2);
Packit 423ecb
	entry->name3 = xmlStrdup(name3);
Packit 423ecb
    }
Packit 423ecb
    entry->payload = userdata;
Packit 423ecb
    entry->next = NULL;
Packit 423ecb
    entry->valid = 1;
Packit 423ecb
    table->nbElems++;
Packit 423ecb
Packit 423ecb
Packit 423ecb
    if (insert != NULL) {
Packit 423ecb
	insert->next = entry;
Packit 423ecb
    }
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashLookup3:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @name2: a second name of the userdata
Packit 423ecb
 * @name3: a third name of the userdata
Packit 423ecb
 *
Packit 423ecb
 * Find the userdata specified by the (@name, @name2, @name3) tuple.
Packit 423ecb
 *
Packit 423ecb
 * Returns the a pointer to the userdata
Packit 423ecb
 */
Packit 423ecb
void *
Packit 423ecb
xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
Packit 423ecb
	       const xmlChar *name2, const xmlChar *name3) {
Packit 423ecb
    unsigned long key;
Packit 423ecb
    xmlHashEntryPtr entry;
Packit 423ecb
Packit 423ecb
    if (table == NULL)
Packit 423ecb
	return(NULL);
Packit 423ecb
    if (name == NULL)
Packit 423ecb
	return(NULL);
Packit 423ecb
    key = xmlHashComputeKey(table, name, name2, name3);
Packit 423ecb
    if (table->table[key].valid == 0)
Packit 423ecb
	return(NULL);
Packit 423ecb
    if (table->dict) {
Packit 423ecb
	for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Packit 423ecb
	    if ((entry->name == name) &&
Packit 423ecb
		(entry->name2 == name2) &&
Packit 423ecb
		(entry->name3 == name3))
Packit 423ecb
		return(entry->payload);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Packit 423ecb
	if ((xmlStrEqual(entry->name, name)) &&
Packit 423ecb
	    (xmlStrEqual(entry->name2, name2)) &&
Packit 423ecb
	    (xmlStrEqual(entry->name3, name3)))
Packit 423ecb
	    return(entry->payload);
Packit 423ecb
    }
Packit 423ecb
    return(NULL);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashQLookup3:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @prefix: the prefix of the userdata
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @prefix2: the second prefix of the userdata
Packit 423ecb
 * @name2: a second name of the userdata
Packit 423ecb
 * @prefix3: the third prefix of the userdata
Packit 423ecb
 * @name3: a third name of the userdata
Packit 423ecb
 *
Packit 423ecb
 * Find the userdata specified by the (@name, @name2, @name3) tuple.
Packit 423ecb
 *
Packit 423ecb
 * Returns the a pointer to the userdata
Packit 423ecb
 */
Packit 423ecb
void *
Packit 423ecb
xmlHashQLookup3(xmlHashTablePtr table,
Packit 423ecb
                const xmlChar *prefix, const xmlChar *name,
Packit 423ecb
		const xmlChar *prefix2, const xmlChar *name2,
Packit 423ecb
		const xmlChar *prefix3, const xmlChar *name3) {
Packit 423ecb
    unsigned long key;
Packit 423ecb
    xmlHashEntryPtr entry;
Packit 423ecb
Packit 423ecb
    if (table == NULL)
Packit 423ecb
	return(NULL);
Packit 423ecb
    if (name == NULL)
Packit 423ecb
	return(NULL);
Packit 423ecb
    key = xmlHashComputeQKey(table, prefix, name, prefix2,
Packit 423ecb
                             name2, prefix3, name3);
Packit 423ecb
    if (table->table[key].valid == 0)
Packit 423ecb
	return(NULL);
Packit 423ecb
    for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Packit 423ecb
	if ((xmlStrQEqual(prefix, name, entry->name)) &&
Packit 423ecb
	    (xmlStrQEqual(prefix2, name2, entry->name2)) &&
Packit 423ecb
	    (xmlStrQEqual(prefix3, name3, entry->name3)))
Packit 423ecb
	    return(entry->payload);
Packit 423ecb
    }
Packit 423ecb
    return(NULL);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
typedef struct {
Packit 423ecb
    xmlHashScanner hashscanner;
Packit 423ecb
    void *data;
Packit 423ecb
} stubData;
Packit 423ecb
Packit 423ecb
static void
Packit 423ecb
stubHashScannerFull (void *payload, void *data, const xmlChar *name,
Packit 423ecb
                     const xmlChar *name2 ATTRIBUTE_UNUSED,
Packit 423ecb
		     const xmlChar *name3 ATTRIBUTE_UNUSED) {
Packit 423ecb
    stubData *stubdata = (stubData *) data;
Packit 423ecb
    stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashScan:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @f:  the scanner function for items in the hash
Packit 423ecb
 * @data:  extra data passed to f
Packit 423ecb
 *
Packit 423ecb
 * Scan the hash @table and applied @f to each value.
Packit 423ecb
 */
Packit 423ecb
void
Packit 423ecb
xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
Packit 423ecb
    stubData stubdata;
Packit 423ecb
    stubdata.data = data;
Packit 423ecb
    stubdata.hashscanner = f;
Packit 423ecb
    xmlHashScanFull (table, stubHashScannerFull, &stubdata);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashScanFull:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @f:  the scanner function for items in the hash
Packit 423ecb
 * @data:  extra data passed to f
Packit 423ecb
 *
Packit 423ecb
 * Scan the hash @table and applied @f to each value.
Packit 423ecb
 */
Packit 423ecb
void
Packit 423ecb
xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
Packit 423ecb
    int i, nb;
Packit 423ecb
    xmlHashEntryPtr iter;
Packit 423ecb
    xmlHashEntryPtr next;
Packit 423ecb
Packit 423ecb
    if (table == NULL)
Packit 423ecb
	return;
Packit 423ecb
    if (f == NULL)
Packit 423ecb
	return;
Packit 423ecb
Packit 423ecb
    if (table->table) {
Packit 423ecb
	for(i = 0; i < table->size; i++) {
Packit 423ecb
	    if (table->table[i].valid == 0)
Packit 423ecb
		continue;
Packit 423ecb
	    iter = &(table->table[i]);
Packit 423ecb
	    while (iter) {
Packit 423ecb
		next = iter->next;
Packit 423ecb
                nb = table->nbElems;
Packit 423ecb
		if ((f != NULL) && (iter->payload != NULL))
Packit 423ecb
		    f(iter->payload, data, iter->name,
Packit 423ecb
		      iter->name2, iter->name3);
Packit 423ecb
                if (nb != table->nbElems) {
Packit 423ecb
                    /* table was modified by the callback, be careful */
Packit 423ecb
                    if (iter == &(table->table[i])) {
Packit 423ecb
                        if (table->table[i].valid == 0)
Packit 423ecb
                            iter = NULL;
Packit 423ecb
                        if (table->table[i].next != next)
Packit 423ecb
			    iter = &(table->table[i]);
Packit 423ecb
                    } else
Packit 423ecb
		        iter = next;
Packit 423ecb
                } else
Packit 423ecb
		    iter = next;
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashScan3:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata or NULL
Packit 423ecb
 * @name2: a second name of the userdata or NULL
Packit 423ecb
 * @name3: a third name of the userdata or NULL
Packit 423ecb
 * @f:  the scanner function for items in the hash
Packit 423ecb
 * @data:  extra data passed to f
Packit 423ecb
 *
Packit 423ecb
 * Scan the hash @table and applied @f to each value matching
Packit 423ecb
 * (@name, @name2, @name3) tuple. If one of the names is null,
Packit 423ecb
 * the comparison is considered to match.
Packit 423ecb
 */
Packit 423ecb
void
Packit 423ecb
xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
Packit 423ecb
	     const xmlChar *name2, const xmlChar *name3,
Packit 423ecb
	     xmlHashScanner f, void *data) {
Packit 423ecb
    xmlHashScanFull3 (table, name, name2, name3,
Packit 423ecb
		      (xmlHashScannerFull) f, data);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashScanFull3:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata or NULL
Packit 423ecb
 * @name2: a second name of the userdata or NULL
Packit 423ecb
 * @name3: a third name of the userdata or NULL
Packit 423ecb
 * @f:  the scanner function for items in the hash
Packit 423ecb
 * @data:  extra data passed to f
Packit 423ecb
 *
Packit 423ecb
 * Scan the hash @table and applied @f to each value matching
Packit 423ecb
 * (@name, @name2, @name3) tuple. If one of the names is null,
Packit 423ecb
 * the comparison is considered to match.
Packit 423ecb
 */
Packit 423ecb
void
Packit 423ecb
xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
Packit 423ecb
		 const xmlChar *name2, const xmlChar *name3,
Packit 423ecb
		 xmlHashScannerFull f, void *data) {
Packit 423ecb
    int i;
Packit 423ecb
    xmlHashEntryPtr iter;
Packit 423ecb
    xmlHashEntryPtr next;
Packit 423ecb
Packit 423ecb
    if (table == NULL)
Packit 423ecb
	return;
Packit 423ecb
    if (f == NULL)
Packit 423ecb
	return;
Packit 423ecb
Packit 423ecb
    if (table->table) {
Packit 423ecb
	for(i = 0; i < table->size; i++) {
Packit 423ecb
	    if (table->table[i].valid == 0)
Packit 423ecb
		continue;
Packit 423ecb
	    iter = &(table->table[i]);
Packit 423ecb
	    while (iter) {
Packit 423ecb
		next = iter->next;
Packit 423ecb
		if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
Packit 423ecb
		    ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
Packit 423ecb
		    ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
Packit 423ecb
		    (iter->payload != NULL)) {
Packit 423ecb
		    f(iter->payload, data, iter->name,
Packit 423ecb
		      iter->name2, iter->name3);
Packit 423ecb
		}
Packit 423ecb
		iter = next;
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashCopy:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @f:  the copier function for items in the hash
Packit 423ecb
 *
Packit 423ecb
 * Scan the hash @table and applied @f to each value.
Packit 423ecb
 *
Packit 423ecb
 * Returns the new table or NULL in case of error.
Packit 423ecb
 */
Packit 423ecb
xmlHashTablePtr
Packit 423ecb
xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
Packit 423ecb
    int i;
Packit 423ecb
    xmlHashEntryPtr iter;
Packit 423ecb
    xmlHashEntryPtr next;
Packit 423ecb
    xmlHashTablePtr ret;
Packit 423ecb
Packit 423ecb
    if (table == NULL)
Packit 423ecb
	return(NULL);
Packit 423ecb
    if (f == NULL)
Packit 423ecb
	return(NULL);
Packit 423ecb
Packit 423ecb
    ret = xmlHashCreate(table->size);
Packit 423ecb
    if (ret == NULL)
Packit 423ecb
        return(NULL);
Packit 423ecb
Packit 423ecb
    if (table->table) {
Packit 423ecb
	for(i = 0; i < table->size; i++) {
Packit 423ecb
	    if (table->table[i].valid == 0)
Packit 423ecb
		continue;
Packit 423ecb
	    iter = &(table->table[i]);
Packit 423ecb
	    while (iter) {
Packit 423ecb
		next = iter->next;
Packit 423ecb
		xmlHashAddEntry3(ret, iter->name, iter->name2,
Packit 423ecb
			         iter->name3, f(iter->payload, iter->name));
Packit 423ecb
		iter = next;
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    ret->nbElems = table->nbElems;
Packit 423ecb
    return(ret);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashSize:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 *
Packit 423ecb
 * Query the number of elements installed in the hash @table.
Packit 423ecb
 *
Packit 423ecb
 * Returns the number of elements in the hash table or
Packit 423ecb
 * -1 in case of error
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlHashSize(xmlHashTablePtr table) {
Packit 423ecb
    if (table == NULL)
Packit 423ecb
	return(-1);
Packit 423ecb
    return(table->nbElems);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashRemoveEntry:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @f: the deallocator function for removed item (if any)
Packit 423ecb
 *
Packit 423ecb
 * Find the userdata specified by the @name and remove
Packit 423ecb
 * it from the hash @table. Existing userdata for this tuple will be removed
Packit 423ecb
 * and freed with @f.
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
Packit 423ecb
 */
Packit 423ecb
int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
Packit 423ecb
		       xmlHashDeallocator f) {
Packit 423ecb
    return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashRemoveEntry2:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @name2: a second name of the userdata
Packit 423ecb
 * @f: the deallocator function for removed item (if any)
Packit 423ecb
 *
Packit 423ecb
 * Find the userdata specified by the (@name, @name2) tuple and remove
Packit 423ecb
 * it from the hash @table. Existing userdata for this tuple will be removed
Packit 423ecb
 * and freed with @f.
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
Packit 423ecb
			const xmlChar *name2, xmlHashDeallocator f) {
Packit 423ecb
    return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlHashRemoveEntry3:
Packit 423ecb
 * @table: the hash table
Packit 423ecb
 * @name: the name of the userdata
Packit 423ecb
 * @name2: a second name of the userdata
Packit 423ecb
 * @name3: a third name of the userdata
Packit 423ecb
 * @f: the deallocator function for removed item (if any)
Packit 423ecb
 *
Packit 423ecb
 * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
Packit 423ecb
 * it from the hash @table. Existing userdata for this tuple will be removed
Packit 423ecb
 * and freed with @f.
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 if the removal succeeded and -1 in case of error or not found.
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
Packit 423ecb
    const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
Packit 423ecb
    unsigned long key;
Packit 423ecb
    xmlHashEntryPtr entry;
Packit 423ecb
    xmlHashEntryPtr prev = NULL;
Packit 423ecb
Packit 423ecb
    if (table == NULL || name == NULL)
Packit 423ecb
        return(-1);
Packit 423ecb
Packit 423ecb
    key = xmlHashComputeKey(table, name, name2, name3);
Packit 423ecb
    if (table->table[key].valid == 0) {
Packit 423ecb
        return(-1);
Packit 423ecb
    } else {
Packit 423ecb
        for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
Packit 423ecb
            if (xmlStrEqual(entry->name, name) &&
Packit 423ecb
                    xmlStrEqual(entry->name2, name2) &&
Packit 423ecb
                    xmlStrEqual(entry->name3, name3)) {
Packit 423ecb
                if ((f != NULL) && (entry->payload != NULL))
Packit 423ecb
                    f(entry->payload, entry->name);
Packit 423ecb
                entry->payload = NULL;
Packit 423ecb
		if (table->dict == NULL) {
Packit 423ecb
		    if(entry->name)
Packit 423ecb
			xmlFree(entry->name);
Packit 423ecb
		    if(entry->name2)
Packit 423ecb
			xmlFree(entry->name2);
Packit 423ecb
		    if(entry->name3)
Packit 423ecb
			xmlFree(entry->name3);
Packit 423ecb
		}
Packit 423ecb
                if(prev) {
Packit 423ecb
                    prev->next = entry->next;
Packit 423ecb
		    xmlFree(entry);
Packit 423ecb
		} else {
Packit 423ecb
		    if (entry->next == NULL) {
Packit 423ecb
			entry->valid = 0;
Packit 423ecb
		    } else {
Packit 423ecb
			entry = entry->next;
Packit 423ecb
			memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
Packit 423ecb
			xmlFree(entry);
Packit 423ecb
		    }
Packit 423ecb
		}
Packit 423ecb
                table->nbElems--;
Packit 423ecb
                return(0);
Packit 423ecb
            }
Packit 423ecb
            prev = entry;
Packit 423ecb
        }
Packit 423ecb
        return(-1);
Packit 423ecb
    }
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
#define bottom_hash
Packit 423ecb
#include "elfgcchack.h"